UNPKG

5.42 kBJavaScriptView Raw
1/**
2 * npmDependencies.js list module's dependencies
3 *
4 * Changelog:
5 * 2018 Oct 17:
6 * printNpmListFromExec() is stuck with handling the callback instead of using async /await because npm cli is
7 * easy to blow up errors
8 */
9'use strict';
10
11// Dependencies
12
13function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
14
15const execChildProcess = require('child_process').exec;
16const spawn = require('child_process').spawn;
17const chalk = require('chalk');
18const pkgInfo = require('pkginfo');
19const cwd = process.cwd();
20const iPipeTo = require('ipt');
21const StringUtil = require('./utils/stringUtil');
22
23/*
24 * Output npm list 2 options provided: default () and fuzzy()
25 *
26 */
27module.exports.npmList = function () {
28 let pkg = collectDependencies();
29 let list = parseListFromPkgOutput(pkg);
30
31 // Returns default(), fuzzy(), raw(), rawNoColor() options
32 return {
33 default() {
34 if (!list || list.length === 0) return;
35
36 return list.forEach(i => console.log('├── ' + i));
37 },
38 fuzzy() {
39 if (!list || list.length === 0) return;
40
41 return iPipeTo(list, {
42 size: 20,
43 autocomplete: true,
44 message: ' '
45 }).then(keys => {
46 return keys.forEach(function (key) {
47 key = StringUtil.getRidOfColors(key);
48
49 spawn(`npm info ${key} | less -r`, {
50 stdio: 'inherit',
51 shell: true
52 });
53 });
54 }).catch(err => {
55 console.log(err, "Error building interactive interface");
56 });
57 },
58
59 /***** For API use *****/
60 raw: (() => {
61 var _ref = _asyncToGenerator(function* () {
62 if (!list || list.length === 0) return;
63
64 return list;
65 });
66
67 return function raw() {
68 return _ref.apply(this, arguments);
69 };
70 })(),
71
72 rawNoColor: (() => {
73 var _ref2 = _asyncToGenerator(function* () {
74 if (!list || list.length === 0) return;
75
76 return list.map(function (key) {
77 let result = StringUtil.getRidOfColors(key);
78 result = StringUtil.getRidOfQuotationMarks(result);
79 return result;
80 });
81 });
82
83 return function rawNoColor() {
84 return _ref2.apply(this, arguments);
85 };
86 })()
87 };
88};
89
90/*
91 * Run `npm list --long=true`
92 */
93module.exports.npmListDetails = function () {
94 const cmd = 'npm ll --depth=0 --long=true ';
95
96 // We are stuck with handling the callback instead of using async /await because npm cli is easy to blow up errors
97 execChildProcess(cmd + '--local', function (error, stdout, stderr) {
98 if (error) {
99 // Don't return if erred for `npm ERR! peer dep missing:` might occur, which is normal
100 console.log(chalk.red.bold.underline("exec error:") + error);
101 }
102 if (stdout) {
103 let list = parseNpmListFromStdout(stdout);
104 return list.forEach(i => {
105 console.log(i);
106 });
107 }
108 if (stderr) {
109 return console.log(chalk.red("Error: ") + stderr);
110 }
111 });
112};
113
114/*
115 * Use pkgInfo to get package.json dependencies value. Parsing package.json for dependencies is more than 10x faster
116 * than running `npm list`
117 */
118function collectDependencies() {
119 let pkg;
120 try {
121 pkg = {
122 exports: {}
123 };
124 pkgInfo(pkg, {
125 dir: cwd,
126 include: ["name", "version", "dependencies", "devDependencies"]
127 });
128 } catch (e) {
129 console.log(chalk.redBright("No package.json found"));
130 }
131 return pkg;
132}
133module.exports.collectDependencies = collectDependencies;
134
135/*
136 * Parse pkg object into a list
137 *
138 */
139function parseListFromPkgOutput({
140 exports: {
141 name,
142 version,
143 dependencies,
144 devDependencies
145 }
146}) {
147 if (!name && !version) return; // Not a npm package if having neither name nor version
148
149 let list = [];
150
151 (function printTitle() {
152 if (version) {
153 console.log(chalk.blueBright(name + '@' + version));
154 } else {
155 console.log(name);
156 }
157 })();
158
159 if (dependencies) {
160 list.push(chalk.underline('Dependencies'));
161 list = list.concat(objectToList(dependencies));
162 }
163
164 if (devDependencies) {
165 list.push(chalk.underline('DevDependencies'));
166 list = list.concat(objectToList(devDependencies));
167 }
168
169 return list;
170
171 /*
172 * Converts the deps object to list
173 * @params
174 * deps: {}
175 *
176 * returns []
177 */
178 function objectToList(deps = {}) {
179 return Object.keys(deps).map(key => {
180 let value = deps[key] ? deps[key].replace(/[^0-9.,]/g, "") : '';
181 return key + '@' + chalk.grey(value);
182 });
183 }
184}
185module.exports.parseListFromPkgOutput = parseListFromPkgOutput;
186
187/*
188 * parseNpmListFromStdout parse stdout to list
189 * @params
190 * stdout: string
191 * returns list: []
192 */
193function parseNpmListFromStdout(stdout) {
194 if (!stdout) return;
195 const lines = stdout.split('\n');
196
197 return lines.map(i => {
198 if (isTitle(i)) {
199 return chalk.blueBright(i);
200 } else if (isAddress(i)) {
201 return chalk.grey(i);
202 } else if (isSymlink(i)) {
203 return chalk.magenta(i);
204 } else {
205 return i;
206 }
207 });
208
209 function isTitle(i) {
210 return i.includes('@') && !i.includes('->') && !i.includes('//');
211 }
212
213 function isAddress(i) {
214 // hosted addresses, i.e. Github, Bitbucket, Gitlab
215 return i.includes('//');
216 }
217
218 function isSymlink(i) {
219 return i.includes('@') && i.includes('->');
220 }
221}
222module.exports.parseNpmListFromStdout = parseNpmListFromStdout;
\No newline at end of file