@parcel/packager-js 2.0.0-dev.1518 → 2.0.0-dev.1528

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.ESMOutputFormat = void 0;
7
+ var _utils = require("./utils");
7
8
  class ESMOutputFormat {
8
9
  constructor(packager) {
9
10
  this.packager = packager;
@@ -22,6 +23,9 @@ class ESMOutputFormat {
22
23
  namespaceSpecifier = `* as ${symbol}`;
23
24
  } else {
24
25
  let specifier = imported;
26
+ if (!(0, _utils.isValidIdentifier)(specifier)) {
27
+ specifier = JSON.stringify(specifier);
28
+ }
25
29
  if (symbol !== imported) {
26
30
  specifier += ` as ${symbol}`;
27
31
  }
@@ -78,7 +82,10 @@ class ESMOutputFormat {
78
82
  }
79
83
  for (let as of exportAs) {
80
84
  let specifier = local;
81
- if (exportAs !== local) {
85
+ if (as !== local) {
86
+ if (!(0, _utils.isValidIdentifier)(as)) {
87
+ as = JSON.stringify(as);
88
+ }
82
89
  specifier += ` as ${as}`;
83
90
  }
84
91
  exportSpecifiers.push(specifier);
@@ -61,11 +61,6 @@ var _utils2 = require("./utils");
61
61
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
62
62
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
63
63
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
64
- // https://262.ecma-international.org/6.0/#sec-names-and-keywords
65
- const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
66
- const ID_START_RE = /^[$_\p{ID_Start}]/u;
67
- const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
68
-
69
64
  // General regex used to replace imports with the resolved code, references with resolutions,
70
65
  // and count the number of newlines in the file for source maps.
71
66
  const REPLACEMENT_RE = /\n|import\s+"([0-9a-f]{16}:.+?)";|(?:\$[0-9a-f]{16}\$exports)|(?:\$[0-9a-f]{16}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
@@ -116,23 +111,10 @@ class ScopeHoistingPackager {
116
111
  // of each bundle group pointing at the sibling bundles. These can be
117
112
  // picked up by another bundler later at which point runtimes will be added.
118
113
  if (this.bundle.env.isLibrary || this.bundle.env.outputFormat === 'commonjs') {
119
- for (let b of this.bundleGraph.getReferencedBundles(this.bundle)) {
120
- let entry = b.getMainEntry();
121
- let symbols = new Map();
122
- if (entry && !this.isAsyncBundle && entry.type === 'js') {
123
- this.externalAssets.add(entry);
124
- let usedSymbols = this.bundleGraph.getUsedSymbols(entry) || new Set();
125
- for (let s of usedSymbols) {
126
- // If the referenced bundle is ESM, and we are importing '*', use 'default' instead.
127
- // This matches the logic below in buildExportedSymbols.
128
- let imported = s;
129
- if (imported === '*' && b.env.outputFormat === 'esmodule') {
130
- imported = 'default';
131
- }
132
- symbols.set(imported, this.getSymbolResolution(entry, entry, s));
133
- }
134
- }
135
- this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), symbols);
114
+ for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
115
+ recursive: false
116
+ })) {
117
+ this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), new Map());
136
118
  }
137
119
  }
138
120
  let res = '';
@@ -256,7 +238,7 @@ class ScopeHoistingPackager {
256
238
  map
257
239
  }];
258
240
  });
259
- if (asset.meta.shouldWrap || this.isAsyncBundle || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
241
+ if (asset.meta.shouldWrap || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) {
260
242
  if (!asset.meta.isConstantModule) {
261
243
  this.wrappedAssets.add(asset.id);
262
244
  wrapped.push(asset);
@@ -282,7 +264,7 @@ class ScopeHoistingPackager {
282
264
  return wrapped;
283
265
  }
284
266
  buildExportedSymbols() {
285
- if (this.isAsyncBundle || !this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
267
+ if (!this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
286
268
  return;
287
269
  }
288
270
 
@@ -331,8 +313,8 @@ class ScopeHoistingPackager {
331
313
  }
332
314
  }
333
315
  getTopLevelName(name) {
334
- name = name.replace(NON_ID_CONTINUE_RE, '');
335
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
316
+ name = (0, _utils2.makeValidIdentifier)(name);
317
+ if (this.globalNames.has(name)) {
336
318
  name = '_' + name;
337
319
  }
338
320
  let count = this.topLevelNames.get(name);
@@ -344,7 +326,7 @@ class ScopeHoistingPackager {
344
326
  return name + count;
345
327
  }
346
328
  getPropertyAccess(obj, property) {
347
- if (IDENTIFIER_RE.test(property)) {
329
+ if ((0, _utils2.isValidIdentifier)(property)) {
348
330
  return `${obj}.${property}`;
349
331
  }
350
332
  return `${obj}[${JSON.stringify(property)}]`;
@@ -401,7 +383,7 @@ class ScopeHoistingPackager {
401
383
  code = code.replace('$parcel$filenameReplace', relPath);
402
384
  }
403
385
  let [depMap, replacements] = this.buildReplacements(asset, deps);
404
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
386
+ let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps, replacements);
405
387
  if (prependLines > 0) {
406
388
  sourceMap === null || sourceMap === void 0 || sourceMap.offsetLines(1, prependLines);
407
389
  code = prepend + code;
@@ -543,6 +525,16 @@ ${code}
543
525
  if (!resolved) {
544
526
  continue;
545
527
  }
528
+
529
+ // Handle imports from other bundles in libraries.
530
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
531
+ let referencedBundle = this.bundleGraph.getReferencedBundle(dep, this.bundle);
532
+ if (referencedBundle && referencedBundle.getMainEntry() === resolved && referencedBundle.type === 'js' && !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)) {
533
+ this.addExternal(dep, replacements, referencedBundle);
534
+ this.externalAssets.add(resolved);
535
+ continue;
536
+ }
537
+ }
546
538
  for (let [imported, {
547
539
  local
548
540
  }] of dep.symbols) {
@@ -575,7 +567,7 @@ ${code}
575
567
  }
576
568
  return [depMap, replacements];
577
569
  }
578
- addExternal(dep, replacements) {
570
+ addExternal(dep, replacements, referencedBundle) {
579
571
  if (this.bundle.env.outputFormat === 'global') {
580
572
  throw new (_diagnostic().default)({
581
573
  diagnostic: {
@@ -587,12 +579,16 @@ ${code}
587
579
  }
588
580
  });
589
581
  }
582
+ let specifier = dep.specifier;
583
+ if (referencedBundle) {
584
+ specifier = (0, _utils().relativeBundlePath)(this.bundle, referencedBundle);
585
+ }
590
586
 
591
587
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
592
- let external = this.externals.get(dep.specifier);
588
+ let external = this.externals.get(specifier);
593
589
  if (!external) {
594
590
  external = new Map();
595
- this.externals.set(dep.specifier, external);
591
+ this.externals.set(specifier, external);
596
592
  }
597
593
  for (let [imported, {
598
594
  local
@@ -609,7 +605,13 @@ ${code}
609
605
  if (this.bundle.env.outputFormat === 'commonjs') {
610
606
  renamed = external.get('*');
611
607
  if (!renamed) {
612
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
608
+ if (referencedBundle) {
609
+ var _entry$symbols$get$lo, _entry$symbols$get3;
610
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
611
+ renamed = (_entry$symbols$get$lo = (_entry$symbols$get3 = entry.symbols.get('*')) === null || _entry$symbols$get3 === void 0 ? void 0 : _entry$symbols$get3.local) !== null && _entry$symbols$get$lo !== void 0 ? _entry$symbols$get$lo : `$${String(entry.meta.id)}$exports`;
612
+ } else {
613
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
614
+ }
613
615
  external.set('*', renamed);
614
616
  }
615
617
  if (local !== '*' && replacements) {
@@ -625,19 +627,55 @@ ${code}
625
627
  replacements.set(local, replacement);
626
628
  }
627
629
  } else {
630
+ let property;
631
+ if (referencedBundle) {
632
+ let entry = (0, _nullthrows().default)(referencedBundle.getMainEntry());
633
+ if (entry.symbols.hasExportSymbol('*')) {
634
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
635
+ // This mirrors the logic in buildExportedSymbols.
636
+ property = imported;
637
+ imported = (referencedBundle === null || referencedBundle === void 0 ? void 0 : referencedBundle.env.outputFormat) === 'esmodule' ? 'default' : '*';
638
+ } else {
639
+ if (imported === '*') {
640
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
641
+ if (local === '*') {
642
+ // Re-export all symbols.
643
+ for (let exported of exportedSymbols) {
644
+ if (exported.symbol) {
645
+ external.set(exported.exportSymbol, exported.symbol);
646
+ }
647
+ }
648
+ continue;
649
+ }
650
+ }
651
+ renamed = this.bundleGraph.getSymbolResolution(entry, imported, this.bundle).symbol;
652
+ }
653
+ }
654
+
628
655
  // Rename the specifier so that multiple local imports of the same imported specifier
629
656
  // are deduplicated. We have to prefix the imported name with the bundle id so that
630
657
  // local variables do not shadow it.
631
- if (this.exportedSymbols.has(local)) {
632
- renamed = local;
633
- } else if (imported === 'default' || imported === '*') {
634
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
635
- } else {
636
- renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
658
+ if (!renamed) {
659
+ if (this.exportedSymbols.has(local)) {
660
+ renamed = local;
661
+ } else if (imported === 'default' || imported === '*') {
662
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${specifier}`);
663
+ } else {
664
+ renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
665
+ }
637
666
  }
638
667
  external.set(imported, renamed);
639
668
  if (local !== '*' && replacements) {
640
- replacements.set(local, renamed);
669
+ let replacement = renamed;
670
+ if (property === '*') {
671
+ replacement = renamed;
672
+ } else if (property === 'default') {
673
+ replacement = `($parcel$interopDefault(${renamed}))`;
674
+ this.usedHelpers.add('$parcel$interopDefault');
675
+ } else if (property) {
676
+ replacement = this.getPropertyAccess(renamed, property);
677
+ }
678
+ replacements.set(local, replacement);
641
679
  }
642
680
  }
643
681
  }
@@ -649,8 +687,7 @@ ${code}
649
687
  }
650
688
  return !this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset;
651
689
  }
652
- getSymbolResolution(parentAsset, resolved, imported, dep) {
653
- var _resolvedAsset$symbol;
690
+ getSymbolResolution(parentAsset, resolved, imported, dep, replacements) {
654
691
  let {
655
692
  asset: resolvedAsset,
656
693
  exportSymbol,
@@ -696,9 +733,17 @@ ${code}
696
733
  // namespace export symbol.
697
734
  let assetId = resolvedAsset.meta.id;
698
735
  (0, _assert().default)(typeof assetId === 'string');
699
- let obj = isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap) ?
700
- // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
701
- `(parcelRequire(${JSON.stringify(publicId)}))` : isWrapped && dep ? `$${publicId}` : ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
736
+ let obj;
737
+ if (isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap)) {
738
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
739
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
740
+ } else if (isWrapped && dep) {
741
+ obj = `$${publicId}`;
742
+ } else {
743
+ var _resolvedAsset$symbol;
744
+ obj = ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
745
+ obj = (replacements === null || replacements === void 0 ? void 0 : replacements.get(obj)) || obj;
746
+ }
702
747
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
703
748
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
704
749
  if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset.id)) {
@@ -722,7 +767,7 @@ ${code}
722
767
  } else if (!symbol) {
723
768
  (0, _assert().default)(false, 'Asset was skipped or not found.');
724
769
  } else {
725
- return symbol;
770
+ return (replacements === null || replacements === void 0 ? void 0 : replacements.get(symbol)) || symbol;
726
771
  }
727
772
  }
728
773
  getHoistedParcelRequires(parentAsset, dep, resolved) {
@@ -749,7 +794,7 @@ ${code}
749
794
  }
750
795
  return [res, lineCount];
751
796
  }
752
- buildAssetPrelude(asset, deps) {
797
+ buildAssetPrelude(asset, deps, replacements) {
753
798
  let prepend = '';
754
799
  let prependLineCount = 0;
755
800
  let append = '';
@@ -767,13 +812,15 @@ ${code}
767
812
  // The one case where this isn't true is in ESM library entries, where the only
768
813
  // dependency on * is the entry dependency. In this case, we will use ESM exports
769
814
  // instead of the namespace object.
770
- usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
815
+ usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && this.bundle.hasDependency(dep) && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) ||
771
816
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
772
817
  // we fallback on the namespace object.
773
818
  asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) ||
774
819
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
775
820
  // include the namespace object for the default export.
776
- this.exportedSymbols.has(`$${assetId}$exports`);
821
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
822
+ // CommonJS library bundle entries always need a namespace.
823
+ this.bundle.env.isLibrary && this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry();
777
824
 
778
825
  // If the asset doesn't have static exports, should wrap, the namespace is used,
779
826
  // or we need default interop, then we need to synthesize a namespace object for
@@ -824,7 +871,7 @@ ${code}
824
871
  if (isWrapped || resolved.meta.staticExports === false || (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(resolved)).has('*') ||
825
872
  // an empty asset
826
873
  !resolved.meta.hasCJSExports && resolved.symbols.hasExportSymbol('*')) {
827
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
874
+ let obj = this.getSymbolResolution(asset, resolved, '*', dep, replacements);
828
875
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
829
876
  this.usedHelpers.add('$parcel$exportWildcard');
830
877
  } else {
@@ -834,7 +881,7 @@ ${code}
834
881
  symbol === '__esModule') {
835
882
  continue;
836
883
  }
837
- let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol);
884
+ let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol, undefined, replacements);
838
885
  let get = this.buildFunctionExpression([], resolvedSymbol);
839
886
  let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolvedSymbol} = v`) : '';
840
887
  prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(symbol)}, ${get}${set});\n`;
@@ -873,7 +920,7 @@ ${code}
873
920
  // additional assignments after each mutation of the original binding.
874
921
  prepend += `\n${usedExports.map(exp => {
875
922
  var _asset$symbols$get2;
876
- let resolved = this.getSymbolResolution(asset, asset, exp);
923
+ let resolved = this.getSymbolResolution(asset, asset, exp, undefined, replacements);
877
924
  let get = this.buildFunctionExpression([], resolved);
878
925
  let isEsmExport = !!((_asset$symbols$get2 = asset.symbols.get(exp)) !== null && _asset$symbols$get2 !== void 0 && (_asset$symbols$get2 = _asset$symbols$get2.meta) !== null && _asset$symbols$get2 !== void 0 && _asset$symbols$get2.isEsm);
879
926
  let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
package/lib/utils.js CHANGED
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getSpecifier = getSpecifier;
7
+ exports.isValidIdentifier = isValidIdentifier;
8
+ exports.makeValidIdentifier = makeValidIdentifier;
7
9
  exports.replaceScriptDependencies = replaceScriptDependencies;
8
10
  function _nullthrows() {
9
11
  const data = _interopRequireDefault(require("nullthrows"));
@@ -48,4 +50,19 @@ function getSpecifier(dep) {
48
50
  return dep.meta.placeholder;
49
51
  }
50
52
  return dep.specifier;
53
+ }
54
+
55
+ // https://262.ecma-international.org/6.0/#sec-names-and-keywords
56
+ const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
57
+ const ID_START_RE = /^[$_\p{ID_Start}]/u;
58
+ const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
59
+ function isValidIdentifier(id) {
60
+ return IDENTIFIER_RE.test(id);
61
+ }
62
+ function makeValidIdentifier(name) {
63
+ name = name.replace(NON_ID_CONTINUE_RE, '');
64
+ if (!ID_START_RE.test(name)) {
65
+ name = '_' + name;
66
+ }
67
+ return name;
51
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/packager-js",
3
- "version": "2.0.0-dev.1518+b5ddb4610",
3
+ "version": "2.0.0-dev.1528+70889ca07",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -17,17 +17,17 @@
17
17
  "source": "src/index.js",
18
18
  "engines": {
19
19
  "node": ">= 12.0.0",
20
- "parcel": "^2.0.0-dev.1516+b5ddb4610"
20
+ "parcel": "^2.0.0-dev.1526+70889ca07"
21
21
  },
22
22
  "dependencies": {
23
- "@parcel/diagnostic": "2.0.0-dev.1518+b5ddb4610",
24
- "@parcel/plugin": "2.0.0-dev.1518+b5ddb4610",
25
- "@parcel/rust": "2.12.1-dev.3141+b5ddb4610",
23
+ "@parcel/diagnostic": "2.0.0-dev.1528+70889ca07",
24
+ "@parcel/plugin": "2.0.0-dev.1528+70889ca07",
25
+ "@parcel/rust": "2.12.1-dev.3151+70889ca07",
26
26
  "@parcel/source-map": "^2.1.1",
27
- "@parcel/types": "2.0.0-dev.1518+b5ddb4610",
28
- "@parcel/utils": "2.0.0-dev.1518+b5ddb4610",
27
+ "@parcel/types": "2.0.0-dev.1528+70889ca07",
28
+ "@parcel/utils": "2.0.0-dev.1528+70889ca07",
29
29
  "globals": "^13.2.0",
30
30
  "nullthrows": "^1.1.1"
31
31
  },
32
- "gitHead": "b5ddb46104f3bf167a7d1735a2dfd1b6bf403614"
32
+ "gitHead": "70889ca07dccb95e21e4c6a2844d632e3723faf4"
33
33
  }
@@ -3,6 +3,7 @@ import type {
3
3
  ScopeHoistingPackager,
4
4
  OutputFormat,
5
5
  } from './ScopeHoistingPackager';
6
+ import {isValidIdentifier} from './utils';
6
7
 
7
8
  export class ESMOutputFormat implements OutputFormat {
8
9
  packager: ScopeHoistingPackager;
@@ -25,6 +26,9 @@ export class ESMOutputFormat implements OutputFormat {
25
26
  namespaceSpecifier = `* as ${symbol}`;
26
27
  } else {
27
28
  let specifier = imported;
29
+ if (!isValidIdentifier(specifier)) {
30
+ specifier = JSON.stringify(specifier);
31
+ }
28
32
  if (symbol !== imported) {
29
33
  specifier += ` as ${symbol}`;
30
34
  }
@@ -93,7 +97,10 @@ export class ESMOutputFormat implements OutputFormat {
93
97
 
94
98
  for (let as of exportAs) {
95
99
  let specifier = local;
96
- if (exportAs !== local) {
100
+ if (as !== local) {
101
+ if (!isValidIdentifier(as)) {
102
+ as = JSON.stringify(as);
103
+ }
97
104
  specifier += ` as ${as}`;
98
105
  }
99
106
 
@@ -28,12 +28,12 @@ import {ESMOutputFormat} from './ESMOutputFormat';
28
28
  import {CJSOutputFormat} from './CJSOutputFormat';
29
29
  import {GlobalOutputFormat} from './GlobalOutputFormat';
30
30
  import {prelude, helpers, bundleQueuePrelude, fnExpr} from './helpers';
31
- import {replaceScriptDependencies, getSpecifier} from './utils';
32
-
33
- // https://262.ecma-international.org/6.0/#sec-names-and-keywords
34
- const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
35
- const ID_START_RE = /^[$_\p{ID_Start}]/u;
36
- const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
31
+ import {
32
+ replaceScriptDependencies,
33
+ getSpecifier,
34
+ isValidIdentifier,
35
+ makeValidIdentifier,
36
+ } from './utils';
37
37
 
38
38
  // General regex used to replace imports with the resolved code, references with resolutions,
39
39
  // and count the number of newlines in the file for source maps.
@@ -134,25 +134,10 @@ export class ScopeHoistingPackager {
134
134
  this.bundle.env.isLibrary ||
135
135
  this.bundle.env.outputFormat === 'commonjs'
136
136
  ) {
137
- for (let b of this.bundleGraph.getReferencedBundles(this.bundle)) {
138
- let entry = b.getMainEntry();
139
- let symbols = new Map();
140
- if (entry && !this.isAsyncBundle && entry.type === 'js') {
141
- this.externalAssets.add(entry);
142
-
143
- let usedSymbols = this.bundleGraph.getUsedSymbols(entry) || new Set();
144
- for (let s of usedSymbols) {
145
- // If the referenced bundle is ESM, and we are importing '*', use 'default' instead.
146
- // This matches the logic below in buildExportedSymbols.
147
- let imported = s;
148
- if (imported === '*' && b.env.outputFormat === 'esmodule') {
149
- imported = 'default';
150
- }
151
- symbols.set(imported, this.getSymbolResolution(entry, entry, s));
152
- }
153
- }
154
-
155
- this.externals.set(relativeBundlePath(this.bundle, b), symbols);
137
+ for (let b of this.bundleGraph.getReferencedBundles(this.bundle, {
138
+ recursive: false,
139
+ })) {
140
+ this.externals.set(relativeBundlePath(this.bundle, b), new Map());
156
141
  }
157
142
  }
158
143
 
@@ -324,7 +309,6 @@ export class ScopeHoistingPackager {
324
309
 
325
310
  if (
326
311
  asset.meta.shouldWrap ||
327
- this.isAsyncBundle ||
328
312
  this.bundle.env.sourceType === 'script' ||
329
313
  this.bundleGraph.isAssetReferenced(this.bundle, asset) ||
330
314
  this.bundleGraph
@@ -361,7 +345,6 @@ export class ScopeHoistingPackager {
361
345
 
362
346
  buildExportedSymbols() {
363
347
  if (
364
- this.isAsyncBundle ||
365
348
  !this.bundle.env.isLibrary ||
366
349
  this.bundle.env.outputFormat !== 'esmodule'
367
350
  ) {
@@ -418,8 +401,8 @@ export class ScopeHoistingPackager {
418
401
  }
419
402
 
420
403
  getTopLevelName(name: string): string {
421
- name = name.replace(NON_ID_CONTINUE_RE, '');
422
- if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
404
+ name = makeValidIdentifier(name);
405
+ if (this.globalNames.has(name)) {
423
406
  name = '_' + name;
424
407
  }
425
408
 
@@ -434,7 +417,7 @@ export class ScopeHoistingPackager {
434
417
  }
435
418
 
436
419
  getPropertyAccess(obj: string, property: string): string {
437
- if (IDENTIFIER_RE.test(property)) {
420
+ if (isValidIdentifier(property)) {
438
421
  return `${obj}.${property}`;
439
422
  }
440
423
 
@@ -511,7 +494,11 @@ export class ScopeHoistingPackager {
511
494
  }
512
495
 
513
496
  let [depMap, replacements] = this.buildReplacements(asset, deps);
514
- let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
497
+ let [prepend, prependLines, append] = this.buildAssetPrelude(
498
+ asset,
499
+ deps,
500
+ replacements,
501
+ );
515
502
  if (prependLines > 0) {
516
503
  sourceMap?.offsetLines(1, prependLines);
517
504
  code = prepend + code;
@@ -703,6 +690,24 @@ ${code}
703
690
  continue;
704
691
  }
705
692
 
693
+ // Handle imports from other bundles in libraries.
694
+ if (this.bundle.env.isLibrary && !this.bundle.hasAsset(resolved)) {
695
+ let referencedBundle = this.bundleGraph.getReferencedBundle(
696
+ dep,
697
+ this.bundle,
698
+ );
699
+ if (
700
+ referencedBundle &&
701
+ referencedBundle.getMainEntry() === resolved &&
702
+ referencedBundle.type === 'js' &&
703
+ !this.bundleGraph.isAssetReferenced(referencedBundle, resolved)
704
+ ) {
705
+ this.addExternal(dep, replacements, referencedBundle);
706
+ this.externalAssets.add(resolved);
707
+ continue;
708
+ }
709
+ }
710
+
706
711
  for (let [imported, {local}] of dep.symbols) {
707
712
  if (local === '*') {
708
713
  continue;
@@ -748,7 +753,11 @@ ${code}
748
753
  return [depMap, replacements];
749
754
  }
750
755
 
751
- addExternal(dep: Dependency, replacements?: Map<string, string>) {
756
+ addExternal(
757
+ dep: Dependency,
758
+ replacements?: Map<string, string>,
759
+ referencedBundle?: NamedBundle,
760
+ ) {
752
761
  if (this.bundle.env.outputFormat === 'global') {
753
762
  throw new ThrowableDiagnostic({
754
763
  diagnostic: {
@@ -766,11 +775,16 @@ ${code}
766
775
  });
767
776
  }
768
777
 
778
+ let specifier = dep.specifier;
779
+ if (referencedBundle) {
780
+ specifier = relativeBundlePath(this.bundle, referencedBundle);
781
+ }
782
+
769
783
  // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
770
- let external = this.externals.get(dep.specifier);
784
+ let external = this.externals.get(specifier);
771
785
  if (!external) {
772
786
  external = new Map();
773
- this.externals.set(dep.specifier, external);
787
+ this.externals.set(specifier, external);
774
788
  }
775
789
 
776
790
  for (let [imported, {local}] of dep.symbols) {
@@ -786,9 +800,16 @@ ${code}
786
800
  if (this.bundle.env.outputFormat === 'commonjs') {
787
801
  renamed = external.get('*');
788
802
  if (!renamed) {
789
- renamed = this.getTopLevelName(
790
- `$${this.bundle.publicId}$${dep.specifier}`,
791
- );
803
+ if (referencedBundle) {
804
+ let entry = nullthrows(referencedBundle.getMainEntry());
805
+ renamed =
806
+ entry.symbols.get('*')?.local ??
807
+ `$${String(entry.meta.id)}$exports`;
808
+ } else {
809
+ renamed = this.getTopLevelName(
810
+ `$${this.bundle.publicId}$${specifier}`,
811
+ );
812
+ }
792
813
 
793
814
  external.set('*', renamed);
794
815
  }
@@ -807,24 +828,67 @@ ${code}
807
828
  replacements.set(local, replacement);
808
829
  }
809
830
  } else {
831
+ let property;
832
+ if (referencedBundle) {
833
+ let entry = nullthrows(referencedBundle.getMainEntry());
834
+ if (entry.symbols.hasExportSymbol('*')) {
835
+ // If importing * and the referenced module has a * export (e.g. CJS), use default instead.
836
+ // This mirrors the logic in buildExportedSymbols.
837
+ property = imported;
838
+ imported =
839
+ referencedBundle?.env.outputFormat === 'esmodule'
840
+ ? 'default'
841
+ : '*';
842
+ } else {
843
+ if (imported === '*') {
844
+ let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
845
+ if (local === '*') {
846
+ // Re-export all symbols.
847
+ for (let exported of exportedSymbols) {
848
+ if (exported.symbol) {
849
+ external.set(exported.exportSymbol, exported.symbol);
850
+ }
851
+ }
852
+ continue;
853
+ }
854
+ }
855
+ renamed = this.bundleGraph.getSymbolResolution(
856
+ entry,
857
+ imported,
858
+ this.bundle,
859
+ ).symbol;
860
+ }
861
+ }
862
+
810
863
  // Rename the specifier so that multiple local imports of the same imported specifier
811
864
  // are deduplicated. We have to prefix the imported name with the bundle id so that
812
865
  // local variables do not shadow it.
813
- if (this.exportedSymbols.has(local)) {
814
- renamed = local;
815
- } else if (imported === 'default' || imported === '*') {
816
- renamed = this.getTopLevelName(
817
- `$${this.bundle.publicId}$${dep.specifier}`,
818
- );
819
- } else {
820
- renamed = this.getTopLevelName(
821
- `$${this.bundle.publicId}$${imported}`,
822
- );
866
+ if (!renamed) {
867
+ if (this.exportedSymbols.has(local)) {
868
+ renamed = local;
869
+ } else if (imported === 'default' || imported === '*') {
870
+ renamed = this.getTopLevelName(
871
+ `$${this.bundle.publicId}$${specifier}`,
872
+ );
873
+ } else {
874
+ renamed = this.getTopLevelName(
875
+ `$${this.bundle.publicId}$${imported}`,
876
+ );
877
+ }
823
878
  }
824
879
 
825
880
  external.set(imported, renamed);
826
881
  if (local !== '*' && replacements) {
827
- replacements.set(local, renamed);
882
+ let replacement = renamed;
883
+ if (property === '*') {
884
+ replacement = renamed;
885
+ } else if (property === 'default') {
886
+ replacement = `($parcel$interopDefault(${renamed}))`;
887
+ this.usedHelpers.add('$parcel$interopDefault');
888
+ } else if (property) {
889
+ replacement = this.getPropertyAccess(renamed, property);
890
+ }
891
+ replacements.set(local, replacement);
828
892
  }
829
893
  }
830
894
  }
@@ -849,6 +913,7 @@ ${code}
849
913
  resolved: Asset,
850
914
  imported: string,
851
915
  dep?: Dependency,
916
+ replacements?: Map<string, string>,
852
917
  ): string {
853
918
  let {
854
919
  asset: resolvedAsset,
@@ -922,13 +987,16 @@ ${code}
922
987
  // namespace export symbol.
923
988
  let assetId = resolvedAsset.meta.id;
924
989
  invariant(typeof assetId === 'string');
925
- let obj =
926
- isWrapped && (!dep || dep?.meta.shouldWrap)
927
- ? // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
928
- `(parcelRequire(${JSON.stringify(publicId)}))`
929
- : isWrapped && dep
930
- ? `$${publicId}`
931
- : resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
990
+ let obj;
991
+ if (isWrapped && (!dep || dep?.meta.shouldWrap)) {
992
+ // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
993
+ obj = `(parcelRequire(${JSON.stringify(publicId)}))`;
994
+ } else if (isWrapped && dep) {
995
+ obj = `$${publicId}`;
996
+ } else {
997
+ obj = resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
998
+ obj = replacements?.get(obj) || obj;
999
+ }
932
1000
 
933
1001
  if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
934
1002
  // Resolve to the namespace object if requested or this is a CJS default interop reqiure.
@@ -964,7 +1032,7 @@ ${code}
964
1032
  } else if (!symbol) {
965
1033
  invariant(false, 'Asset was skipped or not found.');
966
1034
  } else {
967
- return symbol;
1035
+ return replacements?.get(symbol) || symbol;
968
1036
  }
969
1037
  }
970
1038
 
@@ -1011,6 +1079,7 @@ ${code}
1011
1079
  buildAssetPrelude(
1012
1080
  asset: Asset,
1013
1081
  deps: Array<Dependency>,
1082
+ replacements: Map<string, string>,
1014
1083
  ): [string, number, string] {
1015
1084
  let prepend = '';
1016
1085
  let prependLineCount = 0;
@@ -1043,6 +1112,7 @@ ${code}
1043
1112
  .some(
1044
1113
  dep =>
1045
1114
  !dep.isEntry &&
1115
+ this.bundle.hasDependency(dep) &&
1046
1116
  nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
1047
1117
  ))) ||
1048
1118
  // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
@@ -1051,7 +1121,11 @@ ${code}
1051
1121
  [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s))) ||
1052
1122
  // If the exports has this asset's namespace (e.g. ESM output from CJS input),
1053
1123
  // include the namespace object for the default export.
1054
- this.exportedSymbols.has(`$${assetId}$exports`);
1124
+ this.exportedSymbols.has(`$${assetId}$exports`) ||
1125
+ // CommonJS library bundle entries always need a namespace.
1126
+ (this.bundle.env.isLibrary &&
1127
+ this.bundle.env.outputFormat === 'commonjs' &&
1128
+ asset === this.bundle.getMainEntry());
1055
1129
 
1056
1130
  // If the asset doesn't have static exports, should wrap, the namespace is used,
1057
1131
  // or we need default interop, then we need to synthesize a namespace object for
@@ -1118,7 +1192,13 @@ ${code}
1118
1192
  (!resolved.meta.hasCJSExports &&
1119
1193
  resolved.symbols.hasExportSymbol('*'))
1120
1194
  ) {
1121
- let obj = this.getSymbolResolution(asset, resolved, '*', dep);
1195
+ let obj = this.getSymbolResolution(
1196
+ asset,
1197
+ resolved,
1198
+ '*',
1199
+ dep,
1200
+ replacements,
1201
+ );
1122
1202
  append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
1123
1203
  this.usedHelpers.add('$parcel$exportWildcard');
1124
1204
  } else {
@@ -1136,6 +1216,8 @@ ${code}
1136
1216
  asset,
1137
1217
  resolved,
1138
1218
  symbol,
1219
+ undefined,
1220
+ replacements,
1139
1221
  );
1140
1222
  let get = this.buildFunctionExpression([], resolvedSymbol);
1141
1223
  let set = asset.meta.hasCJSExports
@@ -1182,7 +1264,13 @@ ${code}
1182
1264
  // additional assignments after each mutation of the original binding.
1183
1265
  prepend += `\n${usedExports
1184
1266
  .map(exp => {
1185
- let resolved = this.getSymbolResolution(asset, asset, exp);
1267
+ let resolved = this.getSymbolResolution(
1268
+ asset,
1269
+ asset,
1270
+ exp,
1271
+ undefined,
1272
+ replacements,
1273
+ );
1186
1274
  let get = this.buildFunctionExpression([], resolved);
1187
1275
  let isEsmExport = !!asset.symbols.get(exp)?.meta?.isEsm;
1188
1276
  let set =
package/src/utils.js CHANGED
@@ -55,3 +55,20 @@ export function getSpecifier(dep: Dependency): string {
55
55
 
56
56
  return dep.specifier;
57
57
  }
58
+
59
+ // https://262.ecma-international.org/6.0/#sec-names-and-keywords
60
+ const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
61
+ const ID_START_RE = /^[$_\p{ID_Start}]/u;
62
+ const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu;
63
+
64
+ export function isValidIdentifier(id: string): boolean {
65
+ return IDENTIFIER_RE.test(id);
66
+ }
67
+
68
+ export function makeValidIdentifier(name: string): string {
69
+ name = name.replace(NON_ID_CONTINUE_RE, '');
70
+ if (!ID_START_RE.test(name)) {
71
+ name = '_' + name;
72
+ }
73
+ return name;
74
+ }