1 | const path = require('path');
|
2 | const { existsSync, statSync } = require('fs');
|
3 | const { walk } = require('estree-walker');
|
4 | const { attachScopes } = require('rollup-pluginutils');
|
5 | const evaluate = require('./utils/static-eval');
|
6 | let acorn = require('acorn');
|
7 | const bindings = require('bindings');
|
8 | const { isIdentifierRead, isLoop, isVarLoop } = require('./utils/ast-helpers');
|
9 | const glob = require('glob');
|
10 | const getPackageBase = require('./utils/get-package-base');
|
11 | const { pregyp, nbind } = require('./utils/binary-locators');
|
12 | const interopRequire = require('./utils/interop-require');
|
13 | const handleSpecialCases = require('./utils/special-cases');
|
14 | const resolve = require('./resolve-dependency.js');
|
15 | const nodeGypBuild = require('node-gyp-build');
|
16 |
|
17 |
|
18 | acorn = 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 | );
|
25 | const os = require('os');
|
26 | const handleWrappers = require('./utils/wrappers.js');
|
27 | const resolveFrom = require('resolve-from');
|
28 |
|
29 | const { UNKNOWN, FUNCTION, WILDCARD, wildcardRegEx } = evaluate;
|
30 |
|
31 | const staticProcess = {
|
32 | cwd: () => {
|
33 | return cwd;
|
34 | },
|
35 | env: {
|
36 | NODE_ENV: UNKNOWN,
|
37 | [UNKNOWN]: true
|
38 | },
|
39 | [UNKNOWN]: true
|
40 | };
|
41 |
|
42 |
|
43 | const EXPRESS_SET = Symbol();
|
44 | const EXPRESS_ENGINE = Symbol();
|
45 | const NBIND_INIT = Symbol();
|
46 | const SET_ROOT_DIR = Symbol();
|
47 | const PKG_INFO = Symbol();
|
48 | const FS_FN = Symbol();
|
49 | const BINDINGS = Symbol();
|
50 | const NODE_GYP_BUILD = Symbol();
|
51 | const 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 | };
|
67 | const 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 |
|
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 | });
|
121 | const globalBindings = {
|
122 |
|
123 | _interopRequireDefault: interopRequire.normalizeDefaultRequire,
|
124 | _interopRequireWildcard: interopRequire.normalizeWildcardRequire,
|
125 |
|
126 | __importDefault: interopRequire.normalizeDefaultRequire,
|
127 | __importStar: interopRequire.normalizeWildcardRequire,
|
128 | MONGOOSE_DRIVER_PATH: undefined
|
129 | };
|
130 | globalBindings.global = globalBindings.GLOBAL = globalBindings.globalThis = globalBindings;
|
131 |
|
132 |
|
133 | const TRIGGER = Symbol();
|
134 | pregyp.find[TRIGGER] = true;
|
135 | const staticPath = staticModules.path;
|
136 | Object.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 |
|
151 | staticPath.resolve = staticPath.default.resolve = function (...args) {
|
152 | return path.resolve.apply(this, [cwd, ...args]);
|
153 | };
|
154 | staticPath.resolve[TRIGGER] = true;
|
155 |
|
156 | const excludeAssetExtensions = new Set(['.h', '.cmake', '.c', '.cpp']);
|
157 | const excludeAssetFiles = new Set(['CHANGELOG.md', 'README.md', 'readme.md', 'changelog.md']);
|
158 | let cwd;
|
159 |
|
160 | const absoluteRegEx = /^\/[^\/]+|^[a-z]:[\\/][^\\/]+/i;
|
161 | function isAbsolutePathStr (str) {
|
162 | return typeof str === 'string' && str.match(absoluteRegEx);
|
163 | }
|
164 |
|
165 | const BOUND_REQUIRE = Symbol();
|
166 |
|
167 | const repeatGlobRegEx = /([\/\\]\*\*[\/\\]\*)+/g
|
168 |
|
169 | module.exports = async function (id, code, job) {
|
170 | const assets = new Set();
|
171 | const deps = new Set();
|
172 |
|
173 | const dir = path.dirname(id);
|
174 |
|
175 |
|
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 |
|
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 |
|
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 |
|
270 |
|
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 |
|
322 | const result = evaluate(expr, vars, computeBranches);
|
323 | return result;
|
324 | }
|
325 |
|
326 |
|
327 |
|
328 | let staticChildNode, staticChildValue;
|
329 |
|
330 |
|
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 |
|
403 |
|
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 |
|
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 |
|
430 | if (staticChildNode) return;
|
431 |
|
432 | if (node.type === 'Identifier') {
|
433 | if (isIdentifierRead(node, parent) && job.analysis.computeFileReferences) {
|
434 | let binding;
|
435 |
|
436 |
|
437 |
|
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 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
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 |
|
478 |
|
479 | if (calleeValue && typeof calleeValue.value === 'function' && calleeValue.value[TRIGGER] && job.analysis.computeFileReferences) {
|
480 | staticChildValue = computePureStaticValue(node, true);
|
481 |
|
482 | if (staticChildValue) {
|
483 | staticChildNode = node;
|
484 | backtrack(this, parent);
|
485 | }
|
486 | }
|
487 |
|
488 | else if (calleeValue && typeof calleeValue.value === 'symbol') {
|
489 | switch (calleeValue.value) {
|
490 |
|
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 |
|
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 |
|
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 |
|
558 |
|
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 |
|
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 |
|
576 | if (staticChildValue) {
|
577 | staticChildNode = node.arguments[0];
|
578 | backtrack(this, parent);
|
579 | return this.skip();
|
580 | }
|
581 | }
|
582 | break;
|
583 |
|
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 |
|
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 |
|
610 | if (decl.id.type === 'Identifier') {
|
611 | setKnownBinding(decl.id.name, computed.value);
|
612 | }
|
613 |
|
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 |
|
639 | if (node.left.type === 'Identifier') {
|
640 | setKnownBinding(node.left.name, computed.value);
|
641 | }
|
642 |
|
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 |
|
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 |
|
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 |
|
759 | if (assetPath === dir + wildcardSuffix)
|
760 | return false;
|
761 |
|
762 | if (assetPath === cwd + wildcardSuffix)
|
763 | return false;
|
764 |
|
765 | if (assetPath.endsWith(path.sep + 'node_modules' + wildcardSuffix))
|
766 | return false;
|
767 |
|
768 | if (dir.startsWith(assetPath.substr(0, assetPath.length - wildcardSuffix.length) + path.sep))
|
769 | return false;
|
770 |
|
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 | };
|