UNPKG

28.9 kBJavaScriptView Raw
1const path = require('path');
2const { existsSync, statSync } = require('fs');
3const { walk } = require('estree-walker');
4const { attachScopes } = require('rollup-pluginutils');
5const evaluate = require('./utils/static-eval');
6let acorn = require('acorn');
7const bindings = require('bindings');
8const { isIdentifierRead, isLoop, isVarLoop } = require('./utils/ast-helpers');
9const glob = require('glob');
10const getPackageBase = require('./utils/get-package-base');
11const { pregyp, nbind } = require('./utils/binary-locators');
12const interopRequire = require('./utils/interop-require');
13const handleSpecialCases = require('./utils/special-cases');
14const resolve = require('./resolve-dependency.js');
15const nodeGypBuild = require('node-gyp-build');
16
17// Note: these should be deprecated over time as they ship in Acorn core
18acorn = acorn.Parser.extend(
19 require("acorn-class-fields"),
20 require("acorn-export-ns-from"),
21 require("acorn-import-meta"),
22 require("acorn-numeric-separator"),
23 require("acorn-static-class-features"),
24);
25const os = require('os');
26const handleWrappers = require('./utils/wrappers.js');
27const resolveFrom = require('resolve-from');
28
29const { UNKNOWN, FUNCTION, WILDCARD, wildcardRegEx } = evaluate;
30
31const staticProcess = {
32 cwd: () => {
33 return cwd;
34 },
35 env: {
36 NODE_ENV: UNKNOWN,
37 [UNKNOWN]: true
38 },
39 [UNKNOWN]: true
40};
41
42// unique symbol value to identify express instance in static analysis
43const EXPRESS_SET = Symbol();
44const EXPRESS_ENGINE = Symbol();
45const NBIND_INIT = Symbol();
46const SET_ROOT_DIR = Symbol();
47const PKG_INFO = Symbol();
48const FS_FN = Symbol();
49const BINDINGS = Symbol();
50const NODE_GYP_BUILD = Symbol();
51const fsSymbols = {
52 access: FS_FN,
53 accessSync: FS_FN,
54 createReadStream: FS_FN,
55 exists: FS_FN,
56 existsSync: FS_FN,
57 fstat: FS_FN,
58 fstatSync: FS_FN,
59 lstat: FS_FN,
60 lstatSync: FS_FN,
61 open: FS_FN,
62 readFile: FS_FN,
63 readFileSync: FS_FN,
64 stat: FS_FN,
65 statSync: FS_FN
66};
67const staticModules = Object.assign(Object.create(null), {
68 bindings: {
69 default: BINDINGS
70 },
71 express: {
72 default: function () {
73 return {
74 [UNKNOWN]: true,
75 set: EXPRESS_SET,
76 engine: EXPRESS_ENGINE
77 };
78 }
79 },
80 fs: {
81 default: fsSymbols,
82 ...fsSymbols
83 },
84 process: {
85 default: staticProcess,
86 ...staticProcess
87 },
88 // populated below
89 path: {
90 default: {}
91 },
92 os: {
93 default: os,
94 ...os
95 },
96 'node-pre-gyp': pregyp,
97 'node-pre-gyp/lib/pre-binding': pregyp,
98 'node-pre-gyp/lib/pre-binding.js': pregyp,
99 'node-gyp-build': {
100 default: NODE_GYP_BUILD
101 },
102 'nbind': {
103 init: NBIND_INIT,
104 default: {
105 init: NBIND_INIT
106 }
107 },
108 'resolve-from': {
109 default: resolveFrom
110 },
111 'strong-globalize': {
112 default: {
113 SetRootDir: SET_ROOT_DIR
114 },
115 SetRootDir: SET_ROOT_DIR
116 },
117 'pkginfo': {
118 default: PKG_INFO
119 }
120});
121const globalBindings = {
122 // Support for require calls generated from `import` statements by babel
123 _interopRequireDefault: interopRequire.normalizeDefaultRequire,
124 _interopRequireWildcard: interopRequire.normalizeWildcardRequire,
125 // Support for require calls generated from `import` statements by tsc
126 __importDefault: interopRequire.normalizeDefaultRequire,
127 __importStar: interopRequire.normalizeWildcardRequire,
128 MONGOOSE_DRIVER_PATH: undefined
129};
130globalBindings.global = globalBindings.GLOBAL = globalBindings.globalThis = globalBindings;
131
132// call expression triggers
133const TRIGGER = Symbol();
134pregyp.find[TRIGGER] = true;
135const staticPath = staticModules.path;
136Object.keys(path).forEach(name => {
137 const pathFn = path[name];
138 if (typeof pathFn === 'function') {
139 const fn = function () {
140 return pathFn.apply(this, arguments);
141 };
142 fn[TRIGGER] = true;
143 staticPath[name] = staticPath.default[name] = fn;
144 }
145 else {
146 staticPath[name] = staticPath.default[name] = pathFn;
147 }
148});
149
150// overload path.resolve to support custom cwd
151staticPath.resolve = staticPath.default.resolve = function (...args) {
152 return path.resolve.apply(this, [cwd, ...args]);
153};
154staticPath.resolve[TRIGGER] = true;
155
156const excludeAssetExtensions = new Set(['.h', '.cmake', '.c', '.cpp']);
157const excludeAssetFiles = new Set(['CHANGELOG.md', 'README.md', 'readme.md', 'changelog.md']);
158let cwd;
159
160const absoluteRegEx = /^\/[^\/]+|^[a-z]:[\\/][^\\/]+/i;
161function isAbsolutePathStr (str) {
162 return typeof str === 'string' && str.match(absoluteRegEx);
163}
164
165const BOUND_REQUIRE = Symbol();
166
167const repeatGlobRegEx = /([\/\\]\*\*[\/\\]\*)+/g
168
169module.exports = async function (id, code, job) {
170 const assets = new Set();
171 const deps = new Set();
172
173 const dir = path.dirname(id);
174 // if (typeof options.production === 'boolean' && staticProcess.env.NODE_ENV === UNKNOWN)
175 // staticProcess.env.NODE_ENV = options.production ? 'production' : 'dev';
176 cwd = job.base;
177 const pkgBase = getPackageBase(id);
178
179 const emitAssetDirectory = (wildcardPath) => {
180 if (!job.analysis.emitGlobs) return;
181 const wildcardIndex = wildcardPath.indexOf(WILDCARD);
182 const dirIndex = wildcardIndex === -1 ? wildcardPath.length : wildcardPath.lastIndexOf(path.sep, wildcardIndex);
183 const assetDirPath = wildcardPath.substr(0, dirIndex);
184 const patternPath = wildcardPath.substr(dirIndex);
185 const wildcardPattern = patternPath.replace(wildcardRegEx, (_match, index) => {
186 return patternPath[index - 1] === path.sep ? '**/*' : '*';
187 }).replace(repeatGlobRegEx, '/**/*') || '/**/*';
188
189 if (job.ignoreFn(path.relative(job.base, assetDirPath + wildcardPattern)))
190 return;
191
192 assetEmissionPromises = assetEmissionPromises.then(async () => {
193 if (job.log)
194 console.log('Globbing ' + assetDirPath + wildcardPattern);
195 const files = (await new Promise((resolve, reject) =>
196 glob(assetDirPath + wildcardPattern, { mark: true, ignore: assetDirPath + '/**/node_modules/**/*' }, (err, files) => err ? reject(err) : resolve(files))
197 ));
198 files
199 .filter(name =>
200 !excludeAssetExtensions.has(path.extname(name)) &&
201 !excludeAssetFiles.has(path.basename(name)) &&
202 !name.endsWith('/')
203 )
204 .forEach(file => assets.add(file));
205 });
206 };
207
208 let assetEmissionPromises = Promise.resolve();
209
210 // remove shebang
211 code = code.replace(/^#![^\n\r]*[\r\n]/, '');
212
213 let ast, isESM;
214 try {
215 ast = acorn.parse(code, { ecmaVersion: 2020, allowReturnOutsideFunction: true });
216 isESM = false;
217 }
218 catch (e) {
219 const isModule = e && e.message && e.message.includes('sourceType: module');
220 if (!isModule) {
221 job.warnings.add(new Error(`Failed to parse ${id} as script:\n${e && e.message}`));
222 }
223 }
224 if (!ast) {
225 try {
226 ast = acorn.parse(code, { ecmaVersion: 2020, sourceType: 'module' });
227 isESM = true;
228 }
229 catch (e) {
230 job.warnings.add(new Error(`Failed to parse ${id} as module:\n${e && e.message}`));
231 // Parser errors just skip analysis
232 return { assets, deps, isESM: false };
233 }
234 }
235
236 const knownBindings = Object.assign(Object.create(null), {
237 __dirname: {
238 shadowDepth: 0,
239 value: path.resolve(id, '..')
240 },
241 __filename: {
242 shadowDepth: 0,
243 value: id
244 },
245 process: {
246 shadowDepth: 0,
247 value: staticProcess
248 }
249 });
250
251 if (!isESM || job.mixedModules) {
252 knownBindings.require = {
253 shadowDepth: 0,
254 value: {
255 [FUNCTION] (specifier) {
256 deps.add(specifier);
257 const m = staticModules[specifier];
258 return m.default;
259 },
260 resolve (specifier) {
261 return resolve(specifier, id, job);
262 }
263 }
264 };
265 knownBindings.require.value.resolve[TRIGGER] = true;
266 }
267
268 function setKnownBinding (name, value) {
269 // require is somewhat special in that we shadow it but don't
270 // statically analyze it ("known unknown" of sorts)
271 if (name === 'require') return;
272 knownBindings[name] = {
273 shadowDepth: 0,
274 value: value
275 };
276 }
277 function getKnownBinding (name) {
278 const binding = knownBindings[name];
279 if (binding) {
280 if (binding.shadowDepth === 0) {
281 return binding.value;
282 }
283 }
284 }
285 function hasKnownBindingValue (name) {
286 const binding = knownBindings[name];
287 return binding && binding.shadowDepth === 0;
288 }
289
290 if (isESM || job.mixedModules) {
291 for (const decl of ast.body) {
292 if (decl.type === 'ImportDeclaration') {
293 const source = decl.source.value;
294 deps.add(source);
295 const staticModule = staticModules[source];
296 if (staticModule) {
297 for (const impt of decl.specifiers) {
298 if (impt.type === 'ImportNamespaceSpecifier')
299 setKnownBinding(impt.local.name, staticModule);
300 else if (impt.type === 'ImportDefaultSpecifier' && 'default' in staticModule)
301 setKnownBinding(impt.local.name, staticModule.default);
302 else if (impt.type === 'ImportSpecifier' && impt.imported.name in staticModule)
303 setKnownBinding(impt.local.name, staticModule[impt.imported.name]);
304 }
305 }
306 }
307 else if (decl.type === 'ExportNamedDeclaration' || decl.type === 'ExportAllDeclaration') {
308 if (decl.source) deps.add(decl.source.value);
309 }
310 }
311 }
312
313 function computePureStaticValue (expr, computeBranches = true) {
314 const vars = Object.create(null);
315 Object.keys(knownBindings).forEach(name => {
316 vars[name] = getKnownBinding(name);
317 });
318 Object.keys(globalBindings).forEach(name => {
319 vars[name] = globalBindings[name];
320 });
321 // evaluate returns undefined for non-statically-analyzable
322 const result = evaluate(expr, vars, computeBranches);
323 return result;
324 }
325
326 // statically determinable leaves are tracked, and inlined when the
327 // greatest parent statically known leaf computation corresponds to an asset path
328 let staticChildNode, staticChildValue;
329
330 // Express engine opt-out
331 let definedExpressEngines = false;
332
333 function emitWildcardRequire (wildcardRequire) {
334 if (!job.analysis.emitGlobs || !wildcardRequire.startsWith('./') && !wildcardRequire.startsWith('../')) return;
335
336 wildcardRequire = path.resolve(dir, wildcardRequire);
337
338 const wildcardIndex = wildcardRequire.indexOf(WILDCARD);
339 const dirIndex = wildcardIndex === -1 ? wildcardRequire.length : wildcardRequire.lastIndexOf(path.sep, wildcardIndex);
340 const wildcardDirPath = wildcardRequire.substr(0, dirIndex);
341 const patternPath = wildcardRequire.substr(dirIndex);
342 let wildcardPattern = patternPath.replace(wildcardRegEx, (_match, index) => {
343 return patternPath[index - 1] === path.sep ? '**/*' : '*';
344 }) || '/**/*';
345
346 if (!wildcardPattern.endsWith('*'))
347 wildcardPattern += '?(' + (job.ts ? '.ts|.tsx|' : '') + '.js|.json|.node)';
348
349 if (job.ignoreFn(path.relative(job.base, wildcardDirPath + wildcardPattern)))
350 return;
351
352 assetEmissionPromises = assetEmissionPromises.then(async () => {
353 if (job.log)
354 console.log('Globbing ' + wildcardDirPath + wildcardPattern);
355 const files = (await new Promise((resolve, reject) =>
356 glob(wildcardDirPath + wildcardPattern, { mark: true, ignore: wildcardDirPath + '/**/node_modules/**/*' }, (err, files) => err ? reject(err) : resolve(files))
357 ));
358 files
359 .filter(name =>
360 !excludeAssetExtensions.has(path.extname(name)) &&
361 !excludeAssetFiles.has(path.basename(name)) &&
362 !name.endsWith('/')
363 )
364 .forEach(file => assets.add(file));
365 });
366 }
367
368 function processRequireArg (expression) {
369 if (expression.type === 'ConditionalExpression') {
370 processRequireArg(expression.consequent);
371 processRequireArg(expression.alternate);
372 return;
373 }
374 if (expression.type === 'LogicalExpression') {
375 processRequireArg(expression.left);
376 processRequireArg(expression.right);
377 return;
378 }
379
380 let computed = computePureStaticValue(expression, true);
381 if (!computed) return;
382
383 if (typeof computed.value === 'string') {
384 if (!computed.wildcards)
385 deps.add(computed.value);
386 else if (computed.wildcards.length >= 1)
387 emitWildcardRequire(computed.value);
388 }
389 else {
390 if (typeof computed.then === 'string')
391 deps.add(computed.then);
392 if (typeof computed.else === 'string')
393 deps.add(computed.else);
394 }
395 }
396
397 handleWrappers(ast);
398 let scope = attachScopes(ast, 'scope');
399 ({ ast = ast, scope = scope } = handleSpecialCases({ id, ast, scope, emitAsset: path => assets.add(path), emitAssetDirectory, job }) || {});
400
401 function backtrack (self, parent) {
402 // computing a static expression outward
403 // -> compute and backtrack
404 if (!staticChildNode) throw new Error('Internal error: No staticChildNode for backtrack.');
405 const curStaticValue = computePureStaticValue(parent, true);
406 if (curStaticValue) {
407 if ('value' in curStaticValue && typeof curStaticValue.value !== 'symbol' ||
408 typeof curStaticValue.then !== 'symbol' && typeof curStaticValue.else !== 'symbol') {
409 staticChildValue = curStaticValue;
410 staticChildNode = parent;
411 if (self.skip) self.skip();
412 return;
413 }
414 }
415 // no static value -> see if we should emit the asset if it exists
416 emitStaticChildAsset();
417 }
418
419 walk(ast, {
420 enter (node, parent) {
421 if (node.scope) {
422 scope = node.scope;
423 for (const id in node.scope.declarations) {
424 if (id in knownBindings)
425 knownBindings[id].shadowDepth++;
426 }
427 }
428
429 // currently backtracking
430 if (staticChildNode) return;
431
432 if (node.type === 'Identifier') {
433 if (isIdentifierRead(node, parent) && job.analysis.computeFileReferences) {
434 let binding;
435 // detect asset leaf expression triggers (if not already)
436 // __dirname, __filename
437 // Could add import.meta.url, even path-like environment variables
438 if (typeof (binding = getKnownBinding(node.name)) === 'string' && binding.match(absoluteRegEx) ||
439 binding && (typeof binding === 'function' || typeof binding === 'object') && binding[TRIGGER]) {
440 staticChildValue = { value: typeof binding === 'string' ? binding : undefined };
441 staticChildNode = node;
442 backtrack(this, parent);
443 }
444 }
445 }
446 else if ((isESM || job.mixedModules) && node.type === 'ImportExpression') {
447 processRequireArg(node.source);
448 return;
449 }
450 // Call expression cases and asset triggers
451 // - fs triggers: fs.readFile(...)
452 // - require.resolve()
453 // - bindings()(...)
454 // - nodegyp()
455 // - etc.
456 else if (node.type === 'CallExpression') {
457 if ((!isESM || job.mixedModules) && node.callee.type === 'Identifier' && node.arguments.length) {
458 if (node.callee.name === 'require' && knownBindings.require.shadowDepth === 0) {
459 processRequireArg(node.arguments[0]);
460 return;
461 }
462 }
463 else if ((!isESM || job.mixedModules) &&
464 node.callee.type === 'MemberExpression' &&
465 node.callee.object.type === 'Identifier' &&
466 node.callee.object.name === 'module' &&
467 'module' in knownBindings === false &&
468 node.callee.property.type === 'Identifier' &&
469 !node.callee.computed &&
470 node.callee.property.name === 'require' &&
471 node.arguments.length) {
472 processRequireArg(node.arguments[0]);
473 return;
474 }
475
476 const calleeValue = job.analysis.evaluatePureExpressions && computePureStaticValue(node.callee, false);
477 // if we have a direct pure static function,
478 // and that function has a [TRIGGER] symbol -> trigger asset emission from it
479 if (calleeValue && typeof calleeValue.value === 'function' && calleeValue.value[TRIGGER] && job.analysis.computeFileReferences) {
480 staticChildValue = computePureStaticValue(node, true);
481 // if it computes, then we start backtracking
482 if (staticChildValue) {
483 staticChildNode = node;
484 backtrack(this, parent);
485 }
486 }
487 // handle well-known function symbol cases
488 else if (calleeValue && typeof calleeValue.value === 'symbol') {
489 switch (calleeValue.value) {
490 // customRequireWrapper('...')
491 case BOUND_REQUIRE:
492 if (node.arguments.length === 1 &&
493 node.arguments[0].type === 'Literal' &&
494 node.callee.type === 'Identifier' &&
495 knownBindings.require.shadowDepth === 0) {
496 processRequireArg(node.arguments[0]);
497 }
498 break;
499 // require('bindings')(...)
500 case BINDINGS:
501 if (node.arguments.length) {
502 const arg = computePureStaticValue(node.arguments[0], false);
503 if (arg && arg.value) {
504 let staticBindingsInstance = false;
505 let opts;
506 if (typeof arg.value === 'object')
507 opts = arg.value;
508 else if (typeof arg.value === 'string')
509 opts = { bindings: arg.value };
510 if (!opts.path) {
511 staticBindingsInstance = true;
512 opts.path = true;
513 }
514 opts.module_root = pkgBase;
515 let resolved;
516 try {
517 resolved = bindings(opts);
518 }
519 catch (e) {}
520 if (resolved) {
521 staticChildValue = { value: resolved };
522 staticChildNode = node;
523 emitStaticChildAsset(staticBindingsInstance);
524 }
525 }
526 }
527 break;
528 case NODE_GYP_BUILD:
529 if (node.arguments.length === 1 && node.arguments[0].type === 'Identifier' &&
530 node.arguments[0].name === '__dirname' && knownBindings.__dirname.shadowDepth === 0) {
531 transformed = true;
532 let resolved;
533 try {
534 resolved = nodeGypBuild.path(dir);
535 }
536 catch (e) {}
537 if (resolved) {
538 staticChildValue = { value: resolved };
539 staticChildNode = node;
540 emitStaticChildAsset(path);
541 }
542 }
543 break;
544 // nbind.init(...) -> require('./resolved.node')
545 case NBIND_INIT:
546 if (node.arguments.length) {
547 const arg = computePureStaticValue(node.arguments[0], false);
548 if (arg && arg.value) {
549 const bindingInfo = nbind(arg.value);
550 if (bindingInfo) {
551 deps.add(path.relative(dir, bindingInfo.path).replace(/\\/g, '/'));
552 return this.skip();
553 }
554 }
555 }
556 break;
557 // Express templates:
558 // app.set("view engine", [name]) -> 'name' is a require
559 case EXPRESS_SET:
560 if (node.arguments.length === 2 &&
561 node.arguments[0].type === 'Literal' &&
562 node.arguments[0].value === 'view engine' &&
563 !definedExpressEngines) {
564 processRequireArg(node.arguments[1]);
565 return this.skip();
566 }
567 break;
568 // app.engine('name', ...) causes opt-out of express dynamic require
569 case EXPRESS_ENGINE:
570 definedExpressEngines = true;
571 break;
572 case FS_FN:
573 if (node.arguments[0] && job.analysis.computeFileReferences) {
574 staticChildValue = computePureStaticValue(node.arguments[0], true);
575 // if it computes, then we start backtracking
576 if (staticChildValue) {
577 staticChildNode = node.arguments[0];
578 backtrack(this, parent);
579 return this.skip();
580 }
581 }
582 break;
583 // strong globalize (emits intl folder)
584 case SET_ROOT_DIR:
585 if (node.arguments[0]) {
586 const rootDir = computePureStaticValue(node.arguments[0], false);
587 if (rootDir && rootDir.value)
588 emitAssetDirectory(rootDir.value + '/intl');
589 return this.skip();
590 }
591 break;
592 // pkginfo - require('pkginfo')(module) -> loads package.json
593 case PKG_INFO:
594 let pjsonPath = path.resolve(id, '../package.json');
595 const rootPjson = path.resolve('/package.json');
596 while (pjsonPath !== rootPjson && !existsSync(pjsonPath))
597 pjsonPath = path.resolve(pjsonPath, '../../package.json');
598 if (pjsonPath !== rootPjson)
599 assets.add(pjsonPath);
600 break;
601 }
602 }
603 }
604 else if (node.type === 'VariableDeclaration' && !isVarLoop(parent) && job.analysis.evaluatePureExpressions) {
605 for (const decl of node.declarations) {
606 if (!decl.init) continue;
607 const computed = computePureStaticValue(decl.init, false);
608 if (computed && 'value' in computed) {
609 // var known = ...;
610 if (decl.id.type === 'Identifier') {
611 setKnownBinding(decl.id.name, computed.value);
612 }
613 // var { known } = ...;
614 else if (decl.id.type === 'ObjectPattern') {
615 for (const prop of decl.id.properties) {
616 if (prop.type !== 'Property' ||
617 prop.key.type !== 'Identifier' ||
618 prop.value.type !== 'Identifier' ||
619 typeof computed.value !== 'object' ||
620 computed.value === null ||
621 !(prop.key.name in computed.value))
622 continue;
623 setKnownBinding(prop.value.name, computed.value[prop.key.name]);
624 }
625 }
626 if (isAbsolutePathStr(computed.value)) {
627 staticChildValue = computed;
628 staticChildNode = decl.init;
629 emitStaticChildAsset();
630 }
631 }
632 }
633 }
634 else if (node.type === 'AssignmentExpression' && !isLoop(parent) && job.analysis.evaluatePureExpressions) {
635 if (!hasKnownBindingValue(node.left.name)) {
636 const computed = computePureStaticValue(node.right, false);
637 if (computed && 'value' in computed) {
638 // var known = ...
639 if (node.left.type === 'Identifier') {
640 setKnownBinding(node.left.name, computed.value);
641 }
642 // var { known } = ...
643 else if (node.left.type === 'ObjectPattern') {
644 for (const prop of node.left.properties) {
645 if (prop.type !== 'Property' ||
646 prop.key.type !== 'Identifier' ||
647 prop.value.type !== 'Identifier' ||
648 typeof computed.value !== 'object' ||
649 computed.value === null ||
650 !(prop.key.name in computed.value))
651 continue;
652 setKnownBinding(prop.value.name, computed.value[prop.key.name]);
653 }
654 }
655 if (isAbsolutePathStr(computed.value)) {
656 staticChildValue = computed;
657 staticChildNode = node.right;
658 emitStaticChildAsset();
659 }
660 }
661 }
662 }
663 // Support require wrappers like function p (x) { ...; var y = require(x); ...; return y; }
664 else if ((!isESM || job.mixedModules) &&
665 (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') &&
666 (node.arguments || node.params)[0] && (node.arguments || node.params)[0].type === 'Identifier') {
667 let fnName, args;
668 if ((node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') &&
669 parent.type === 'VariableDeclarator' &&
670 parent.id.type === 'Identifier') {
671 fnName = parent.id;
672 args = node.arguments || node.params;
673 }
674 else if (node.id) {
675 fnName = node.id;
676 args = node.arguments || node.params;
677 }
678 if (fnName && node.body.body) {
679 let requireDecl, returned = false;
680 for (let i = 0; i < node.body.body.length; i++) {
681 if (node.body.body[i].type === 'VariableDeclaration' && !requireDecl) {
682 requireDecl = node.body.body[i].declarations.find(decl =>
683 decl.id.type === 'Identifier' &&
684 decl.init &&
685 decl.init.type === 'CallExpression' &&
686 decl.init.callee.type === 'Identifier' &&
687 decl.init.callee.name === 'require' &&
688 knownBindings.require.shadowDepth === 0 &&
689 decl.init.arguments[0] &&
690 decl.init.arguments[0].type === 'Identifier' &&
691 decl.init.arguments[0].name === args[0].name
692 );
693 }
694 if (requireDecl &&
695 node.body.body[i].type === 'ReturnStatement' &&
696 node.body.body[i].argument &&
697 node.body.body[i].argument.type === 'Identifier' &&
698 node.body.body[i].argument.name === requireDecl.id.name) {
699 returned = true;
700 break;
701 }
702 }
703 if (returned)
704 setKnownBinding(fnName.name, BOUND_REQUIRE);
705 }
706 }
707 },
708 leave (node, parent) {
709 if (node.scope) {
710 scope = scope.parent;
711 for (const id in node.scope.declarations) {
712 if (id in knownBindings) {
713 if (knownBindings[id].shadowDepth > 0)
714 knownBindings[id].shadowDepth--;
715 else
716 delete knownBindings[id];
717 }
718 }
719 }
720
721 if (staticChildNode) backtrack(this, parent);
722 }
723 });
724
725 await assetEmissionPromises;
726 return { assets, deps, isESM };
727
728 function emitAssetPath (assetPath) {
729 // verify the asset file / directory exists
730 const wildcardIndex = assetPath.indexOf(WILDCARD);
731 const dirIndex = wildcardIndex === -1 ? assetPath.length : assetPath.lastIndexOf(path.sep, wildcardIndex);
732 const basePath = assetPath.substr(0, dirIndex);
733 try {
734 var stats = statSync(basePath);
735 }
736 catch (e) {
737 return;
738 }
739 if (wildcardIndex !== -1 && stats.isFile())
740 return;
741 if (stats.isFile()) {
742 assets.add(assetPath);
743 }
744 else if (stats.isDirectory()) {
745 if (validWildcard(assetPath))
746 emitAssetDirectory(assetPath);
747 }
748 }
749
750 function validWildcard (assetPath) {
751 let wildcardSuffix = '';
752 if (assetPath.endsWith(path.sep))
753 wildcardSuffix = path.sep;
754 else if (assetPath.endsWith(path.sep + WILDCARD))
755 wildcardSuffix = path.sep + WILDCARD;
756 else if (assetPath.endsWith(WILDCARD))
757 wildcardSuffix = WILDCARD;
758 // do not emit __dirname
759 if (assetPath === dir + wildcardSuffix)
760 return false;
761 // do not emit cwd
762 if (assetPath === cwd + wildcardSuffix)
763 return false;
764 // do not emit node_modules
765 if (assetPath.endsWith(path.sep + 'node_modules' + wildcardSuffix))
766 return false;
767 // do not emit directories above __dirname
768 if (dir.startsWith(assetPath.substr(0, assetPath.length - wildcardSuffix.length) + path.sep))
769 return false;
770 // do not emit asset directories higher than the node_modules base if a package
771 if (pkgBase) {
772 const nodeModulesBase = id.substr(0, id.indexOf(path.sep + 'node_modules')) + path.sep + 'node_modules' + path.sep;
773 if (!assetPath.startsWith(nodeModulesBase)) {
774 if (job.log) console.log('Skipping asset emission of ' + assetPath.replace(wildcardRegEx, '*') + ' for ' + id + ' as it is outside the package base ' + pkgBase);
775 return false;
776 }
777 }
778 return true;
779 }
780
781 function emitStaticChildAsset () {
782 if (isAbsolutePathStr(staticChildValue.value)) {
783 let resolved;
784 try { resolved = path.resolve(staticChildValue.value); }
785 catch (e) {}
786 emitAssetPath(resolved);
787 }
788 else if (isAbsolutePathStr(staticChildValue.then) && isAbsolutePathStr(staticChildValue.else)) {
789 let resolvedThen;
790 try { resolvedThen = path.resolve(staticChildValue.then); }
791 catch (e) {}
792 let resolvedElse;
793 try { resolvedElse = path.resolve(staticChildValue.else); }
794 catch (e) {}
795 if (resolvedThen) emitAssetPath(resolvedThen);
796 if (resolvedElse) emitAssetPath(resolvedElse);
797 }
798 staticChildNode = staticChildValue = undefined;
799 }
800};