1 | /**
|
2 | * @fileoverview Utility for executing npm commands.
|
3 | * @author Ian VanSchooten
|
4 | * @copyright 2016 Ilya Volodin. All rights reserved.
|
5 | * See LICENSE file in root directory for full license.
|
6 | */
|
7 |
|
8 | ;
|
9 |
|
10 | //------------------------------------------------------------------------------
|
11 | // Requirements
|
12 | //------------------------------------------------------------------------------
|
13 |
|
14 | var fs = require("fs"),
|
15 | path = require("path"),
|
16 | shell = require("shelljs");
|
17 |
|
18 | //------------------------------------------------------------------------------
|
19 | // Helpers
|
20 | //------------------------------------------------------------------------------
|
21 |
|
22 | /**
|
23 | * Find the closest package.json file, starting at process.cwd (by default),
|
24 | * and working up to root.
|
25 | *
|
26 | * @param {string} [startDir=process.cwd()] Starting directory
|
27 | * @returns {string} Absolute path to closest package.json file
|
28 | */
|
29 | function findPackageJson(startDir) {
|
30 | var dir = path.resolve(startDir || process.cwd());
|
31 | do {
|
32 | var pkgfile = path.join(dir, "package.json");
|
33 | if (!fs.existsSync(pkgfile)) {
|
34 | dir = path.join(dir, "..");
|
35 | continue;
|
36 | }
|
37 | return pkgfile;
|
38 | } while (dir !== path.resolve(dir, ".."));
|
39 | return null;
|
40 | }
|
41 |
|
42 | //------------------------------------------------------------------------------
|
43 | // Private
|
44 | //------------------------------------------------------------------------------
|
45 |
|
46 | /**
|
47 | * Install node modules synchronously and save to devDependencies in package.json
|
48 | * @param {string|string[]} packages Node module or modules to install
|
49 | * @returns {void}
|
50 | */
|
51 | function installSyncSaveDev(packages) {
|
52 | if (Array.isArray(packages)) {
|
53 | packages = packages.join(" ");
|
54 | }
|
55 | shell.exec("npm i --save-dev " + packages, {stdio: "inherit"});
|
56 | }
|
57 |
|
58 | /**
|
59 | * Check whether node modules are include in a project's package.json.
|
60 | *
|
61 | * @param {string[]} packages Array of node module names
|
62 | * @param {Object} opt Options Object
|
63 | * @param {boolean} opt.dependencies Set to true to check for direct dependencies
|
64 | * @param {boolean} opt.devDependencies Set to true to check for development dependencies
|
65 | * @param {boolean} opt.startdir Directory to begin searching from
|
66 | * @returns {Object} An object whose keys are the module names
|
67 | * and values are booleans indicating installation.
|
68 | */
|
69 | function check(packages, opt) {
|
70 | var deps = [];
|
71 | var pkgJson = (opt) ? findPackageJson(opt.startDir) : findPackageJson();
|
72 | if (!pkgJson) {
|
73 | throw new Error("Could not find a package.json file. Run 'npm init' to create one.");
|
74 | }
|
75 | var fileJson = JSON.parse(fs.readFileSync(pkgJson, "utf8"));
|
76 | if (opt.devDependencies && typeof fileJson.devDependencies === "object") {
|
77 | deps = deps.concat(Object.keys(fileJson.devDependencies));
|
78 | }
|
79 | if (opt.dependencies && typeof fileJson.dependencies === "object") {
|
80 | deps = deps.concat(Object.keys(fileJson.dependencies));
|
81 | }
|
82 | return packages.reduce(function(status, pkg) {
|
83 | status[pkg] = deps.indexOf(pkg) !== -1;
|
84 | return status;
|
85 | }, {});
|
86 | }
|
87 |
|
88 | /**
|
89 | * Check whether node modules are included in the dependencies of a project's
|
90 | * package.json.
|
91 | *
|
92 | * Convienience wrapper around check().
|
93 | *
|
94 | * @param {string[]} packages Array of node modules to check.
|
95 | * @param {string} rootDir The directory contianing a package.json
|
96 | * @returns {Object} An object whose keys are the module names
|
97 | * and values are booleans indicating installation.
|
98 | */
|
99 | function checkDeps(packages, rootDir) {
|
100 | return check(packages, {dependencies: true, startDir: rootDir});
|
101 | }
|
102 |
|
103 | /**
|
104 | * Check whether node modules are included in the devDependencies of a project's
|
105 | * package.json.
|
106 | *
|
107 | * Convienience wrapper around check().
|
108 | *
|
109 | * @param {string[]} packages Array of node modules to check.
|
110 | * @returns {Object} An object whose keys are the module names
|
111 | * and values are booleans indicating installation.
|
112 | */
|
113 | function checkDevDeps(packages) {
|
114 | return check(packages, {devDependencies: true});
|
115 | }
|
116 |
|
117 | //------------------------------------------------------------------------------
|
118 | // Public Interface
|
119 | //------------------------------------------------------------------------------
|
120 |
|
121 | module.exports = {
|
122 | installSyncSaveDev: installSyncSaveDev,
|
123 | checkDeps: checkDeps,
|
124 | checkDevDeps: checkDevDeps
|
125 | };
|