git ssb

0+

cel-desktop / ssb-pkg



Tree: 67c0e15a98a66eb99db2251478505d6f3d37535c

Files: 67c0e15a98a66eb99db2251478505d6f3d37535c / lib / detector.js

10262 bytesRaw
1/* eslint-disable operator-linebreak */
2/* eslint-disable prefer-const */
3
4const common = require('../prelude/common.js');
5const generate = require('escodegen').generate;
6const babelParser = require('@babel/parser');
7const parse = babelParser.parse;
8
9const ALIAS_AS_RELATIVE = common.ALIAS_AS_RELATIVE;
10const ALIAS_AS_RESOLVABLE = common.ALIAS_AS_RESOLVABLE;
11
12function forge (pattern, was) {
13 return pattern.replace('{c1}', ', ')
14 .replace('{v1}', '"' + was.v1 + '"')
15 .replace('{c2}', was.v2 ? ', ' : '')
16 .replace('{v2}', was.v2 ? ('"' + was.v2 + '"') : '')
17 .replace('{c3}', was.v3 ? ' from ' : '')
18 .replace('{v3}', was.v3 ? was.v3 : '');
19}
20
21function valid2 (v2) {
22 return (v2 === undefined) ||
23 (v2 === null) ||
24 (v2 === 'must-exclude') ||
25 (v2 === 'may-exclude');
26}
27
28function visitor_REQUIRE_RESOLVE (n) { // eslint-disable-line camelcase
29 const c = n.callee;
30 if (!c) return null;
31 const ci = (c.object
32 && c.object.type === 'Identifier'
33 && c.object.name === 'require'
34 && c.property
35 && c.property.type === 'Identifier'
36 && c.property.name === 'resolve');
37 if (!ci) return null;
38 const f = (n.type === 'CallExpression'
39 && n.arguments
40 && n.arguments[0]
41 && n.arguments[0].type === 'Literal');
42 if (!f) return null;
43 const m = (n.arguments[1]
44 && n.arguments[1].type === 'Literal');
45 return { v1: n.arguments[0].value,
46 v2: m ? n.arguments[1].value : null };
47}
48
49function visitor_REQUIRE (n) { // eslint-disable-line camelcase
50 const c = n.callee;
51 if (!c) return null;
52 const ci = (c.type === 'Identifier'
53 && c.name === 'require');
54 if (!ci) return null;
55 const f = (n.type === 'CallExpression'
56 && n.arguments
57 && n.arguments[0]
58 && n.arguments[0].type === 'Literal');
59 if (!f) return null;
60 const m = (n.arguments[1]
61 && n.arguments[1].type === 'Literal');
62 return { v1: n.arguments[0].value,
63 v2: m ? n.arguments[1].value : null };
64}
65
66function visitor_IMPORT (n) { // eslint-disable-line camelcase
67 const ni = (n.type === 'ImportDeclaration');
68 if (!ni) return null;
69 const s = n.specifiers;
70 return { v1: n.source.value,
71 v3: reconstructSpecifiers(s) };
72}
73
74function visitor_PATH_JOIN (n) { // eslint-disable-line camelcase
75 const c = n.callee;
76 if (!c) return null;
77 const ci = (c.object
78 && c.object.type === 'Identifier'
79 && c.object.name === 'path'
80 && c.property
81 && c.property.type === 'Identifier'
82 && c.property.name === 'join');
83 if (!ci) return null;
84 const dn = (n.arguments[0]
85 && n.arguments[0].type === 'Identifier'
86 && n.arguments[0].name === '__dirname');
87 if (!dn) return null;
88 const f = (n.type === 'CallExpression'
89 && n.arguments
90 && n.arguments[1]
91 && n.arguments[1].type === 'Literal'
92 && n.arguments.length === 2); // TODO concate them
93 if (!f) return null;
94 return { v1: n.arguments[1].value };
95}
96
97module.exports.visitor_SUCCESSFUL = function (node, test) { // eslint-disable-line camelcase
98 let mustExclude, mayExclude, was;
99
100 was = visitor_REQUIRE_RESOLVE(node);
101 if (was) {
102 if (test) return forge('require.resolve({v1}{c2}{v2})', was);
103 if (!valid2(was.v2)) return null;
104 mustExclude = (was.v2 === 'must-exclude');
105 mayExclude = (was.v2 === 'may-exclude');
106 return { alias: was.v1,
107 aliasType: ALIAS_AS_RESOLVABLE,
108 mustExclude: mustExclude,
109 mayExclude: mayExclude };
110 }
111
112 was = visitor_REQUIRE(node);
113 if (was) {
114 if (test) return forge('require({v1}{c2}{v2})', was);
115 if (!valid2(was.v2)) return null;
116 mustExclude = (was.v2 === 'must-exclude');
117 mayExclude = (was.v2 === 'may-exclude');
118 return { alias: was.v1,
119 aliasType: ALIAS_AS_RESOLVABLE,
120 mustExclude: mustExclude,
121 mayExclude: mayExclude };
122 }
123
124 was = visitor_IMPORT(node);
125 if (was) {
126 if (test) return forge('import {v3}{c3}{v1}', was);
127 return { alias: was.v1,
128 aliasType: ALIAS_AS_RESOLVABLE };
129 }
130
131 was = visitor_PATH_JOIN(node);
132 if (was) {
133 if (test) return forge('path.join(__dirname{c1}{v1})', was);
134 return { alias: was.v1,
135 aliasType: ALIAS_AS_RELATIVE,
136 mayExclude: false };
137 }
138
139 return null;
140};
141
142function visitor_NONLITERAL (n) { // eslint-disable-line camelcase
143 return (function () {
144 const c = n.callee;
145 if (!c) return null;
146 const ci = (c.object
147 && c.object.type === 'Identifier'
148 && c.object.name === 'require'
149 && c.property
150 && c.property.type === 'Identifier'
151 && c.property.name === 'resolve');
152 if (!ci) return null;
153 const f = (n.type === 'CallExpression'
154 && n.arguments
155 && n.arguments[0]
156 && n.arguments[0].type !== 'Literal');
157 if (!f) return null;
158 const m = n.arguments[1];
159 if (!m) return { v1: reconstruct(n.arguments[0]) };
160 const q = (n.arguments[1]
161 && n.arguments[1].type === 'Literal');
162 if (!q) return null;
163 return { v1: reconstruct(n.arguments[0]),
164 v2: n.arguments[1].value };
165 }()) || (function () {
166 const c = n.callee;
167 if (!c) return null;
168 const ci = (c.type === 'Identifier'
169 && c.name === 'require');
170 if (!ci) return null;
171 const f = (n.type === 'CallExpression'
172 && n.arguments
173 && n.arguments[0]
174 && n.arguments[0].type !== 'Literal');
175 if (!f) return null;
176 const m = n.arguments[1];
177 if (!m) return { v1: reconstruct(n.arguments[0]) };
178 const q = (n.arguments[1]
179 && n.arguments[1].type === 'Literal');
180 if (!q) return null;
181 return { v1: reconstruct(n.arguments[0]),
182 v2: n.arguments[1].value };
183 }());
184}
185
186module.exports.visitor_NONLITERAL = function (node) { // eslint-disable-line camelcase
187 let mustExclude, mayExclude, was;
188
189 was = visitor_NONLITERAL(node);
190 if (was) {
191 if (!valid2(was.v2)) return null;
192 mustExclude = (was.v2 === 'must-exclude');
193 mayExclude = (was.v2 === 'may-exclude');
194 return { alias: was.v1,
195 mustExclude: mustExclude,
196 mayExclude: mayExclude };
197 }
198
199 return null;
200};
201
202function visitor_MALFORMED (n) { // eslint-disable-line camelcase
203 return (function () {
204 const c = n.callee;
205 if (!c) return null;
206 const ci = (c.object
207 && c.object.type === 'Identifier'
208 && c.object.name === 'require'
209 && c.property
210 && c.property.type === 'Identifier'
211 && c.property.name === 'resolve');
212 if (!ci) return null;
213 const f = (n.type === 'CallExpression'
214 && n.arguments
215 && n.arguments[0]);
216 if (!f) return null;
217 return { v1: reconstruct(n.arguments[0]) };
218 }()) || (function () {
219 const c = n.callee;
220 if (!c) return null;
221 const ci = (c.type === 'Identifier'
222 && c.name === 'require');
223 if (!ci) return null;
224 const f = (n.type === 'CallExpression'
225 && n.arguments
226 && n.arguments[0]);
227 if (!f) return null;
228 return { v1: reconstruct(n.arguments[0]) };
229 }());
230}
231
232module.exports.visitor_MALFORMED = function (node) { // eslint-disable-line camelcase
233 let was;
234
235 was = visitor_MALFORMED(node);
236 if (was) return { alias: was.v1 };
237
238 return null;
239};
240
241function visitor_USESCWD (n) { // eslint-disable-line camelcase
242 const c = n.callee;
243 if (!c) return null;
244 const ci = (c.object
245 && c.object.type === 'Identifier'
246 && c.object.name === 'path'
247 && c.property
248 && c.property.type === 'Identifier'
249 && c.property.name === 'resolve');
250 if (!ci) return null;
251 return { v1: n.arguments.map(reconstruct).join(', ') };
252}
253
254module.exports.visitor_USESCWD = function (node) { // eslint-disable-line camelcase
255 let was;
256
257 was = visitor_USESCWD(node);
258 if (was) return { alias: was.v1 };
259
260 return null;
261};
262
263function reconstructSpecifiers (specs) {
264 if (!specs || !specs.length) return '';
265 const defaults = [];
266 for (const spec of specs) {
267 if (spec.type === 'ImportDefaultSpecifier') {
268 defaults.push(spec.local.name);
269 }
270 }
271 const nonDefaults = [];
272 for (const spec of specs) {
273 if (spec.type === 'ImportSpecifier') {
274 if (spec.local.name === spec.imported.name) {
275 nonDefaults.push(spec.local.name);
276 } else {
277 nonDefaults.push(
278 spec.imported.name + ' as ' + spec.local.name
279 );
280 }
281 }
282 }
283 if (nonDefaults.length) {
284 defaults.push('{ ' + nonDefaults.join(', ') + ' }');
285 }
286 return defaults.join(', ');
287}
288
289function reconstruct (node) {
290 let v = generate(node).replace(/\n/g, '');
291 let v2;
292 while (true) {
293 v2 = v.replace(/\[ /g, '[')
294 .replace(/ \]/g, ']')
295 .replace(/ {2}/g, ' ');
296 if (v2 === v) break;
297 v = v2;
298 }
299 return v2;
300}
301
302function traverse (ast, visitor) {
303 // modified esprima-walk to support
304 // visitor return value and "trying" flag
305 let stack = [ [ ast, false ] ];
306 let i, j, key;
307 let len, item, node, trying, child;
308 for (i = 0; i < stack.length; i += 1) {
309 item = stack[i];
310 node = item[0];
311 if (node) {
312 trying = item[1] || (node.type === 'TryStatement');
313 if (visitor(node, trying)) {
314 for (key in node) {
315 child = node[key];
316 if (child instanceof Array) {
317 len = child.length;
318 for (j = 0; j < len; j += 1) {
319 stack.push([ child[j], trying ]);
320 }
321 } else
322 if (child && typeof child.type === 'string') {
323 stack.push([ child, trying ]);
324 }
325 }
326 }
327 }
328 }
329}
330
331module.exports.parse = function (body) {
332 return parse(body, {
333 allowImportExportEverywhere: true,
334 allowReturnOutsideFunction: true,
335 ecmaVersion: 8,
336 plugins: [ 'estree', 'bigInt', 'classPrivateProperties', 'classProperties' ]
337 });
338};
339
340module.exports.detect = function (body, visitor) {
341 const json = module.exports.parse(body);
342 if (!json) return;
343 traverse(json, visitor);
344};
345

Built with git-ssb-web