Son CV dans un terminal web en Javascript!
https://terminal-cv.gregandev.fr
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
985 lines
38 KiB
985 lines
38 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.ScopeHoistingPackager = void 0;
|
|
|
|
function _utils() {
|
|
const data = require("@parcel/utils");
|
|
|
|
_utils = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _sourceMap2() {
|
|
const data = _interopRequireDefault(require("@parcel/source-map"));
|
|
|
|
_sourceMap2 = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _nullthrows() {
|
|
const data = _interopRequireDefault(require("nullthrows"));
|
|
|
|
_nullthrows = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _assert() {
|
|
const data = _interopRequireDefault(require("assert"));
|
|
|
|
_assert = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _diagnostic() {
|
|
const data = _interopRequireDefault(require("@parcel/diagnostic"));
|
|
|
|
_diagnostic = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _globals() {
|
|
const data = _interopRequireDefault(require("globals"));
|
|
|
|
_globals = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
var _ESMOutputFormat = require("./ESMOutputFormat");
|
|
|
|
var _CJSOutputFormat = require("./CJSOutputFormat");
|
|
|
|
var _GlobalOutputFormat = require("./GlobalOutputFormat");
|
|
|
|
var _helpers = require("./helpers");
|
|
|
|
var _utils2 = require("./utils");
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
// https://262.ecma-international.org/6.0/#sec-names-and-keywords
|
|
const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u;
|
|
const ID_START_RE = /^[$_\p{ID_Start}]/u;
|
|
const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu; // General regex used to replace imports with the resolved code, references with resolutions,
|
|
// and count the number of newlines in the file for source maps.
|
|
|
|
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;
|
|
const BUILTINS = Object.keys(_globals().default.builtin);
|
|
const GLOBALS_BY_CONTEXT = {
|
|
browser: new Set([...BUILTINS, ...Object.keys(_globals().default.browser)]),
|
|
'web-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.worker)]),
|
|
'service-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.serviceworker)]),
|
|
worklet: new Set([...BUILTINS]),
|
|
node: new Set([...BUILTINS, ...Object.keys(_globals().default.node)]),
|
|
'electron-main': new Set([...BUILTINS, ...Object.keys(_globals().default.node)]),
|
|
'electron-renderer': new Set([...BUILTINS, ...Object.keys(_globals().default.node), ...Object.keys(_globals().default.browser)])
|
|
};
|
|
const OUTPUT_FORMATS = {
|
|
esmodule: _ESMOutputFormat.ESMOutputFormat,
|
|
commonjs: _CJSOutputFormat.CJSOutputFormat,
|
|
global: _GlobalOutputFormat.GlobalOutputFormat
|
|
};
|
|
|
|
class ScopeHoistingPackager {
|
|
exportedSymbols = new Map();
|
|
externals = new Map();
|
|
topLevelNames = new Map();
|
|
seenAssets = new Set();
|
|
wrappedAssets = new Set();
|
|
hoistedRequires = new Map();
|
|
needsPrelude = false;
|
|
usedHelpers = new Set();
|
|
|
|
constructor(options, bundleGraph, bundle, parcelRequireName) {
|
|
this.options = options;
|
|
this.bundleGraph = bundleGraph;
|
|
this.bundle = bundle;
|
|
this.parcelRequireName = parcelRequireName;
|
|
let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
|
|
this.outputFormat = new OutputFormat(this);
|
|
this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated';
|
|
this.globalNames = GLOBALS_BY_CONTEXT[bundle.env.context];
|
|
}
|
|
|
|
async package() {
|
|
var _sourceMap;
|
|
|
|
await this.loadAssets();
|
|
this.buildExportedSymbols(); // If building a library, the target is actually another bundler rather
|
|
// than the final output that could be loaded in a browser. So, loader
|
|
// runtimes are excluded, and instead we add imports into the entry bundle
|
|
// of each bundle group pointing at the sibling bundles. These can be
|
|
// picked up by another bundler later at which point runtimes will be added.
|
|
|
|
if (this.bundle.env.isLibrary || this.bundle.env.outputFormat === 'commonjs') {
|
|
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
|
|
|
for (let b of bundles) {
|
|
this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), new Map());
|
|
}
|
|
} // Add each asset that is directly connected to the bundle. Dependencies will be handled
|
|
// by replacing `import` statements in the code.
|
|
|
|
|
|
let res = '';
|
|
let lineCount = 0;
|
|
let sourceMap = null;
|
|
this.bundle.traverseAssets((asset, _, actions) => {
|
|
if (this.seenAssets.has(asset.id)) {
|
|
actions.skipChildren();
|
|
return;
|
|
}
|
|
|
|
let [content, map, lines] = this.visitAsset(asset);
|
|
|
|
if (sourceMap && map) {
|
|
sourceMap.addSourceMap(map, lineCount);
|
|
} else if (this.bundle.env.sourceMap) {
|
|
sourceMap = map;
|
|
}
|
|
|
|
res += content + '\n';
|
|
lineCount += lines + 1;
|
|
actions.skipChildren();
|
|
});
|
|
let [prelude, preludeLines] = this.buildBundlePrelude();
|
|
res = prelude + res;
|
|
lineCount += preludeLines;
|
|
(_sourceMap = sourceMap) === null || _sourceMap === void 0 ? void 0 : _sourceMap.offsetLines(1, preludeLines);
|
|
let entries = this.bundle.getEntryAssets();
|
|
let mainEntry = this.bundle.getMainEntry();
|
|
|
|
if (this.isAsyncBundle) {
|
|
// In async bundles we don't want the main entry to execute until we require it
|
|
// as there might be dependencies in a sibling bundle that hasn't loaded yet.
|
|
entries = entries.filter(a => {
|
|
var _mainEntry;
|
|
|
|
return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id);
|
|
});
|
|
mainEntry = null;
|
|
} // If any of the entry assets are wrapped, call parcelRequire so they are executed.
|
|
|
|
|
|
for (let entry of entries) {
|
|
if (this.wrappedAssets.has(entry.id) && !this.isScriptEntry(entry)) {
|
|
var _entry$symbols$get;
|
|
|
|
let parcelRequire = `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(entry))});\n`;
|
|
let entryExports = (_entry$symbols$get = entry.symbols.get('*')) === null || _entry$symbols$get === void 0 ? void 0 : _entry$symbols$get.local;
|
|
|
|
if (entryExports && entry === mainEntry && this.exportedSymbols.has(entryExports)) {
|
|
res += `\nvar ${entryExports} = ${parcelRequire}`;
|
|
} else {
|
|
res += `\n${parcelRequire}`;
|
|
}
|
|
|
|
lineCount += 2;
|
|
}
|
|
}
|
|
|
|
let [postlude, postludeLines] = this.outputFormat.buildBundlePostlude();
|
|
res += postlude;
|
|
lineCount += postludeLines; // The entry asset of a script bundle gets hoisted outside the bundle wrapper so that
|
|
// its top-level variables become globals like a real browser script. We need to replace
|
|
// all dependency references for runtimes with a parcelRequire call.
|
|
|
|
if (this.bundle.env.outputFormat === 'global' && this.bundle.env.sourceType === 'script') {
|
|
res += '\n';
|
|
lineCount++;
|
|
let mainEntry = (0, _nullthrows().default)(this.bundle.getMainEntry());
|
|
let {
|
|
code,
|
|
map: mapBuffer
|
|
} = (0, _nullthrows().default)(this.assetOutputs.get(mainEntry.id));
|
|
let map;
|
|
|
|
if (mapBuffer) {
|
|
map = new (_sourceMap2().default)(this.options.projectRoot, mapBuffer);
|
|
}
|
|
|
|
res += (0, _utils2.replaceScriptDependencies)(this.bundleGraph, this.bundle, code, map, this.parcelRequireName);
|
|
|
|
if (sourceMap && map) {
|
|
sourceMap.addSourceMap(map, lineCount);
|
|
}
|
|
}
|
|
|
|
return {
|
|
contents: res,
|
|
map: sourceMap
|
|
};
|
|
}
|
|
|
|
async loadAssets() {
|
|
let queue = new (_utils().PromiseQueue)({
|
|
maxConcurrent: 32
|
|
});
|
|
this.bundle.traverseAssets((asset, shouldWrap) => {
|
|
queue.add(async () => {
|
|
let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]);
|
|
return [asset.id, {
|
|
code,
|
|
map
|
|
}];
|
|
});
|
|
|
|
if (shouldWrap || 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')) {
|
|
this.wrappedAssets.add(asset.id);
|
|
return true;
|
|
}
|
|
});
|
|
this.assetOutputs = new Map(await queue.run());
|
|
}
|
|
|
|
buildExportedSymbols() {
|
|
if (this.isAsyncBundle || !this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') {
|
|
return;
|
|
} // TODO: handle ESM exports of wrapped entry assets...
|
|
|
|
|
|
let entry = this.bundle.getMainEntry();
|
|
|
|
if (entry && !this.wrappedAssets.has(entry.id)) {
|
|
for (let {
|
|
asset,
|
|
exportAs,
|
|
symbol,
|
|
exportSymbol
|
|
} of this.bundleGraph.getExportedSymbols(entry)) {
|
|
if (typeof symbol === 'string') {
|
|
var _this$exportedSymbols, _entry$symbols$get2;
|
|
|
|
let symbols = (_this$exportedSymbols = this.exportedSymbols.get(symbol === '*' ? (0, _nullthrows().default)((_entry$symbols$get2 = entry.symbols.get('*')) === null || _entry$symbols$get2 === void 0 ? void 0 : _entry$symbols$get2.local) : symbol)) === null || _this$exportedSymbols === void 0 ? void 0 : _this$exportedSymbols.exportAs;
|
|
|
|
if (!symbols) {
|
|
symbols = [];
|
|
this.exportedSymbols.set(symbol, {
|
|
asset,
|
|
exportSymbol,
|
|
local: symbol,
|
|
exportAs: symbols
|
|
});
|
|
}
|
|
|
|
if (exportAs === '*') {
|
|
exportAs = 'default';
|
|
}
|
|
|
|
symbols.push(exportAs);
|
|
} else if (symbol === null) {// TODO `meta.exportsIdentifier[exportSymbol]` should be exported
|
|
// let relativePath = relative(options.projectRoot, asset.filePath);
|
|
// throw getThrowableDiagnosticForNode(
|
|
// md`${relativePath} couldn't be statically analyzed when importing '${exportSymbol}'`,
|
|
// entry.filePath,
|
|
// loc,
|
|
// );
|
|
} else if (symbol !== false) {// let relativePath = relative(options.projectRoot, asset.filePath);
|
|
// throw getThrowableDiagnosticForNode(
|
|
// md`${relativePath} does not export '${exportSymbol}'`,
|
|
// entry.filePath,
|
|
// loc,
|
|
// );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
getTopLevelName(name) {
|
|
name = name.replace(NON_ID_CONTINUE_RE, '');
|
|
|
|
if (!ID_START_RE.test(name) || this.globalNames.has(name)) {
|
|
name = '_' + name;
|
|
}
|
|
|
|
let count = this.topLevelNames.get(name);
|
|
|
|
if (count == null) {
|
|
this.topLevelNames.set(name, 1);
|
|
return name;
|
|
}
|
|
|
|
this.topLevelNames.set(name, count + 1);
|
|
return name + count;
|
|
}
|
|
|
|
getPropertyAccess(obj, property) {
|
|
if (IDENTIFIER_RE.test(property)) {
|
|
return `${obj}.${property}`;
|
|
}
|
|
|
|
return `${obj}[${JSON.stringify(property)}]`;
|
|
}
|
|
|
|
visitAsset(asset) {
|
|
(0, _assert().default)(!this.seenAssets.has(asset.id), 'Already visited asset');
|
|
this.seenAssets.add(asset.id);
|
|
let {
|
|
code,
|
|
map
|
|
} = (0, _nullthrows().default)(this.assetOutputs.get(asset.id));
|
|
return this.buildAsset(asset, code, map);
|
|
}
|
|
|
|
buildAsset(asset, code, map) {
|
|
let shouldWrap = this.wrappedAssets.has(asset.id);
|
|
let deps = this.bundleGraph.getDependencies(asset);
|
|
let sourceMap = this.bundle.env.sourceMap && map ? new (_sourceMap2().default)(this.options.projectRoot, map) : null; // If this asset is skipped, just add dependencies and not the asset's content.
|
|
|
|
if (this.shouldSkipAsset(asset)) {
|
|
let depCode = '';
|
|
let lineCount = 0;
|
|
|
|
for (let dep of deps) {
|
|
let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
|
let skipped = this.bundleGraph.isDependencySkipped(dep);
|
|
|
|
if (!resolved || skipped) {
|
|
continue;
|
|
}
|
|
|
|
if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) {
|
|
let [code, map, lines] = this.visitAsset(resolved);
|
|
depCode += code + '\n';
|
|
|
|
if (sourceMap && map) {
|
|
sourceMap.addSourceMap(map, lineCount);
|
|
}
|
|
|
|
lineCount += lines + 1;
|
|
}
|
|
}
|
|
|
|
return [depCode, sourceMap, lineCount];
|
|
} // TODO: maybe a meta prop?
|
|
|
|
|
|
if (code.includes('$parcel$global')) {
|
|
this.usedHelpers.add('$parcel$global');
|
|
}
|
|
|
|
let [depMap, replacements] = this.buildReplacements(asset, deps);
|
|
let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps);
|
|
|
|
if (prependLines > 0) {
|
|
sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.offsetLines(1, prependLines);
|
|
code = prepend + code;
|
|
}
|
|
|
|
code += append;
|
|
let lineCount = 0;
|
|
let depContent = [];
|
|
|
|
if (depMap.size === 0 && replacements.size === 0) {
|
|
// If there are no dependencies or replacements, use a simple function to count the number of lines.
|
|
lineCount = (0, _utils().countLines)(code) - 1;
|
|
} else {
|
|
// Otherwise, use a regular expression to perform replacements.
|
|
// We need to track how many newlines there are for source maps, replace
|
|
// all import statements with dependency code, and perform inline replacements
|
|
// of all imported symbols with their resolved export symbols. This is all done
|
|
// in a single regex so that we only do one pass over the whole code.
|
|
let offset = 0;
|
|
let columnStartIndex = 0;
|
|
code = code.replace(REPLACEMENT_RE, (m, d, i) => {
|
|
var _replacements$get;
|
|
|
|
if (m === '\n') {
|
|
columnStartIndex = i + offset + 1;
|
|
lineCount++;
|
|
return '\n';
|
|
} // If we matched an import, replace with the source code for the dependency.
|
|
|
|
|
|
if (d != null) {
|
|
let dep = depMap.get(d);
|
|
|
|
if (!dep) {
|
|
return m;
|
|
}
|
|
|
|
let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
|
let skipped = this.bundleGraph.isDependencySkipped(dep);
|
|
|
|
if (resolved && !skipped) {
|
|
// Hoist variable declarations for the referenced parcelRequire dependencies
|
|
// after the dependency is declared. This handles the case where the resulting asset
|
|
// is wrapped, but the dependency in this asset is not marked as wrapped. This means
|
|
// that it was imported/required at the top-level, so its side effects should run immediately.
|
|
let [res, lines] = this.getHoistedParcelRequires(asset, dep, resolved);
|
|
let map;
|
|
|
|
if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) {
|
|
// If this asset is wrapped, we need to hoist the code for the dependency
|
|
// outside our parcelRequire.register wrapper. This is safe because all
|
|
// assets referenced by this asset will also be wrapped. Otherwise, inline the
|
|
// asset content where the import statement was.
|
|
if (shouldWrap) {
|
|
depContent.push(this.visitAsset(resolved));
|
|
} else {
|
|
let [depCode, depMap, depLines] = this.visitAsset(resolved);
|
|
res = depCode + '\n' + res;
|
|
lines += 1 + depLines;
|
|
map = depMap;
|
|
}
|
|
} // Push this asset's source mappings down by the number of lines in the dependency
|
|
// plus the number of hoisted parcelRequires. Then insert the source map for the dependency.
|
|
|
|
|
|
if (sourceMap) {
|
|
if (lines > 0) {
|
|
sourceMap.offsetLines(lineCount + 1, lines);
|
|
}
|
|
|
|
if (map) {
|
|
sourceMap.addSourceMap(map, lineCount);
|
|
}
|
|
}
|
|
|
|
lineCount += lines;
|
|
return res;
|
|
}
|
|
|
|
return '';
|
|
} // If it wasn't a dependency, then it was an inline replacement (e.g. $id$import$foo -> $id$export$foo).
|
|
|
|
|
|
let replacement = (_replacements$get = replacements.get(m)) !== null && _replacements$get !== void 0 ? _replacements$get : m;
|
|
|
|
if (sourceMap) {
|
|
// Offset the source map columns for this line if the replacement was a different length.
|
|
// This assumes that the match and replacement both do not contain any newlines.
|
|
let lengthDifference = replacement.length - m.length;
|
|
|
|
if (lengthDifference !== 0) {
|
|
sourceMap.offsetColumns(lineCount + 1, i + offset - columnStartIndex + m.length, lengthDifference);
|
|
offset += lengthDifference;
|
|
}
|
|
}
|
|
|
|
return replacement;
|
|
});
|
|
} // If the asset is wrapped, we need to insert the dependency code outside the parcelRequire.register
|
|
// wrapper. Dependencies must be inserted AFTER the asset is registered so that circular dependencies work.
|
|
|
|
|
|
if (shouldWrap) {
|
|
// Offset by one line for the parcelRequire.register wrapper.
|
|
sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.offsetLines(1, 1);
|
|
lineCount++;
|
|
code = `parcelRequire.register(${JSON.stringify(this.bundleGraph.getAssetPublicId(asset))}, function(module, exports) {
|
|
${code}
|
|
});
|
|
`;
|
|
lineCount += 2;
|
|
|
|
for (let [depCode, map, lines] of depContent) {
|
|
if (!depCode) continue;
|
|
code += depCode + '\n';
|
|
|
|
if (sourceMap && map) {
|
|
sourceMap.addSourceMap(map, lineCount);
|
|
}
|
|
|
|
lineCount += lines + 1;
|
|
}
|
|
|
|
this.needsPrelude = true;
|
|
}
|
|
|
|
return [code, sourceMap, lineCount];
|
|
}
|
|
|
|
buildReplacements(asset, deps) {
|
|
let assetId = asset.meta.id;
|
|
(0, _assert().default)(typeof assetId === 'string'); // Build two maps: one of import specifiers, and one of imported symbols to replace.
|
|
// These will be used to build a regex below.
|
|
|
|
let depMap = new Map();
|
|
let replacements = new Map();
|
|
|
|
for (let dep of deps) {
|
|
depMap.set(`${assetId}:${(0, _utils2.getSpecifier)(dep)}`, dep);
|
|
let asyncResolution = this.bundleGraph.resolveAsyncDependency(dep, this.bundle);
|
|
let resolved = (asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? // Prefer the underlying asset over a runtime to load it. It will
|
|
// be wrapped in Promise.resolve() later.
|
|
asyncResolution.value : this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
|
|
|
if (!resolved && !dep.isOptional && !this.bundleGraph.isDependencySkipped(dep)) {
|
|
let external = this.addExternal(dep);
|
|
|
|
for (let [imported, {
|
|
local
|
|
}] of dep.symbols) {
|
|
// If already imported, just add the already renamed variable to the mapping.
|
|
let renamed = external.get(imported);
|
|
|
|
if (renamed && local !== '*') {
|
|
replacements.set(local, renamed);
|
|
continue;
|
|
} // For CJS output, always use a property lookup so that exports remain live.
|
|
// For ESM output, use named imports which are always live.
|
|
|
|
|
|
if (this.bundle.env.outputFormat === 'commonjs') {
|
|
renamed = external.get('*');
|
|
|
|
if (!renamed) {
|
|
renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
|
|
external.set('*', renamed);
|
|
}
|
|
|
|
if (local !== '*') {
|
|
let replacement;
|
|
|
|
if (imported === '*') {
|
|
replacement = renamed;
|
|
} else if (imported === 'default') {
|
|
replacement = `$parcel$interopDefault(${renamed})`;
|
|
this.usedHelpers.add('$parcel$interopDefault');
|
|
} else {
|
|
replacement = this.getPropertyAccess(renamed, imported);
|
|
}
|
|
|
|
replacements.set(local, replacement);
|
|
}
|
|
} else {
|
|
// Rename the specifier so that multiple local imports of the same imported specifier
|
|
// are deduplicated. We have to prefix the imported name with the bundle id so that
|
|
// local variables do not shadow it.
|
|
if (this.exportedSymbols.has(local)) {
|
|
renamed = local;
|
|
} else if (imported === 'default' || imported === '*') {
|
|
renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`);
|
|
} else {
|
|
renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`);
|
|
}
|
|
|
|
external.set(imported, renamed);
|
|
|
|
if (local !== '*') {
|
|
replacements.set(local, renamed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!resolved) {
|
|
continue;
|
|
}
|
|
|
|
for (let [imported, {
|
|
local
|
|
}] of dep.symbols) {
|
|
if (local === '*') {
|
|
continue;
|
|
}
|
|
|
|
let symbol = this.getSymbolResolution(asset, resolved, imported, dep);
|
|
replacements.set(local, // If this was an internalized async asset, wrap in a Promise.resolve.
|
|
(asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? `Promise.resolve(${symbol})` : symbol);
|
|
} // Async dependencies need a namespace object even if all used symbols were statically analyzed.
|
|
// This is recorded in the promiseSymbol meta property set by the transformer rather than in
|
|
// symbols so that we don't mark all symbols as used.
|
|
|
|
|
|
if (dep.priority === 'lazy' && dep.meta.promiseSymbol) {
|
|
let promiseSymbol = dep.meta.promiseSymbol;
|
|
(0, _assert().default)(typeof promiseSymbol === 'string');
|
|
let symbol = this.getSymbolResolution(asset, resolved, '*', dep);
|
|
replacements.set(promiseSymbol, (asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? `Promise.resolve(${symbol})` : symbol);
|
|
}
|
|
} // If this asset is wrapped, we need to replace the exports namespace with `module.exports`,
|
|
// which will be provided to us by the wrapper.
|
|
|
|
|
|
if (this.wrappedAssets.has(asset.id) || this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry()) {
|
|
var _asset$symbols$get;
|
|
|
|
let exportsName = ((_asset$symbols$get = asset.symbols.get('*')) === null || _asset$symbols$get === void 0 ? void 0 : _asset$symbols$get.local) || `$${assetId}$exports`;
|
|
replacements.set(exportsName, 'module.exports');
|
|
}
|
|
|
|
return [depMap, replacements];
|
|
}
|
|
|
|
addExternal(dep) {
|
|
if (this.bundle.env.outputFormat === 'global') {
|
|
throw new (_diagnostic().default)({
|
|
diagnostic: {
|
|
message: 'External modules are not supported when building for browser',
|
|
codeFrames: [{
|
|
filePath: (0, _nullthrows().default)(dep.sourcePath),
|
|
codeHighlights: dep.loc ? [{
|
|
start: dep.loc.start,
|
|
end: dep.loc.end
|
|
}] : []
|
|
}]
|
|
}
|
|
});
|
|
} // Map of DependencySpecifier -> Map<ExportedSymbol, Identifier>>
|
|
|
|
|
|
let external = this.externals.get(dep.specifier);
|
|
|
|
if (!external) {
|
|
external = new Map();
|
|
this.externals.set(dep.specifier, external);
|
|
}
|
|
|
|
return external;
|
|
}
|
|
|
|
getSymbolResolution(parentAsset, resolved, imported, dep) {
|
|
var _resolvedAsset$symbol;
|
|
|
|
let {
|
|
asset: resolvedAsset,
|
|
exportSymbol,
|
|
symbol
|
|
} = this.bundleGraph.getSymbolResolution(resolved, imported, this.bundle);
|
|
|
|
if (resolvedAsset.type !== 'js') {
|
|
// Graceful fallback for non-js imports
|
|
return '{}';
|
|
}
|
|
|
|
let isWrapped = !this.bundle.hasAsset(resolvedAsset) || this.wrappedAssets.has(resolvedAsset.id) && resolvedAsset !== parentAsset;
|
|
let staticExports = resolvedAsset.meta.staticExports !== false;
|
|
let publicId = this.bundleGraph.getAssetPublicId(resolvedAsset); // If the rsolved asset is wrapped, but imported at the top-level by this asset,
|
|
// then we hoist parcelRequire calls to the top of this asset so side effects run immediately.
|
|
|
|
if (isWrapped && dep && !(dep !== null && dep !== void 0 && dep.meta.shouldWrap) && symbol !== false) {
|
|
let hoisted = this.hoistedRequires.get(dep.id);
|
|
|
|
if (!hoisted) {
|
|
hoisted = new Map();
|
|
this.hoistedRequires.set(dep.id, hoisted);
|
|
}
|
|
|
|
hoisted.set(resolvedAsset.id, `var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`);
|
|
}
|
|
|
|
if (isWrapped) {
|
|
this.needsPrelude = true;
|
|
} // If this is an ESM default import of a CJS module with a `default` symbol,
|
|
// and no __esModule flag, we need to resolve to the namespace instead.
|
|
|
|
|
|
let isDefaultInterop = exportSymbol === 'default' && staticExports && !isWrapped && ((dep === null || dep === void 0 ? void 0 : dep.meta.kind) === 'Import' || (dep === null || dep === void 0 ? void 0 : dep.meta.kind) === 'Export') && resolvedAsset.symbols.hasExportSymbol('*') && resolvedAsset.symbols.hasExportSymbol('default') && !resolvedAsset.symbols.hasExportSymbol('__esModule'); // Find the namespace object for the resolved module. If wrapped and this
|
|
// is an inline require (not top-level), use a parcelRequire call, otherwise
|
|
// the hoisted variable declared above. Otherwise, if not wrapped, use the
|
|
// namespace export symbol.
|
|
|
|
let assetId = resolvedAsset.meta.id;
|
|
(0, _assert().default)(typeof assetId === 'string');
|
|
let obj = isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap) ? // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`.
|
|
`(parcelRequire(${JSON.stringify(publicId)}))` : isWrapped && dep ? `$${publicId}` : ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`;
|
|
|
|
if (imported === '*' || exportSymbol === '*' || isDefaultInterop) {
|
|
// Resolve to the namespace object if requested or this is a CJS default interop reqiure.
|
|
return obj;
|
|
} else if ((!staticExports || isWrapped || !symbol) && resolvedAsset !== parentAsset) {
|
|
// If the resolved asset is wrapped or has non-static exports,
|
|
// we need to use a member access off the namespace object rather
|
|
// than a direct reference. If importing default from a CJS module,
|
|
// use a helper to check the __esModule flag at runtime.
|
|
let kind = dep === null || dep === void 0 ? void 0 : dep.meta.kind;
|
|
|
|
if ((!dep || kind === 'Import' || kind === 'Export') && exportSymbol === 'default' && resolvedAsset.symbols.hasExportSymbol('*') && this.needsDefaultInterop(resolvedAsset)) {
|
|
this.usedHelpers.add('$parcel$interopDefault');
|
|
return `(/*@__PURE__*/$parcel$interopDefault(${obj}))`;
|
|
} else {
|
|
return this.getPropertyAccess(obj, exportSymbol);
|
|
}
|
|
} else if (!symbol) {
|
|
(0, _assert().default)(false, 'Asset was skipped or not found.');
|
|
} else {
|
|
return symbol;
|
|
}
|
|
}
|
|
|
|
getHoistedParcelRequires(parentAsset, dep, resolved) {
|
|
if (resolved.type !== 'js') {
|
|
return ['', 0];
|
|
}
|
|
|
|
let hoisted = this.hoistedRequires.get(dep.id);
|
|
let res = '';
|
|
let lineCount = 0;
|
|
let isWrapped = !this.bundle.hasAsset(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset; // If the resolved asset is wrapped and is imported in the top-level by this asset,
|
|
// we need to run side effects when this asset runs. If the resolved asset is not
|
|
// the first one in the hoisted requires, we need to insert a parcelRequire here
|
|
// so it runs first.
|
|
|
|
if (isWrapped && !dep.meta.shouldWrap && (!hoisted || hoisted.keys().next().value !== resolved.id) && !this.bundleGraph.isDependencySkipped(dep) && !this.shouldSkipAsset(resolved)) {
|
|
this.needsPrelude = true;
|
|
res += `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(resolved))});`;
|
|
}
|
|
|
|
if (hoisted) {
|
|
this.needsPrelude = true;
|
|
res += '\n' + [...hoisted.values()].join('\n');
|
|
lineCount += hoisted.size;
|
|
}
|
|
|
|
return [res, lineCount];
|
|
}
|
|
|
|
buildAssetPrelude(asset, deps) {
|
|
let prepend = '';
|
|
let prependLineCount = 0;
|
|
let append = '';
|
|
let shouldWrap = this.wrappedAssets.has(asset.id);
|
|
let usedSymbols = (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset));
|
|
let assetId = asset.meta.id;
|
|
(0, _assert().default)(typeof assetId === 'string'); // If the asset has a namespace export symbol, it is CommonJS.
|
|
// If there's no __esModule flag, and default is a used symbol, we need
|
|
// to insert an interop helper.
|
|
|
|
let defaultInterop = asset.symbols.hasExportSymbol('*') && usedSymbols.has('default') && !asset.symbols.hasExportSymbol('__esModule');
|
|
let usedNamespace = // If the asset has * in its used symbols, we might need the exports namespace.
|
|
// The one case where this isn't true is in ESM library entries, where the only
|
|
// dependency on * is the entry dependency. In this case, we will use ESM exports
|
|
// instead of the namespace object.
|
|
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('*'))) || // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
|
|
// we fallback on the namespace object.
|
|
asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) || // If the exports has this asset's namespace (e.g. ESM output from CJS input),
|
|
// include the namespace object for the default export.
|
|
this.exportedSymbols.has(`$${assetId}$exports`); // If the asset doesn't have static exports, should wrap, the namespace is used,
|
|
// or we need default interop, then we need to synthesize a namespace object for
|
|
// this asset.
|
|
|
|
if (asset.meta.staticExports === false || shouldWrap || usedNamespace || defaultInterop) {
|
|
// Insert a declaration for the exports namespace object. If the asset is wrapped
|
|
// we don't need to do this, because we'll use the `module.exports` object provided
|
|
// by the wrapper instead. This is also true of CommonJS entry assets, which will use
|
|
// the `module.exports` object provided by CJS.
|
|
if (!shouldWrap && (this.bundle.env.outputFormat !== 'commonjs' || asset !== this.bundle.getMainEntry())) {
|
|
prepend += `var $${assetId}$exports = {};\n`;
|
|
prependLineCount++;
|
|
} // Insert the __esModule interop flag for this module if it has a `default` export
|
|
// and the namespace symbol is used.
|
|
// TODO: only if required by CJS?
|
|
|
|
|
|
if (asset.symbols.hasExportSymbol('default') && usedSymbols.has('*')) {
|
|
prepend += `\n$parcel$defineInteropFlag($${assetId}$exports);\n`;
|
|
prependLineCount += 2;
|
|
this.usedHelpers.add('$parcel$defineInteropFlag');
|
|
} // Find the used exports of this module. This is based on the used symbols of
|
|
// incoming dependencies rather than the asset's own used exports so that we include
|
|
// re-exported symbols rather than only symbols declared in this asset.
|
|
|
|
|
|
let incomingDeps = this.bundleGraph.getIncomingDependencies(asset);
|
|
let usedExports = [...asset.symbols.exportSymbols()].filter(symbol => {
|
|
if (symbol === '*') {
|
|
return false;
|
|
} // If we need default interop, then all symbols are needed because the `default`
|
|
// symbol really maps to the whole namespace.
|
|
|
|
|
|
if (defaultInterop) {
|
|
return true;
|
|
}
|
|
|
|
let unused = incomingDeps.every(d => {
|
|
let symbols = (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(d));
|
|
return !symbols.has(symbol) && !symbols.has('*');
|
|
});
|
|
return !unused;
|
|
});
|
|
|
|
if (usedExports.length > 0) {
|
|
// Insert $parcel$export calls for each of the used exports. This creates a getter/setter
|
|
// for the symbol so that when the value changes the object property also changes. This is
|
|
// required to simulate ESM live bindings. It's easier to do it this way rather than inserting
|
|
// additional assignments after each mutation of the original binding.
|
|
prepend += `\n${usedExports.map(exp => {
|
|
let resolved = this.getSymbolResolution(asset, asset, exp);
|
|
let get = this.buildFunctionExpression([], resolved);
|
|
let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : '';
|
|
return `$parcel$export($${assetId}$exports, ${JSON.stringify(exp)}, ${get}${set});`;
|
|
}).join('\n')}\n`;
|
|
this.usedHelpers.add('$parcel$export');
|
|
prependLineCount += 1 + usedExports.length;
|
|
} // Find wildcard re-export dependencies, and make sure their exports are also included in ours.
|
|
|
|
|
|
for (let dep of deps) {
|
|
let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
|
|
|
if (dep.isOptional || this.bundleGraph.isDependencySkipped(dep)) {
|
|
continue;
|
|
}
|
|
|
|
let isWrapped = resolved && resolved.meta.shouldWrap;
|
|
|
|
for (let [imported, {
|
|
local
|
|
}] of dep.symbols) {
|
|
if (imported === '*' && local === '*') {
|
|
if (!resolved) {
|
|
// Re-exporting an external module. This should have already been handled in buildReplacements.
|
|
let external = (0, _nullthrows().default)((0, _nullthrows().default)(this.externals.get(dep.specifier)).get('*'));
|
|
append += `$parcel$exportWildcard($${assetId}$exports, ${external});\n`;
|
|
this.usedHelpers.add('$parcel$exportWildcard');
|
|
continue;
|
|
} // If the resolved asset has an exports object, use the $parcel$exportWildcard helper
|
|
// to re-export all symbols. Otherwise, if there's no namespace object available, add
|
|
// $parcel$export calls for each used symbol of the dependency.
|
|
|
|
|
|
if (isWrapped || resolved.meta.staticExports === false || (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(resolved)).has('*') || // an empty asset
|
|
!resolved.meta.hasCJSExports && resolved.symbols.hasExportSymbol('*')) {
|
|
let obj = this.getSymbolResolution(asset, resolved, '*', dep);
|
|
append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`;
|
|
this.usedHelpers.add('$parcel$exportWildcard');
|
|
} else {
|
|
for (let symbol of (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep))) {
|
|
if (symbol === 'default' || // `export * as ...` does not include the default export
|
|
symbol === '__esModule') {
|
|
continue;
|
|
}
|
|
|
|
let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol);
|
|
let get = this.buildFunctionExpression([], resolvedSymbol);
|
|
let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolvedSymbol} = v`) : '';
|
|
prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(symbol)}, ${get}${set});\n`;
|
|
this.usedHelpers.add('$parcel$export');
|
|
prependLineCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return [prepend, prependLineCount, append];
|
|
}
|
|
|
|
buildBundlePrelude() {
|
|
let enableSourceMaps = this.bundle.env.sourceMap;
|
|
let res = '';
|
|
let lines = 0; // Add hashbang if the entry asset recorded an interpreter.
|
|
|
|
let mainEntry = this.bundle.getMainEntry();
|
|
|
|
if (mainEntry && !this.isAsyncBundle && !this.bundle.target.env.isBrowser()) {
|
|
let interpreter = mainEntry.meta.interpreter;
|
|
(0, _assert().default)(interpreter == null || typeof interpreter === 'string');
|
|
|
|
if (interpreter != null) {
|
|
res += `#!${interpreter}\n`;
|
|
lines++;
|
|
}
|
|
} // The output format may have specific things to add at the start of the bundle (e.g. imports).
|
|
|
|
|
|
let [outputFormatPrelude, outputFormatLines] = this.outputFormat.buildBundlePrelude();
|
|
res += outputFormatPrelude;
|
|
lines += outputFormatLines; // Add used helpers.
|
|
|
|
if (this.needsPrelude) {
|
|
this.usedHelpers.add('$parcel$global');
|
|
}
|
|
|
|
for (let helper of this.usedHelpers) {
|
|
res += _helpers.helpers[helper];
|
|
|
|
if (enableSourceMaps) {
|
|
lines += (0, _utils().countLines)(_helpers.helpers[helper]) - 1;
|
|
}
|
|
}
|
|
|
|
if (this.needsPrelude) {
|
|
// Add the prelude if this is potentially the first JS bundle to load in a
|
|
// particular context (e.g. entry scripts in HTML, workers, etc.).
|
|
let parentBundles = this.bundleGraph.getParentBundles(this.bundle);
|
|
let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated';
|
|
|
|
if (mightBeFirstJS) {
|
|
let preludeCode = (0, _helpers.prelude)(this.parcelRequireName);
|
|
res += preludeCode;
|
|
|
|
if (enableSourceMaps) {
|
|
lines += (0, _utils().countLines)(preludeCode) - 1;
|
|
}
|
|
} else {
|
|
// Otherwise, get the current parcelRequire global.
|
|
res += `var parcelRequire = $parcel$global[${JSON.stringify(this.parcelRequireName)}];\n`;
|
|
lines++;
|
|
}
|
|
} // Add importScripts for sibling bundles in workers.
|
|
|
|
|
|
if (this.bundle.env.isWorker() || this.bundle.env.isWorklet()) {
|
|
let importScripts = '';
|
|
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
|
|
|
for (let b of bundles) {
|
|
if (this.bundle.env.outputFormat === 'esmodule') {
|
|
// importScripts() is not allowed in native ES module workers.
|
|
importScripts += `import "${(0, _utils().relativeBundlePath)(this.bundle, b)}";\n`;
|
|
} else {
|
|
importScripts += `importScripts("${(0, _utils().relativeBundlePath)(this.bundle, b)}");\n`;
|
|
}
|
|
}
|
|
|
|
res += importScripts;
|
|
lines += bundles.length;
|
|
}
|
|
|
|
return [res, lines];
|
|
}
|
|
|
|
needsDefaultInterop(asset) {
|
|
if (asset.symbols.hasExportSymbol('*') && !asset.symbols.hasExportSymbol('default')) {
|
|
let deps = this.bundleGraph.getIncomingDependencies(asset);
|
|
return deps.some(dep => this.bundle.hasDependency(dep) && // dep.meta.isES6Module &&
|
|
dep.symbols.hasExportSymbol('default'));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
shouldSkipAsset(asset) {
|
|
if (this.isScriptEntry(asset)) {
|
|
return true;
|
|
}
|
|
|
|
return asset.sideEffects === false && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset)).size == 0 && !this.bundleGraph.isAssetReferenced(this.bundle, asset);
|
|
}
|
|
|
|
isScriptEntry(asset) {
|
|
return this.bundle.env.outputFormat === 'global' && this.bundle.env.sourceType === 'script' && asset === this.bundle.getMainEntry();
|
|
}
|
|
|
|
buildFunctionExpression(args, expr) {
|
|
return this.bundle.env.supports('arrow-functions', true) ? `(${args.join(', ')}) => ${expr}` : `function (${args.join(', ')}) { return ${expr}; }`;
|
|
}
|
|
|
|
}
|
|
|
|
exports.ScopeHoistingPackager = ScopeHoistingPackager; |