1 | "use strict";
|
2 |
|
3 | var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
4 |
|
5 | var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
6 |
|
7 | const path = require('path');
|
8 |
|
9 | const mm = require('micromatch');
|
10 |
|
11 | const t = require('@babel/types');
|
12 |
|
13 | const template = require('@babel/template').default;
|
14 |
|
15 | const rename = require('./renamer');
|
16 |
|
17 | const _require = require('./utils'),
|
18 | getName = _require.getName,
|
19 | getIdentifier = _require.getIdentifier,
|
20 | getExportIdentifier = _require.getExportIdentifier;
|
21 |
|
22 | const WRAPPER_TEMPLATE = template(`
|
23 | var NAME = (function () {
|
24 | var exports = this;
|
25 | var module = {exports: this};
|
26 | BODY;
|
27 | return module.exports;
|
28 | }).call({});
|
29 | `);
|
30 | const ESMODULE_TEMPLATE = template(`exports.__esModule = true;`);
|
31 | const EXPORT_ASSIGN_TEMPLATE = template('EXPORTS.NAME = LOCAL');
|
32 | const EXPORT_ALL_TEMPLATE = template('$parcel$exportWildcard(OLD_NAME, $parcel$require(ID, SOURCE))');
|
33 | const REQUIRE_CALL_TEMPLATE = template('$parcel$require(ID, SOURCE)');
|
34 | const REQUIRE_RESOLVE_CALL_TEMPLATE = template('$parcel$require$resolve(ID, SOURCE)');
|
35 | const TYPEOF = {
|
36 | module: 'object',
|
37 | require: 'function'
|
38 | };
|
39 |
|
40 | function hasSideEffects(asset, {
|
41 | sideEffects
|
42 | } = asset._package) {
|
43 | switch (typeof sideEffects) {
|
44 | case 'undefined':
|
45 | return true;
|
46 |
|
47 | case 'boolean':
|
48 | return sideEffects;
|
49 |
|
50 | case 'string':
|
51 | return mm.isMatch(path.relative(asset._package.pkgdir, asset.name), sideEffects, {
|
52 | matchBase: true
|
53 | });
|
54 |
|
55 | case 'object':
|
56 | return sideEffects.some(sideEffects => hasSideEffects(asset, {
|
57 | sideEffects
|
58 | }));
|
59 | }
|
60 | }
|
61 |
|
62 | module.exports = {
|
63 | Program: {
|
64 | enter(path, asset) {
|
65 | path.scope.crawl();
|
66 | asset.cacheData.imports = asset.cacheData.imports || Object.create(null);
|
67 | asset.cacheData.exports = asset.cacheData.exports || Object.create(null);
|
68 | asset.cacheData.wildcards = asset.cacheData.wildcards || [];
|
69 | asset.cacheData.sideEffects = asset._package && hasSideEffects(asset);
|
70 | let shouldWrap = false;
|
71 | path.traverse({
|
72 | CallExpression(path) {
|
73 |
|
74 |
|
75 | let callee = path.node.callee;
|
76 |
|
77 | if (t.isIdentifier(callee) && callee.name === 'eval' && !path.scope.hasBinding('eval', true)) {
|
78 | asset.cacheData.isCommonJS = true;
|
79 | shouldWrap = true;
|
80 | path.stop();
|
81 | }
|
82 | },
|
83 |
|
84 | ReturnStatement(path) {
|
85 |
|
86 | if (!path.getFunctionParent()) {
|
87 | shouldWrap = true;
|
88 | asset.cacheData.isCommonJS = true;
|
89 | path.replaceWith(t.returnStatement(t.memberExpression(t.identifier('module'), t.identifier('exports'))));
|
90 | path.stop();
|
91 | }
|
92 | },
|
93 |
|
94 | ReferencedIdentifier(path) {
|
95 |
|
96 |
|
97 | if (path.node.name === 'module' && (!path.parentPath.isMemberExpression() || path.parent.computed) && !(path.parentPath.isUnaryExpression() && path.parent.operator === 'typeof') && !path.scope.hasBinding('module') && !path.scope.getData('shouldWrap')) {
|
98 | asset.cacheData.isCommonJS = true;
|
99 | shouldWrap = true;
|
100 | path.stop();
|
101 | }
|
102 | }
|
103 |
|
104 | });
|
105 | path.scope.setData('shouldWrap', shouldWrap);
|
106 | },
|
107 |
|
108 | exit(path, asset) {
|
109 | let scope = path.scope;
|
110 |
|
111 | if (scope.getData('shouldWrap')) {
|
112 | if (asset.cacheData.isES6Module) {
|
113 | path.unshiftContainer('body', [ESMODULE_TEMPLATE()]);
|
114 | }
|
115 |
|
116 | path.replaceWith(t.program([WRAPPER_TEMPLATE({
|
117 | NAME: getExportsIdentifier(asset),
|
118 | BODY: path.node.body
|
119 | })]));
|
120 | asset.cacheData.exports = {};
|
121 | asset.cacheData.isCommonJS = true;
|
122 | asset.cacheData.isES6Module = false;
|
123 | } else {
|
124 |
|
125 | scope.crawl();
|
126 |
|
127 | for (let name in scope.bindings) {
|
128 | if (!name.startsWith('$' + t.toIdentifier(asset.id))) {
|
129 | let newName = getName(asset, 'var', name);
|
130 | rename(scope, name, newName);
|
131 | }
|
132 | }
|
133 |
|
134 | let exportsIdentifier = getExportsIdentifier(asset);
|
135 |
|
136 | if (scope.hasGlobal(exportsIdentifier.name) && !scope.hasBinding(exportsIdentifier.name)) {
|
137 | scope.push({
|
138 | id: exportsIdentifier,
|
139 | init: t.objectExpression([])
|
140 | });
|
141 | }
|
142 | }
|
143 |
|
144 | path.stop();
|
145 | asset.isAstDirty = true;
|
146 | }
|
147 |
|
148 | },
|
149 |
|
150 | DirectiveLiteral(path) {
|
151 |
|
152 |
|
153 | if (path.node.value === 'use strict') {
|
154 | path.parentPath.remove();
|
155 | }
|
156 | },
|
157 |
|
158 | MemberExpression(path, asset) {
|
159 | if (path.scope.hasBinding('module') || path.scope.getData('shouldWrap')) {
|
160 | return;
|
161 | }
|
162 |
|
163 | if (t.matchesPattern(path.node, 'module.exports')) {
|
164 | path.replaceWith(getExportsIdentifier(asset));
|
165 | asset.cacheData.isCommonJS = true;
|
166 | }
|
167 |
|
168 | if (t.matchesPattern(path.node, 'module.id')) {
|
169 | path.replaceWith(t.stringLiteral(asset.id));
|
170 | }
|
171 |
|
172 | if (t.matchesPattern(path.node, 'module.hot')) {
|
173 | path.replaceWith(t.identifier('null'));
|
174 | }
|
175 |
|
176 | if (t.matchesPattern(path.node, 'module.bundle')) {
|
177 | path.replaceWith(t.identifier('require'));
|
178 | }
|
179 | },
|
180 |
|
181 | ReferencedIdentifier(path, asset) {
|
182 | if (path.node.name === 'exports' && !path.scope.hasBinding('exports') && !path.scope.getData('shouldWrap')) {
|
183 | path.replaceWith(getExportsIdentifier(asset));
|
184 | asset.cacheData.isCommonJS = true;
|
185 | }
|
186 |
|
187 | if (path.node.name === 'global' && !path.scope.hasBinding('global')) {
|
188 | path.replaceWith(t.identifier('$parcel$global'));
|
189 | asset.globals.delete('global');
|
190 | }
|
191 |
|
192 | let globalCode = asset.globals.get(path.node.name);
|
193 |
|
194 | if (globalCode) {
|
195 | path.scope.getProgramParent().path.unshiftContainer('body', [template(globalCode)()]);
|
196 | asset.globals.delete(path.node.name);
|
197 | }
|
198 | },
|
199 |
|
200 | ThisExpression(path, asset) {
|
201 | if (!path.scope.parent && !path.scope.getData('shouldWrap')) {
|
202 | path.replaceWith(getExportsIdentifier(asset));
|
203 | asset.cacheData.isCommonJS = true;
|
204 | }
|
205 | },
|
206 |
|
207 | AssignmentExpression(path, asset) {
|
208 | if (path.scope.hasBinding('exports') || path.scope.getData('shouldWrap')) {
|
209 | return;
|
210 | }
|
211 |
|
212 | let _path$node = path.node,
|
213 | left = _path$node.left,
|
214 | right = _path$node.right;
|
215 |
|
216 | if (t.isIdentifier(left) && left.name === 'exports') {
|
217 | path.get('left').replaceWith(getExportsIdentifier(asset));
|
218 | asset.cacheData.isCommonJS = true;
|
219 | }
|
220 |
|
221 |
|
222 |
|
223 | if (t.isMemberExpression(left) && t.isIdentifier(left.object, {
|
224 | name: 'exports'
|
225 | }) && (t.isIdentifier(left.property) && !left.computed || t.isStringLiteral(left.property))) {
|
226 | let name = t.isIdentifier(left.property) ? left.property.name : left.property.value;
|
227 | let identifier = getExportIdentifier(asset, name);
|
228 |
|
229 | path.get('left.object').replaceWith(getExportsIdentifier(asset));
|
230 | path.get('right').replaceWith(identifier);
|
231 |
|
232 |
|
233 | let scope = path.scope.getProgramParent();
|
234 |
|
235 | if (!scope.hasBinding(identifier.name)) {
|
236 | asset.cacheData.exports[name] = identifier.name;
|
237 |
|
238 | let _path$insertBefore = path.insertBefore(t.variableDeclaration('var', [t.variableDeclarator(t.clone(identifier), right)])),
|
239 | _path$insertBefore2 = (0, _slicedToArray2.default)(_path$insertBefore, 1),
|
240 | decl = _path$insertBefore2[0];
|
241 |
|
242 | scope.registerDeclaration(decl);
|
243 | } else {
|
244 | path.insertBefore(t.assignmentExpression('=', t.clone(identifier), right));
|
245 | }
|
246 |
|
247 | asset.cacheData.isCommonJS = true;
|
248 | }
|
249 | },
|
250 |
|
251 | UnaryExpression(path) {
|
252 |
|
253 | if (path.node.operator === 'typeof' && t.isIdentifier(path.node.argument) && TYPEOF[path.node.argument.name] && !path.scope.hasBinding(path.node.argument.name) && !path.scope.getData('shouldWrap')) {
|
254 | path.replaceWith(t.stringLiteral(TYPEOF[path.node.argument.name]));
|
255 | }
|
256 | },
|
257 |
|
258 | CallExpression(path, asset) {
|
259 | let _path$node2 = path.node,
|
260 | callee = _path$node2.callee,
|
261 | args = _path$node2.arguments;
|
262 | let ignore = args.length !== 1 || !t.isStringLiteral(args[0]) || path.scope.hasBinding('require');
|
263 |
|
264 | if (ignore) {
|
265 | return;
|
266 | }
|
267 |
|
268 | if (t.isIdentifier(callee, {
|
269 | name: 'require'
|
270 | })) {
|
271 | let source = args[0].value;
|
272 |
|
273 | if (!asset.dependencies.has(source)) {
|
274 | return;
|
275 | }
|
276 |
|
277 |
|
278 |
|
279 |
|
280 | let parent = path.getStatementParent().parentPath;
|
281 | let bail = path.findParent(p => p.isConditionalExpression() || p.isLogicalExpression() || p.isSequenceExpression());
|
282 |
|
283 | if (!parent.isProgram() || bail) {
|
284 | asset.dependencies.get(source).shouldWrap = true;
|
285 | }
|
286 |
|
287 | asset.cacheData.imports['$require$' + source] = [source, '*'];
|
288 |
|
289 |
|
290 | path.replaceWith(REQUIRE_CALL_TEMPLATE({
|
291 | ID: t.stringLiteral(asset.id),
|
292 | SOURCE: t.stringLiteral(args[0].value)
|
293 | }));
|
294 | }
|
295 |
|
296 | if (t.matchesPattern(callee, 'require.resolve')) {
|
297 | path.replaceWith(REQUIRE_RESOLVE_CALL_TEMPLATE({
|
298 | ID: t.stringLiteral(asset.id),
|
299 | SOURCE: args[0]
|
300 | }));
|
301 | }
|
302 | },
|
303 |
|
304 | ImportDeclaration(path, asset) {
|
305 |
|
306 |
|
307 | var _iteratorNormalCompletion = true;
|
308 | var _didIteratorError = false;
|
309 | var _iteratorError = undefined;
|
310 |
|
311 | try {
|
312 | for (var _iterator = path.node.specifiers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
313 | let specifier = _step.value;
|
314 | let id = getIdentifier(asset, 'import', specifier.local.name);
|
315 | rename(path.scope, specifier.local.name, id.name);
|
316 |
|
317 | if (t.isImportDefaultSpecifier(specifier)) {
|
318 | asset.cacheData.imports[id.name] = [path.node.source.value, 'default'];
|
319 | } else if (t.isImportSpecifier(specifier)) {
|
320 | asset.cacheData.imports[id.name] = [path.node.source.value, specifier.imported.name];
|
321 | } else if (t.isImportNamespaceSpecifier(specifier)) {
|
322 | asset.cacheData.imports[id.name] = [path.node.source.value, '*'];
|
323 | }
|
324 | }
|
325 | } catch (err) {
|
326 | _didIteratorError = true;
|
327 | _iteratorError = err;
|
328 | } finally {
|
329 | try {
|
330 | if (!_iteratorNormalCompletion && _iterator.return != null) {
|
331 | _iterator.return();
|
332 | }
|
333 | } finally {
|
334 | if (_didIteratorError) {
|
335 | throw _iteratorError;
|
336 | }
|
337 | }
|
338 | }
|
339 |
|
340 | addImport(asset, path);
|
341 | path.remove();
|
342 | },
|
343 |
|
344 | ExportDefaultDeclaration(path, asset) {
|
345 | let declaration = path.node.declaration;
|
346 | let identifier = getExportIdentifier(asset, 'default');
|
347 | let name = declaration.id ? declaration.id.name : declaration.name;
|
348 |
|
349 | if (asset.cacheData.imports[name]) {
|
350 | asset.cacheData.exports['default'] = asset.cacheData.imports[name];
|
351 | identifier = t.identifier(name);
|
352 | }
|
353 |
|
354 | if (hasExport(asset, name)) {
|
355 | identifier = t.identifier(name);
|
356 | }
|
357 |
|
358 |
|
359 | path.insertAfter(EXPORT_ASSIGN_TEMPLATE({
|
360 | EXPORTS: getExportsIdentifier(asset, path.scope),
|
361 | NAME: t.identifier('default'),
|
362 | LOCAL: t.clone(identifier)
|
363 | }));
|
364 |
|
365 | if (t.isIdentifier(declaration)) {
|
366 |
|
367 | safeRename(path, asset, declaration.name, identifier.name);
|
368 | path.remove();
|
369 | } else if (t.isExpression(declaration) || !declaration.id) {
|
370 |
|
371 | path.replaceWith(t.variableDeclaration('var', [t.variableDeclarator(identifier, t.toExpression(declaration))]));
|
372 | path.scope.registerDeclaration(path);
|
373 | } else {
|
374 |
|
375 | safeRename(path, asset, declaration.id.name, identifier.name);
|
376 | path.replaceWith(declaration);
|
377 | }
|
378 |
|
379 | if (!asset.cacheData.exports['default']) {
|
380 | asset.cacheData.exports['default'] = identifier.name;
|
381 | }
|
382 |
|
383 |
|
384 | asset.cacheData.isES6Module = true;
|
385 | },
|
386 |
|
387 | ExportNamedDeclaration(path, asset) {
|
388 | let _path$node3 = path.node,
|
389 | declaration = _path$node3.declaration,
|
390 | source = _path$node3.source,
|
391 | specifiers = _path$node3.specifiers;
|
392 |
|
393 | if (source) {
|
394 | var _iteratorNormalCompletion2 = true;
|
395 | var _didIteratorError2 = false;
|
396 | var _iteratorError2 = undefined;
|
397 |
|
398 | try {
|
399 | for (var _iterator2 = specifiers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
400 | let specifier = _step2.value;
|
401 | let exported = specifier.exported;
|
402 |
|
403 | if (t.isExportDefaultSpecifier(specifier)) {
|
404 | asset.cacheData.exports[exported.name] = [source.value, 'default'];
|
405 | } else if (t.isExportNamespaceSpecifier(specifier)) {
|
406 | asset.cacheData.exports[exported.name] = [source.value, '*'];
|
407 | } else if (t.isExportSpecifier(specifier)) {
|
408 | asset.cacheData.exports[exported.name] = [source.value, specifier.local.name];
|
409 | }
|
410 |
|
411 | let id = getIdentifier(asset, 'import', exported.name);
|
412 | asset.cacheData.imports[id.name] = asset.cacheData.exports[exported.name];
|
413 | path.insertAfter(EXPORT_ASSIGN_TEMPLATE({
|
414 | EXPORTS: getExportsIdentifier(asset, path.scope),
|
415 | NAME: exported,
|
416 | LOCAL: id
|
417 | }));
|
418 | }
|
419 | } catch (err) {
|
420 | _didIteratorError2 = true;
|
421 | _iteratorError2 = err;
|
422 | } finally {
|
423 | try {
|
424 | if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
|
425 | _iterator2.return();
|
426 | }
|
427 | } finally {
|
428 | if (_didIteratorError2) {
|
429 | throw _iteratorError2;
|
430 | }
|
431 | }
|
432 | }
|
433 |
|
434 | addImport(asset, path);
|
435 | path.remove();
|
436 | } else if (declaration) {
|
437 | path.replaceWith(declaration);
|
438 | let identifiers = t.isIdentifier(declaration.id) ? [declaration.id] : t.getBindingIdentifiers(declaration);
|
439 |
|
440 | for (let id in identifiers) {
|
441 | addExport(asset, path, identifiers[id], identifiers[id]);
|
442 | }
|
443 | } else if (specifiers.length > 0) {
|
444 | var _iteratorNormalCompletion3 = true;
|
445 | var _didIteratorError3 = false;
|
446 | var _iteratorError3 = undefined;
|
447 |
|
448 | try {
|
449 | for (var _iterator3 = specifiers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
450 | let specifier = _step3.value;
|
451 | addExport(asset, path, specifier.local, specifier.exported);
|
452 | }
|
453 | } catch (err) {
|
454 | _didIteratorError3 = true;
|
455 | _iteratorError3 = err;
|
456 | } finally {
|
457 | try {
|
458 | if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
|
459 | _iterator3.return();
|
460 | }
|
461 | } finally {
|
462 | if (_didIteratorError3) {
|
463 | throw _iteratorError3;
|
464 | }
|
465 | }
|
466 | }
|
467 |
|
468 | path.remove();
|
469 | }
|
470 |
|
471 |
|
472 | asset.cacheData.isES6Module = true;
|
473 | },
|
474 |
|
475 | ExportAllDeclaration(path, asset) {
|
476 | asset.cacheData.wildcards.push(path.node.source.value);
|
477 | asset.cacheData.isES6Module = true;
|
478 | path.replaceWith(EXPORT_ALL_TEMPLATE({
|
479 | OLD_NAME: getExportsIdentifier(asset),
|
480 | SOURCE: t.stringLiteral(path.node.source.value),
|
481 | ID: t.stringLiteral(asset.id)
|
482 | }));
|
483 | }
|
484 |
|
485 | };
|
486 |
|
487 | function addImport(asset, path) {
|
488 |
|
489 | let requireCall = REQUIRE_CALL_TEMPLATE({
|
490 | ID: t.stringLiteral(asset.id),
|
491 | SOURCE: t.stringLiteral(path.node.source.value)
|
492 | });
|
493 |
|
494 | let lastImport = path.scope.getData('hoistedImport');
|
495 |
|
496 | if (lastImport) {
|
497 | var _lastImport$insertAft = lastImport.insertAfter(requireCall);
|
498 |
|
499 | var _lastImport$insertAft2 = (0, _slicedToArray2.default)(_lastImport$insertAft, 1);
|
500 |
|
501 | lastImport = _lastImport$insertAft2[0];
|
502 | } else {
|
503 | var _path$parentPath$unsh = path.parentPath.unshiftContainer('body', [requireCall]);
|
504 |
|
505 | var _path$parentPath$unsh2 = (0, _slicedToArray2.default)(_path$parentPath$unsh, 1);
|
506 |
|
507 | lastImport = _path$parentPath$unsh2[0];
|
508 | }
|
509 |
|
510 | path.scope.setData('hoistedImport', lastImport);
|
511 | }
|
512 |
|
513 | function addExport(asset, path, local, exported) {
|
514 | let scope = path.scope.getProgramParent();
|
515 | let identifier = getExportIdentifier(asset, exported.name);
|
516 |
|
517 | if (asset.cacheData.imports[local.name]) {
|
518 | asset.cacheData.exports[exported.name] = asset.cacheData.imports[local.name];
|
519 | identifier = t.identifier(local.name);
|
520 | }
|
521 |
|
522 | if (hasExport(asset, local.name)) {
|
523 | identifier = t.identifier(local.name);
|
524 | }
|
525 |
|
526 | let assignNode = EXPORT_ASSIGN_TEMPLATE({
|
527 | EXPORTS: getExportsIdentifier(asset, scope),
|
528 | NAME: t.identifier(exported.name),
|
529 | LOCAL: identifier
|
530 | });
|
531 | let binding = scope.getBinding(local.name);
|
532 | let constantViolations = binding ? binding.constantViolations.concat(path) : [path];
|
533 |
|
534 | if (!asset.cacheData.exports[exported.name]) {
|
535 | asset.cacheData.exports[exported.name] = identifier.name;
|
536 | }
|
537 |
|
538 | try {
|
539 | rename(scope, local.name, identifier.name);
|
540 | } catch (e) {
|
541 | throw new Error('export ' + e.message);
|
542 | }
|
543 |
|
544 | constantViolations.forEach(path => path.insertAfter(t.cloneDeep(assignNode)));
|
545 | }
|
546 |
|
547 | function hasExport(asset, name) {
|
548 | let exports = asset.cacheData.exports;
|
549 | return Object.keys(exports).some(k => exports[k] === name);
|
550 | }
|
551 |
|
552 | function safeRename(path, asset, from, to) {
|
553 | if (from === to) {
|
554 | return;
|
555 | }
|
556 |
|
557 |
|
558 |
|
559 | let binding = path.scope.getBinding(from);
|
560 |
|
561 | if (binding && binding.constant) {
|
562 | rename(path.scope, from, to);
|
563 | } else {
|
564 | let _path$insertAfter = path.insertAfter(t.variableDeclaration('var', [t.variableDeclarator(t.identifier(to), t.identifier(from))])),
|
565 | _path$insertAfter2 = (0, _slicedToArray2.default)(_path$insertAfter, 1),
|
566 | decl = _path$insertAfter2[0];
|
567 |
|
568 | path.scope.getBinding(from).reference(decl.get('declarations.0.init'));
|
569 | path.scope.registerDeclaration(decl);
|
570 | }
|
571 | }
|
572 |
|
573 | function getExportsIdentifier(asset, scope) {
|
574 | if (scope && scope.getData('shouldWrap')) {
|
575 | return t.identifier('exports');
|
576 | } else {
|
577 | return getIdentifier(asset, 'exports');
|
578 | }
|
579 | } |
\ | No newline at end of file |