diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2023-11-01 20:49:36 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2023-11-01 20:49:36 +0800 |
| commit | e99f950f5018cfe737c0d1150e50d97c6e6a4823 (patch) | |
| tree | 16f329a1b22128ed67f3fcae15a9b0a030f2ccbf /node_modules/webpack/lib/javascript | |
| parent | c5d8a744dd584749e0b920119b42e731e37e5f62 (diff) | |
update
Diffstat (limited to 'node_modules/webpack/lib/javascript')
10 files changed, 0 insertions, 7496 deletions
diff --git a/node_modules/webpack/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js b/node_modules/webpack/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js deleted file mode 100644 index d2a2745a..00000000 --- a/node_modules/webpack/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +++ /dev/null @@ -1,154 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const { ConcatSource, PrefixSource, RawSource } = require("webpack-sources"); -const { RuntimeGlobals } = require(".."); -const HotUpdateChunk = require("../HotUpdateChunk"); -const Template = require("../Template"); -const { getCompilationHooks } = require("./JavascriptModulesPlugin"); -const { - generateEntryStartup, - updateHashForEntryStartup -} = require("./StartupHelpers"); - -/** @typedef {import("../Compiler")} Compiler */ - -class ArrayPushCallbackChunkFormatPlugin { - /** - * Apply the plugin - * @param {Compiler} compiler the compiler instance - * @returns {void} - */ - apply(compiler) { - compiler.hooks.thisCompilation.tap( - "ArrayPushCallbackChunkFormatPlugin", - compilation => { - compilation.hooks.additionalChunkRuntimeRequirements.tap( - "ArrayPushCallbackChunkFormatPlugin", - (chunk, set, { chunkGraph }) => { - if (chunk.hasRuntime()) return; - if (chunkGraph.getNumberOfEntryModules(chunk) > 0) { - set.add(RuntimeGlobals.onChunksLoaded); - set.add(RuntimeGlobals.require); - } - set.add(RuntimeGlobals.chunkCallback); - } - ); - const hooks = getCompilationHooks(compilation); - hooks.renderChunk.tap( - "ArrayPushCallbackChunkFormatPlugin", - (modules, renderContext) => { - const { chunk, chunkGraph, runtimeTemplate } = renderContext; - const hotUpdateChunk = - chunk instanceof HotUpdateChunk ? chunk : null; - const globalObject = runtimeTemplate.globalObject; - const source = new ConcatSource(); - const runtimeModules = - chunkGraph.getChunkRuntimeModulesInOrder(chunk); - if (hotUpdateChunk) { - const hotUpdateGlobal = - runtimeTemplate.outputOptions.hotUpdateGlobal; - source.add( - `${globalObject}[${JSON.stringify(hotUpdateGlobal)}](` - ); - source.add(`${JSON.stringify(chunk.id)},`); - source.add(modules); - if (runtimeModules.length > 0) { - source.add(",\n"); - const runtimePart = Template.renderChunkRuntimeModules( - runtimeModules, - renderContext - ); - source.add(runtimePart); - } - source.add(")"); - } else { - const chunkLoadingGlobal = - runtimeTemplate.outputOptions.chunkLoadingGlobal; - source.add( - `(${globalObject}[${JSON.stringify( - chunkLoadingGlobal - )}] = ${globalObject}[${JSON.stringify( - chunkLoadingGlobal - )}] || []).push([` - ); - source.add(`${JSON.stringify(chunk.ids)},`); - source.add(modules); - const entries = Array.from( - chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk) - ); - if (runtimeModules.length > 0 || entries.length > 0) { - const runtime = new ConcatSource( - (runtimeTemplate.supportsArrowFunction() - ? `${RuntimeGlobals.require} =>` - : `function(${RuntimeGlobals.require})`) + - " { // webpackRuntimeModules\n" - ); - if (runtimeModules.length > 0) { - runtime.add( - Template.renderRuntimeModules(runtimeModules, { - ...renderContext, - codeGenerationResults: compilation.codeGenerationResults - }) - ); - } - if (entries.length > 0) { - const startupSource = new RawSource( - generateEntryStartup( - chunkGraph, - runtimeTemplate, - entries, - chunk, - true - ) - ); - runtime.add( - hooks.renderStartup.call( - startupSource, - entries[entries.length - 1][0], - { - ...renderContext, - inlined: false - } - ) - ); - if ( - chunkGraph - .getChunkRuntimeRequirements(chunk) - .has(RuntimeGlobals.returnExportsFromRuntime) - ) { - runtime.add(`return ${RuntimeGlobals.exports};\n`); - } - } - runtime.add("}\n"); - source.add(",\n"); - source.add(new PrefixSource("/******/ ", runtime)); - } - source.add("])"); - } - return source; - } - ); - hooks.chunkHash.tap( - "ArrayPushCallbackChunkFormatPlugin", - (chunk, hash, { chunkGraph, runtimeTemplate }) => { - if (chunk.hasRuntime()) return; - hash.update( - `ArrayPushCallbackChunkFormatPlugin1${runtimeTemplate.outputOptions.chunkLoadingGlobal}${runtimeTemplate.outputOptions.hotUpdateGlobal}${runtimeTemplate.globalObject}` - ); - const entries = Array.from( - chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk) - ); - updateHashForEntryStartup(hash, chunkGraph, entries, chunk); - } - ); - } - ); - } -} - -module.exports = ArrayPushCallbackChunkFormatPlugin; diff --git a/node_modules/webpack/lib/javascript/BasicEvaluatedExpression.js b/node_modules/webpack/lib/javascript/BasicEvaluatedExpression.js deleted file mode 100644 index 701791c8..00000000 --- a/node_modules/webpack/lib/javascript/BasicEvaluatedExpression.js +++ /dev/null @@ -1,609 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -/** @typedef {import("estree").Node} Node */ -/** @typedef {import("./JavascriptParser").Range} Range */ -/** @typedef {import("./JavascriptParser").VariableInfoInterface} VariableInfoInterface */ - -const TypeUnknown = 0; -const TypeUndefined = 1; -const TypeNull = 2; -const TypeString = 3; -const TypeNumber = 4; -const TypeBoolean = 5; -const TypeRegExp = 6; -const TypeConditional = 7; -const TypeArray = 8; -const TypeConstArray = 9; -const TypeIdentifier = 10; -const TypeWrapped = 11; -const TypeTemplateString = 12; -const TypeBigInt = 13; - -class BasicEvaluatedExpression { - constructor() { - this.type = TypeUnknown; - /** @type {[number, number] | undefined} */ - this.range = undefined; - /** @type {boolean} */ - this.falsy = false; - /** @type {boolean} */ - this.truthy = false; - /** @type {boolean | undefined} */ - this.nullish = undefined; - /** @type {boolean} */ - this.sideEffects = true; - /** @type {boolean | undefined} */ - this.bool = undefined; - /** @type {number | undefined} */ - this.number = undefined; - /** @type {bigint | undefined} */ - this.bigint = undefined; - /** @type {RegExp | undefined} */ - this.regExp = undefined; - /** @type {string | undefined} */ - this.string = undefined; - /** @type {BasicEvaluatedExpression[] | undefined} */ - this.quasis = undefined; - /** @type {BasicEvaluatedExpression[] | undefined} */ - this.parts = undefined; - /** @type {any[] | undefined} */ - this.array = undefined; - /** @type {BasicEvaluatedExpression[] | undefined} */ - this.items = undefined; - /** @type {BasicEvaluatedExpression[] | undefined} */ - this.options = undefined; - /** @type {BasicEvaluatedExpression | undefined | null} */ - this.prefix = undefined; - /** @type {BasicEvaluatedExpression | undefined | null} */ - this.postfix = undefined; - /** @type {BasicEvaluatedExpression[] | undefined} */ - this.wrappedInnerExpressions = undefined; - /** @type {string | VariableInfoInterface | undefined} */ - this.identifier = undefined; - /** @type {string | VariableInfoInterface | undefined} */ - this.rootInfo = undefined; - /** @type {(() => string[]) | undefined} */ - this.getMembers = undefined; - /** @type {(() => boolean[]) | undefined} */ - this.getMembersOptionals = undefined; - /** @type {(() => Range[]) | undefined} */ - this.getMemberRanges = undefined; - /** @type {Node | undefined} */ - this.expression = undefined; - } - - isUnknown() { - return this.type === TypeUnknown; - } - - isNull() { - return this.type === TypeNull; - } - - isUndefined() { - return this.type === TypeUndefined; - } - - isString() { - return this.type === TypeString; - } - - isNumber() { - return this.type === TypeNumber; - } - - isBigInt() { - return this.type === TypeBigInt; - } - - isBoolean() { - return this.type === TypeBoolean; - } - - isRegExp() { - return this.type === TypeRegExp; - } - - isConditional() { - return this.type === TypeConditional; - } - - isArray() { - return this.type === TypeArray; - } - - isConstArray() { - return this.type === TypeConstArray; - } - - isIdentifier() { - return this.type === TypeIdentifier; - } - - isWrapped() { - return this.type === TypeWrapped; - } - - isTemplateString() { - return this.type === TypeTemplateString; - } - - /** - * Is expression a primitive or an object type value? - * @returns {boolean | undefined} true: primitive type, false: object type, undefined: unknown/runtime-defined - */ - isPrimitiveType() { - switch (this.type) { - case TypeUndefined: - case TypeNull: - case TypeString: - case TypeNumber: - case TypeBoolean: - case TypeBigInt: - case TypeWrapped: - case TypeTemplateString: - return true; - case TypeRegExp: - case TypeArray: - case TypeConstArray: - return false; - default: - return undefined; - } - } - - /** - * Is expression a runtime or compile-time value? - * @returns {boolean} true: compile time value, false: runtime value - */ - isCompileTimeValue() { - switch (this.type) { - case TypeUndefined: - case TypeNull: - case TypeString: - case TypeNumber: - case TypeBoolean: - case TypeRegExp: - case TypeConstArray: - case TypeBigInt: - return true; - default: - return false; - } - } - - /** - * Gets the compile-time value of the expression - * @returns {any} the javascript value - */ - asCompileTimeValue() { - switch (this.type) { - case TypeUndefined: - return undefined; - case TypeNull: - return null; - case TypeString: - return this.string; - case TypeNumber: - return this.number; - case TypeBoolean: - return this.bool; - case TypeRegExp: - return this.regExp; - case TypeConstArray: - return this.array; - case TypeBigInt: - return this.bigint; - default: - throw new Error( - "asCompileTimeValue must only be called for compile-time values" - ); - } - } - - isTruthy() { - return this.truthy; - } - - isFalsy() { - return this.falsy; - } - - isNullish() { - return this.nullish; - } - - /** - * Can this expression have side effects? - * @returns {boolean} false: never has side effects - */ - couldHaveSideEffects() { - return this.sideEffects; - } - - /** - * Creates a boolean representation of this evaluated expression. - * @returns {boolean | undefined} true: truthy, false: falsy, undefined: unknown - */ - asBool() { - if (this.truthy) return true; - if (this.falsy || this.nullish) return false; - if (this.isBoolean()) return this.bool; - if (this.isNull()) return false; - if (this.isUndefined()) return false; - if (this.isString()) return this.string !== ""; - if (this.isNumber()) return this.number !== 0; - if (this.isBigInt()) return this.bigint !== BigInt(0); - if (this.isRegExp()) return true; - if (this.isArray()) return true; - if (this.isConstArray()) return true; - if (this.isWrapped()) { - return (this.prefix && this.prefix.asBool()) || - (this.postfix && this.postfix.asBool()) - ? true - : undefined; - } - if (this.isTemplateString()) { - const str = this.asString(); - if (typeof str === "string") return str !== ""; - } - return undefined; - } - - /** - * Creates a nullish coalescing representation of this evaluated expression. - * @returns {boolean | undefined} true: nullish, false: not nullish, undefined: unknown - */ - asNullish() { - const nullish = this.isNullish(); - - if (nullish === true || this.isNull() || this.isUndefined()) return true; - - if (nullish === false) return false; - if (this.isTruthy()) return false; - if (this.isBoolean()) return false; - if (this.isString()) return false; - if (this.isNumber()) return false; - if (this.isBigInt()) return false; - if (this.isRegExp()) return false; - if (this.isArray()) return false; - if (this.isConstArray()) return false; - if (this.isTemplateString()) return false; - if (this.isRegExp()) return false; - - return undefined; - } - - /** - * Creates a string representation of this evaluated expression. - * @returns {string | undefined} the string representation or undefined if not possible - */ - asString() { - if (this.isBoolean()) return `${this.bool}`; - if (this.isNull()) return "null"; - if (this.isUndefined()) return "undefined"; - if (this.isString()) return this.string; - if (this.isNumber()) return `${this.number}`; - if (this.isBigInt()) return `${this.bigint}`; - if (this.isRegExp()) return `${this.regExp}`; - if (this.isArray()) { - let array = []; - for (const item of /** @type {BasicEvaluatedExpression[]} */ ( - this.items - )) { - const itemStr = item.asString(); - if (itemStr === undefined) return undefined; - array.push(itemStr); - } - return `${array}`; - } - if (this.isConstArray()) return `${this.array}`; - if (this.isTemplateString()) { - let str = ""; - for (const part of /** @type {BasicEvaluatedExpression[]} */ ( - this.parts - )) { - const partStr = part.asString(); - if (partStr === undefined) return undefined; - str += partStr; - } - return str; - } - return undefined; - } - - /** - * @param {string} string value - * @returns {BasicEvaluatedExpression} basic evaluated expression - */ - setString(string) { - this.type = TypeString; - this.string = string; - this.sideEffects = false; - return this; - } - - setUndefined() { - this.type = TypeUndefined; - this.sideEffects = false; - return this; - } - - setNull() { - this.type = TypeNull; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a number - * @param {number} number number to set - * @returns {this} this - */ - setNumber(number) { - this.type = TypeNumber; - this.number = number; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a BigInt - * @param {bigint} bigint bigint to set - * @returns {this} this - */ - setBigInt(bigint) { - this.type = TypeBigInt; - this.bigint = bigint; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a boolean - * @param {boolean} bool boolean to set - * @returns {this} this - */ - setBoolean(bool) { - this.type = TypeBoolean; - this.bool = bool; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a regular expression - * @param {RegExp} regExp regular expression to set - * @returns {this} this - */ - setRegExp(regExp) { - this.type = TypeRegExp; - this.regExp = regExp; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a particular identifier and its members. - * - * @param {string | VariableInfoInterface} identifier identifier to set - * @param {string | VariableInfoInterface} rootInfo root info - * @param {() => string[]} getMembers members - * @param {() => boolean[]=} getMembersOptionals optional members - * @param {() => Range[]=} getMemberRanges ranges of progressively increasing sub-expressions - * @returns {this} this - */ - setIdentifier( - identifier, - rootInfo, - getMembers, - getMembersOptionals, - getMemberRanges - ) { - this.type = TypeIdentifier; - this.identifier = identifier; - this.rootInfo = rootInfo; - this.getMembers = getMembers; - this.getMembersOptionals = getMembersOptionals; - this.getMemberRanges = getMemberRanges; - this.sideEffects = true; - return this; - } - - /** - * Wraps an array of expressions with a prefix and postfix expression. - * - * @param {BasicEvaluatedExpression | null | undefined} prefix Expression to be added before the innerExpressions - * @param {BasicEvaluatedExpression | null | undefined} postfix Expression to be added after the innerExpressions - * @param {BasicEvaluatedExpression[]} innerExpressions Expressions to be wrapped - * @returns {this} this - */ - setWrapped(prefix, postfix, innerExpressions) { - this.type = TypeWrapped; - this.prefix = prefix; - this.postfix = postfix; - this.wrappedInnerExpressions = innerExpressions; - this.sideEffects = true; - return this; - } - - /** - * Stores the options of a conditional expression. - * - * @param {BasicEvaluatedExpression[]} options optional (consequent/alternate) expressions to be set - * @returns {this} this - */ - setOptions(options) { - this.type = TypeConditional; - this.options = options; - this.sideEffects = true; - return this; - } - - /** - * Adds options to a conditional expression. - * - * @param {BasicEvaluatedExpression[]} options optional (consequent/alternate) expressions to be added - * @returns {this} this - */ - addOptions(options) { - if (!this.options) { - this.type = TypeConditional; - this.options = []; - this.sideEffects = true; - } - for (const item of options) { - this.options.push(item); - } - return this; - } - - /** - * Set's the value of this expression to an array of expressions. - * - * @param {BasicEvaluatedExpression[]} items expressions to set - * @returns {this} this - */ - setItems(items) { - this.type = TypeArray; - this.items = items; - this.sideEffects = items.some(i => i.couldHaveSideEffects()); - return this; - } - - /** - * Set's the value of this expression to an array of strings. - * - * @param {string[]} array array to set - * @returns {this} this - */ - setArray(array) { - this.type = TypeConstArray; - this.array = array; - this.sideEffects = false; - return this; - } - - /** - * Set's the value of this expression to a processed/unprocessed template string. Used - * for evaluating TemplateLiteral expressions in the JavaScript Parser. - * - * @param {BasicEvaluatedExpression[]} quasis template string quasis - * @param {BasicEvaluatedExpression[]} parts template string parts - * @param {"cooked" | "raw"} kind template string kind - * @returns {this} this - */ - setTemplateString(quasis, parts, kind) { - this.type = TypeTemplateString; - this.quasis = quasis; - this.parts = parts; - this.templateStringKind = kind; - this.sideEffects = parts.some(p => p.sideEffects); - return this; - } - - setTruthy() { - this.falsy = false; - this.truthy = true; - this.nullish = false; - return this; - } - - setFalsy() { - this.falsy = true; - this.truthy = false; - return this; - } - - /** - * Set's the value of the expression to nullish. - * - * @param {boolean} value true, if the expression is nullish - * @returns {this} this - */ - setNullish(value) { - this.nullish = value; - - if (value) return this.setFalsy(); - - return this; - } - - /** - * Set's the range for the expression. - * - * @param {[number, number]} range range to set - * @returns {this} this - */ - setRange(range) { - this.range = range; - return this; - } - - /** - * Set whether or not the expression has side effects. - * - * @param {boolean} sideEffects true, if the expression has side effects - * @returns {this} this - */ - setSideEffects(sideEffects = true) { - this.sideEffects = sideEffects; - return this; - } - - /** - * Set the expression node for the expression. - * - * @param {Node | undefined} expression expression - * @returns {this} this - */ - setExpression(expression) { - this.expression = expression; - return this; - } -} - -/** - * @param {string} flags regexp flags - * @returns {boolean} is valid flags - */ -BasicEvaluatedExpression.isValidRegExpFlags = flags => { - const len = flags.length; - - if (len === 0) return true; - if (len > 4) return false; - - // cspell:word gimy - let remaining = 0b0000; // bit per RegExp flag: gimy - - for (let i = 0; i < len; i++) - switch (flags.charCodeAt(i)) { - case 103 /* g */: - if (remaining & 0b1000) return false; - remaining |= 0b1000; - break; - case 105 /* i */: - if (remaining & 0b0100) return false; - remaining |= 0b0100; - break; - case 109 /* m */: - if (remaining & 0b0010) return false; - remaining |= 0b0010; - break; - case 121 /* y */: - if (remaining & 0b0001) return false; - remaining |= 0b0001; - break; - default: - return false; - } - - return true; -}; - -module.exports = BasicEvaluatedExpression; diff --git a/node_modules/webpack/lib/javascript/ChunkHelpers.js b/node_modules/webpack/lib/javascript/ChunkHelpers.js deleted file mode 100644 index f29d8d7a..00000000 --- a/node_modules/webpack/lib/javascript/ChunkHelpers.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const Entrypoint = require("../Entrypoint"); - -/** @typedef {import("../Chunk")} Chunk */ - -/** - * @param {Entrypoint} entrypoint a chunk group - * @param {Chunk=} excludedChunk1 current chunk which is excluded - * @param {Chunk=} excludedChunk2 runtime chunk which is excluded - * @returns {Set<Chunk>} chunks - */ -const getAllChunks = (entrypoint, excludedChunk1, excludedChunk2) => { - const queue = new Set([entrypoint]); - const chunks = new Set(); - for (const entrypoint of queue) { - for (const chunk of entrypoint.chunks) { - if (chunk === excludedChunk1) continue; - if (chunk === excludedChunk2) continue; - chunks.add(chunk); - } - for (const parent of entrypoint.parentsIterable) { - if (parent instanceof Entrypoint) queue.add(parent); - } - } - return chunks; -}; -exports.getAllChunks = getAllChunks; diff --git a/node_modules/webpack/lib/javascript/CommonJsChunkFormatPlugin.js b/node_modules/webpack/lib/javascript/CommonJsChunkFormatPlugin.js deleted file mode 100644 index 65963ec5..00000000 --- a/node_modules/webpack/lib/javascript/CommonJsChunkFormatPlugin.js +++ /dev/null @@ -1,176 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const { ConcatSource, RawSource } = require("webpack-sources"); -const RuntimeGlobals = require("../RuntimeGlobals"); -const Template = require("../Template"); -const { - getChunkFilenameTemplate, - getCompilationHooks -} = require("./JavascriptModulesPlugin"); -const { - generateEntryStartup, - updateHashForEntryStartup -} = require("./StartupHelpers"); - -/** @typedef {import("../Chunk")} Chunk */ -/** @typedef {import("../Compiler")} Compiler */ -/** @typedef {import("../Entrypoint")} Entrypoint */ - -class CommonJsChunkFormatPlugin { - /** - * Apply the plugin - * @param {Compiler} compiler the compiler instance - * @returns {void} - */ - apply(compiler) { - compiler.hooks.thisCompilation.tap( - "CommonJsChunkFormatPlugin", - compilation => { - compilation.hooks.additionalChunkRuntimeRequirements.tap( - "CommonJsChunkLoadingPlugin", - (chunk, set, { chunkGraph }) => { - if (chunk.hasRuntime()) return; - if (chunkGraph.getNumberOfEntryModules(chunk) > 0) { - set.add(RuntimeGlobals.require); - set.add(RuntimeGlobals.startupEntrypoint); - set.add(RuntimeGlobals.externalInstallChunk); - } - } - ); - const hooks = getCompilationHooks(compilation); - hooks.renderChunk.tap( - "CommonJsChunkFormatPlugin", - (modules, renderContext) => { - const { chunk, chunkGraph, runtimeTemplate } = renderContext; - const source = new ConcatSource(); - source.add(`exports.id = ${JSON.stringify(chunk.id)};\n`); - source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`); - source.add(`exports.modules = `); - source.add(modules); - source.add(";\n"); - const runtimeModules = - chunkGraph.getChunkRuntimeModulesInOrder(chunk); - if (runtimeModules.length > 0) { - source.add("exports.runtime =\n"); - source.add( - Template.renderChunkRuntimeModules( - runtimeModules, - renderContext - ) - ); - } - const entries = Array.from( - chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk) - ); - if (entries.length > 0) { - const runtimeChunk = - /** @type {Entrypoint} */ - (entries[0][1]).getRuntimeChunk(); - const currentOutputName = compilation - .getPath( - getChunkFilenameTemplate(chunk, compilation.outputOptions), - { - chunk, - contentHashType: "javascript" - } - ) - .split("/"); - const runtimeOutputName = compilation - .getPath( - getChunkFilenameTemplate( - runtimeChunk, - compilation.outputOptions - ), - { - chunk: /** @type {Chunk} */ (runtimeChunk), - contentHashType: "javascript" - } - ) - .split("/"); - - // remove filename, we only need the directory - currentOutputName.pop(); - - // remove common parts - while ( - currentOutputName.length > 0 && - runtimeOutputName.length > 0 && - currentOutputName[0] === runtimeOutputName[0] - ) { - currentOutputName.shift(); - runtimeOutputName.shift(); - } - - // create final path - const runtimePath = - (currentOutputName.length > 0 - ? "../".repeat(currentOutputName.length) - : "./") + runtimeOutputName.join("/"); - - const entrySource = new ConcatSource(); - entrySource.add( - `(${ - runtimeTemplate.supportsArrowFunction() - ? "() => " - : "function() " - }{\n` - ); - entrySource.add("var exports = {};\n"); - entrySource.add(source); - entrySource.add(";\n\n// load runtime\n"); - entrySource.add( - `var ${RuntimeGlobals.require} = require(${JSON.stringify( - runtimePath - )});\n` - ); - entrySource.add( - `${RuntimeGlobals.externalInstallChunk}(exports);\n` - ); - const startupSource = new RawSource( - generateEntryStartup( - chunkGraph, - runtimeTemplate, - entries, - chunk, - false - ) - ); - entrySource.add( - hooks.renderStartup.call( - startupSource, - entries[entries.length - 1][0], - { - ...renderContext, - inlined: false - } - ) - ); - entrySource.add("\n})()"); - return entrySource; - } - return source; - } - ); - hooks.chunkHash.tap( - "CommonJsChunkFormatPlugin", - (chunk, hash, { chunkGraph }) => { - if (chunk.hasRuntime()) return; - hash.update("CommonJsChunkFormatPlugin"); - hash.update("1"); - const entries = Array.from( - chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk) - ); - updateHashForEntryStartup(hash, chunkGraph, entries, chunk); - } - ); - } - ); - } -} - -module.exports = CommonJsChunkFormatPlugin; diff --git a/node_modules/webpack/lib/javascript/EnableChunkLoadingPlugin.js b/node_modules/webpack/lib/javascript/EnableChunkLoadingPlugin.js deleted file mode 100644 index 3756e4a1..00000000 --- a/node_modules/webpack/lib/javascript/EnableChunkLoadingPlugin.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -/** @typedef {import("../../declarations/WebpackOptions").ChunkLoadingType} ChunkLoadingType */ -/** @typedef {import("../Compiler")} Compiler */ - -/** @type {WeakMap<Compiler, Set<ChunkLoadingType>>} */ -const enabledTypes = new WeakMap(); - -/** - * @param {Compiler} compiler compiler - * @returns {Set<ChunkLoadingType>} enabled types - */ -const getEnabledTypes = compiler => { - let set = enabledTypes.get(compiler); - if (set === undefined) { - set = new Set(); - enabledTypes.set(compiler, set); - } - return set; -}; - -class EnableChunkLoadingPlugin { - /** - * @param {ChunkLoadingType} type library type that should be available - */ - constructor(type) { - this.type = type; - } - - /** - * @param {Compiler} compiler the compiler instance - * @param {ChunkLoadingType} type type of library - * @returns {void} - */ - static setEnabled(compiler, type) { - getEnabledTypes(compiler).add(type); - } - - /** - * @param {Compiler} compiler the compiler instance - * @param {ChunkLoadingType} type type of library - * @returns {void} - */ - static checkEnabled(compiler, type) { - if (!getEnabledTypes(compiler).has(type)) { - throw new Error( - `Chunk loading type "${type}" is not enabled. ` + - "EnableChunkLoadingPlugin need to be used to enable this type of chunk loading. " + - 'This usually happens through the "output.enabledChunkLoadingTypes" option. ' + - 'If you are using a function as entry which sets "chunkLoading", you need to add all potential chunk loading types to "output.enabledChunkLoadingTypes". ' + - "These types are enabled: " + - Array.from(getEnabledTypes(compiler)).join(", ") - ); - } - } - - /** - * Apply the plugin - * @param {Compiler} compiler the compiler instance - * @returns {void} - */ - apply(compiler) { - const { type } = this; - - // Only enable once - const enabled = getEnabledTypes(compiler); - if (enabled.has(type)) return; - enabled.add(type); - - if (typeof type === "string") { - switch (type) { - case "jsonp": { - const JsonpChunkLoadingPlugin = require("../web/JsonpChunkLoadingPlugin"); - new JsonpChunkLoadingPlugin().apply(compiler); - break; - } - case "import-scripts": { - const ImportScriptsChunkLoadingPlugin = require("../webworker/ImportScriptsChunkLoadingPlugin"); - new ImportScriptsChunkLoadingPlugin().apply(compiler); - break; - } - case "require": { - //@ts-expect-error https://github.com/microsoft/TypeScript/issues/41697 - const CommonJsChunkLoadingPlugin = require("../node/CommonJsChunkLoadingPlugin"); - new CommonJsChunkLoadingPlugin({ - asyncChunkLoading: false - }).apply(compiler); - break; - } - case "async-node": { - //@ts-expect-error https://github.com/microsoft/TypeScript/issues/41697 - const CommonJsChunkLoadingPlugin = require("../node/CommonJsChunkLoadingPlugin"); - new CommonJsChunkLoadingPlugin({ - asyncChunkLoading: true - }).apply(compiler); - break; - } - case "import": { - const ModuleChunkLoadingPlugin = require("../esm/ModuleChunkLoadingPlugin"); - new ModuleChunkLoadingPlugin().apply(compiler); - break; - } - case "universal": - // TODO implement universal chunk loading - throw new Error("Universal Chunk Loading is not implemented yet"); - default: - throw new Error(`Unsupported chunk loading type ${type}. -Plugins which provide custom chunk loading types must call EnableChunkLoadingPlugin.setEnabled(compiler, type) to disable this error.`); - } - } else { - // TODO support plugin instances here - // apply them to the compiler - } - } -} - -module.exports = EnableChunkLoadingPlugin; diff --git a/node_modules/webpack/lib/javascript/JavascriptGenerator.js b/node_modules/webpack/lib/javascript/JavascriptGenerator.js deleted file mode 100644 index d13eb8a0..00000000 --- a/node_modules/webpack/lib/javascript/JavascriptGenerator.js +++ /dev/null @@ -1,225 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const util = require("util"); -const { RawSource, ReplaceSource } = require("webpack-sources"); -const Generator = require("../Generator"); -const InitFragment = require("../InitFragment"); -const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); - -/** @typedef {import("webpack-sources").Source} Source */ -/** @typedef {import("../DependenciesBlock")} DependenciesBlock */ -/** @typedef {import("../Dependency")} Dependency */ -/** @typedef {import("../DependencyTemplates")} DependencyTemplates */ -/** @typedef {import("../Generator").GenerateContext} GenerateContext */ -/** @typedef {import("../Module")} Module */ -/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */ -/** @typedef {import("../NormalModule")} NormalModule */ -/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ - -// TODO: clean up this file -// replace with newer constructs - -const deprecatedGetInitFragments = util.deprecate( - (template, dependency, templateContext) => - template.getInitFragments(dependency, templateContext), - "DependencyTemplate.getInitFragment is deprecated (use apply(dep, source, { initFragments }) instead)", - "DEP_WEBPACK_JAVASCRIPT_GENERATOR_GET_INIT_FRAGMENTS" -); - -const TYPES = new Set(["javascript"]); - -class JavascriptGenerator extends Generator { - /** - * @param {NormalModule} module fresh module - * @returns {Set<string>} available types (do not mutate) - */ - getTypes(module) { - return TYPES; - } - - /** - * @param {NormalModule} module the module - * @param {string=} type source type - * @returns {number} estimate size of the module - */ - getSize(module, type) { - const originalSource = module.originalSource(); - if (!originalSource) { - return 39; - } - return originalSource.size(); - } - - /** - * @param {NormalModule} module module for which the bailout reason should be determined - * @param {ConcatenationBailoutReasonContext} context context - * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated - */ - getConcatenationBailoutReason(module, context) { - // Only harmony modules are valid for optimization - if ( - !module.buildMeta || - module.buildMeta.exportsType !== "namespace" || - module.presentationalDependencies === undefined || - !module.presentationalDependencies.some( - d => d instanceof HarmonyCompatibilityDependency - ) - ) { - return "Module is not an ECMAScript module"; - } - - // Some expressions are not compatible with module concatenation - // because they may produce unexpected results. The plugin bails out - // if some were detected upfront. - if (module.buildInfo && module.buildInfo.moduleConcatenationBailout) { - return `Module uses ${module.buildInfo.moduleConcatenationBailout}`; - } - } - - /** - * @param {NormalModule} module module for which the code should be generated - * @param {GenerateContext} generateContext context for generate - * @returns {Source} generated code - */ - generate(module, generateContext) { - const originalSource = module.originalSource(); - if (!originalSource) { - return new RawSource("throw new Error('No source available');"); - } - - const source = new ReplaceSource(originalSource); - const initFragments = []; - - this.sourceModule(module, initFragments, source, generateContext); - - return InitFragment.addToSource(source, initFragments, generateContext); - } - - /** - * @param {Module} module the module to generate - * @param {InitFragment[]} initFragments mutable list of init fragments - * @param {ReplaceSource} source the current replace source which can be modified - * @param {GenerateContext} generateContext the generateContext - * @returns {void} - */ - sourceModule(module, initFragments, source, generateContext) { - for (const dependency of module.dependencies) { - this.sourceDependency( - module, - dependency, - initFragments, - source, - generateContext - ); - } - - if (module.presentationalDependencies !== undefined) { - for (const dependency of module.presentationalDependencies) { - this.sourceDependency( - module, - dependency, - initFragments, - source, - generateContext - ); - } - } - - for (const childBlock of module.blocks) { - this.sourceBlock( - module, - childBlock, - initFragments, - source, - generateContext - ); - } - } - - /** - * @param {Module} module the module to generate - * @param {DependenciesBlock} block the dependencies block which will be processed - * @param {InitFragment[]} initFragments mutable list of init fragments - * @param {ReplaceSource} source the current replace source which can be modified - * @param {GenerateContext} generateContext the generateContext - * @returns {void} - */ - sourceBlock(module, block, initFragments, source, generateContext) { - for (const dependency of block.dependencies) { - this.sourceDependency( - module, - dependency, - initFragments, - source, - generateContext - ); - } - - for (const childBlock of block.blocks) { - this.sourceBlock( - module, - childBlock, - initFragments, - source, - generateContext - ); - } - } - - /** - * @param {Module} module the current module - * @param {Dependency} dependency the dependency to generate - * @param {InitFragment[]} initFragments mutable list of init fragments - * @param {ReplaceSource} source the current replace source which can be modified - * @param {GenerateContext} generateContext the render context - * @returns {void} - */ - sourceDependency(module, dependency, initFragments, source, generateContext) { - const constructor = /** @type {new (...args: any[]) => Dependency} */ ( - dependency.constructor - ); - const template = generateContext.dependencyTemplates.get(constructor); - if (!template) { - throw new Error( - "No template for dependency: " + dependency.constructor.name - ); - } - - const templateContext = { - runtimeTemplate: generateContext.runtimeTemplate, - dependencyTemplates: generateContext.dependencyTemplates, - moduleGraph: generateContext.moduleGraph, - chunkGraph: generateContext.chunkGraph, - module, - runtime: generateContext.runtime, - runtimeRequirements: generateContext.runtimeRequirements, - concatenationScope: generateContext.concatenationScope, - codeGenerationResults: generateContext.codeGenerationResults, - initFragments - }; - - template.apply(dependency, source, templateContext); - - // TODO remove in webpack 6 - if ("getInitFragments" in template) { - const fragments = deprecatedGetInitFragments( - template, - dependency, - templateContext - ); - - if (fragments) { - for (const fragment of fragments) { - initFragments.push(fragment); - } - } - } - } -} - -module.exports = JavascriptGenerator; diff --git a/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js b/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js deleted file mode 100644 index 6eb79e70..00000000 --- a/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js +++ /dev/null @@ -1,1389 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const { SyncWaterfallHook, SyncHook, SyncBailHook } = require("tapable"); -const vm = require("vm"); -const { - ConcatSource, - OriginalSource, - PrefixSource, - RawSource, - CachedSource -} = require("webpack-sources"); -const Compilation = require("../Compilation"); -const { tryRunOrWebpackError } = require("../HookWebpackError"); -const HotUpdateChunk = require("../HotUpdateChunk"); -const InitFragment = require("../InitFragment"); -const { - JAVASCRIPT_MODULE_TYPE_AUTO, - JAVASCRIPT_MODULE_TYPE_DYNAMIC, - JAVASCRIPT_MODULE_TYPE_ESM, - WEBPACK_MODULE_TYPE_RUNTIME -} = require("../ModuleTypeConstants"); -const RuntimeGlobals = require("../RuntimeGlobals"); -const Template = require("../Template"); -const { last, someInIterable } = require("../util/IterableHelpers"); -const StringXor = require("../util/StringXor"); -const { compareModulesByIdentifier } = require("../util/comparators"); -const createHash = require("../util/createHash"); -const nonNumericOnlyHash = require("../util/nonNumericOnlyHash"); -const { intersectRuntime } = require("../util/runtime"); -const JavascriptGenerator = require("./JavascriptGenerator"); -const JavascriptParser = require("./JavascriptParser"); - -/** @typedef {import("webpack-sources").Source} Source */ -/** @typedef {import("../Chunk")} Chunk */ -/** @typedef {import("../ChunkGraph")} ChunkGraph */ -/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */ -/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */ -/** @typedef {import("../Compiler")} Compiler */ -/** @typedef {import("../DependencyTemplates")} DependencyTemplates */ -/** @typedef {import("../Module")} Module */ -/** @typedef {import("../ModuleGraph")} ModuleGraph */ -/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ -/** @typedef {import("../util/Hash")} Hash */ - -/** - * @param {Chunk} chunk a chunk - * @param {ChunkGraph} chunkGraph the chunk graph - * @returns {boolean} true, when a JS file is needed for this chunk - */ -const chunkHasJs = (chunk, chunkGraph) => { - if (chunkGraph.getNumberOfEntryModules(chunk) > 0) return true; - - return chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript") - ? true - : false; -}; - -/** - * @param {Module} module a module - * @param {string} code the code - * @returns {string} generated code for the stack - */ -const printGeneratedCodeForStack = (module, code) => { - const lines = code.split("\n"); - const n = `${lines.length}`.length; - return `\n\nGenerated code for ${module.identifier()}\n${lines - .map( - /** - * @param {string} line the line - * @param {number} i the index - * @param {string[]} lines the lines - * @returns {string} the line with line number - */ - (line, i, lines) => { - const iStr = `${i + 1}`; - return `${" ".repeat(n - iStr.length)}${iStr} | ${line}`; - } - ) - .join("\n")}`; -}; - -/** - * @typedef {Object} RenderContext - * @property {Chunk} chunk the chunk - * @property {DependencyTemplates} dependencyTemplates the dependency templates - * @property {RuntimeTemplate} runtimeTemplate the runtime template - * @property {ModuleGraph} moduleGraph the module graph - * @property {ChunkGraph} chunkGraph the chunk graph - * @property {CodeGenerationResults} codeGenerationResults results of code generation - * @property {boolean} strictMode rendering in strict context - */ - -/** - * @typedef {Object} MainRenderContext - * @property {Chunk} chunk the chunk - * @property {DependencyTemplates} dependencyTemplates the dependency templates - * @property {RuntimeTemplate} runtimeTemplate the runtime template - * @property {ModuleGraph} moduleGraph the module graph - * @property {ChunkGraph} chunkGraph the chunk graph - * @property {CodeGenerationResults} codeGenerationResults results of code generation - * @property {string} hash hash to be used for render call - * @property {boolean} strictMode rendering in strict context - */ - -/** - * @typedef {Object} ChunkRenderContext - * @property {Chunk} chunk the chunk - * @property {DependencyTemplates} dependencyTemplates the dependency templates - * @property {RuntimeTemplate} runtimeTemplate the runtime template - * @property {ModuleGraph} moduleGraph the module graph - * @property {ChunkGraph} chunkGraph the chunk graph - * @property {CodeGenerationResults} codeGenerationResults results of code generation - * @property {InitFragment<ChunkRenderContext>[]} chunkInitFragments init fragments for the chunk - * @property {boolean} strictMode rendering in strict context - */ - -/** - * @typedef {Object} RenderBootstrapContext - * @property {Chunk} chunk the chunk - * @property {CodeGenerationResults} codeGenerationResults results of code generation - * @property {RuntimeTemplate} runtimeTemplate the runtime template - * @property {ModuleGraph} moduleGraph the module graph - * @property {ChunkGraph} chunkGraph the chunk graph - * @property {string} hash hash to be used for render call - */ - -/** @typedef {RenderContext & { inlined: boolean }} StartupRenderContext */ - -/** - * @typedef {Object} CompilationHooks - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContent - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModuleContainer - * @property {SyncWaterfallHook<[Source, Module, ChunkRenderContext]>} renderModulePackage - * @property {SyncWaterfallHook<[Source, RenderContext]>} renderChunk - * @property {SyncWaterfallHook<[Source, RenderContext]>} renderMain - * @property {SyncWaterfallHook<[Source, RenderContext]>} renderContent - * @property {SyncWaterfallHook<[Source, RenderContext]>} render - * @property {SyncWaterfallHook<[Source, Module, StartupRenderContext]>} renderStartup - * @property {SyncWaterfallHook<[string, RenderBootstrapContext]>} renderRequire - * @property {SyncBailHook<[Module, RenderBootstrapContext], string>} inlineInRuntimeBailout - * @property {SyncBailHook<[Module, RenderContext], string | void>} embedInRuntimeBailout - * @property {SyncBailHook<[RenderContext], string | void>} strictRuntimeBailout - * @property {SyncHook<[Chunk, Hash, ChunkHashContext]>} chunkHash - * @property {SyncBailHook<[Chunk, RenderContext], boolean>} useSourceMap - */ - -/** @type {WeakMap<Compilation, CompilationHooks>} */ -const compilationHooksMap = new WeakMap(); - -const PLUGIN_NAME = "JavascriptModulesPlugin"; - -class JavascriptModulesPlugin { - /** - * @param {Compilation} compilation the compilation - * @returns {CompilationHooks} the attached hooks - */ - static getCompilationHooks(compilation) { - if (!(compilation instanceof Compilation)) { - throw new TypeError( - "The 'compilation' argument must be an instance of Compilation" - ); - } - let hooks = compilationHooksMap.get(compilation); - if (hooks === undefined) { - hooks = { - renderModuleContent: new SyncWaterfallHook([ - "source", - "module", - "renderContext" - ]), - renderModuleContainer: new SyncWaterfallHook([ - "source", - "module", - "renderContext" - ]), - renderModulePackage: new SyncWaterfallHook([ - "source", - "module", - "renderContext" - ]), - render: new SyncWaterfallHook(["source", "renderContext"]), - renderContent: new SyncWaterfallHook(["source", "renderContext"]), - renderStartup: new SyncWaterfallHook([ - "source", - "module", - "startupRenderContext" - ]), - renderChunk: new SyncWaterfallHook(["source", "renderContext"]), - renderMain: new SyncWaterfallHook(["source", "renderContext"]), - renderRequire: new SyncWaterfallHook(["code", "renderContext"]), - inlineInRuntimeBailout: new SyncBailHook(["module", "renderContext"]), - embedInRuntimeBailout: new SyncBailHook(["module", "renderContext"]), - strictRuntimeBailout: new SyncBailHook(["renderContext"]), - chunkHash: new SyncHook(["chunk", "hash", "context"]), - useSourceMap: new SyncBailHook(["chunk", "renderContext"]) - }; - compilationHooksMap.set(compilation, hooks); - } - return hooks; - } - - constructor(options = {}) { - this.options = options; - /** @type {WeakMap<Source, TODO>} */ - this._moduleFactoryCache = new WeakMap(); - } - - /** - * Apply the plugin - * @param {Compiler} compiler the compiler instance - * @returns {void} - */ - apply(compiler) { - compiler.hooks.compilation.tap( - PLUGIN_NAME, - (compilation, { normalModuleFactory }) => { - const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation); - normalModuleFactory.hooks.createParser - .for(JAVASCRIPT_MODULE_TYPE_AUTO) - .tap(PLUGIN_NAME, options => { - return new JavascriptParser("auto"); - }); - normalModuleFactory.hooks.createParser - .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) - .tap(PLUGIN_NAME, options => { - return new JavascriptParser("script"); - }); - normalModuleFactory.hooks.createParser - .for(JAVASCRIPT_MODULE_TYPE_ESM) - .tap(PLUGIN_NAME, options => { - return new JavascriptParser("module"); - }); - normalModuleFactory.hooks.createGenerator - .for(JAVASCRIPT_MODULE_TYPE_AUTO) - .tap(PLUGIN_NAME, () => { - return new JavascriptGenerator(); - }); - normalModuleFactory.hooks.createGenerator - .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) - .tap(PLUGIN_NAME, () => { - return new JavascriptGenerator(); - }); - normalModuleFactory.hooks.createGenerator - .for(JAVASCRIPT_MODULE_TYPE_ESM) - .tap(PLUGIN_NAME, () => { - return new JavascriptGenerator(); - }); - compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => { - const { - hash, - chunk, - chunkGraph, - moduleGraph, - runtimeTemplate, - dependencyTemplates, - outputOptions, - codeGenerationResults - } = options; - - const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null; - - let render; - const filenameTemplate = - JavascriptModulesPlugin.getChunkFilenameTemplate( - chunk, - outputOptions - ); - if (hotUpdateChunk) { - render = () => - this.renderChunk( - { - chunk, - dependencyTemplates, - runtimeTemplate, - moduleGraph, - chunkGraph, - codeGenerationResults, - strictMode: runtimeTemplate.isModule() - }, - hooks - ); - } else if (chunk.hasRuntime()) { - render = () => - this.renderMain( - { - hash, - chunk, - dependencyTemplates, - runtimeTemplate, - moduleGraph, - chunkGraph, - codeGenerationResults, - strictMode: runtimeTemplate.isModule() - }, - hooks, - compilation - ); - } else { - if (!chunkHasJs(chunk, chunkGraph)) { - return result; - } - - render = () => - this.renderChunk( - { - chunk, - dependencyTemplates, - runtimeTemplate, - moduleGraph, - chunkGraph, - codeGenerationResults, - strictMode: runtimeTemplate.isModule() - }, - hooks - ); - } - - result.push({ - render, - filenameTemplate, - pathOptions: { - hash, - runtime: chunk.runtime, - chunk, - contentHashType: "javascript" - }, - info: { - javascriptModule: compilation.runtimeTemplate.isModule() - }, - identifier: hotUpdateChunk - ? `hotupdatechunk${chunk.id}` - : `chunk${chunk.id}`, - hash: chunk.contentHash.javascript - }); - - return result; - }); - compilation.hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, context) => { - hooks.chunkHash.call(chunk, hash, context); - if (chunk.hasRuntime()) { - this.updateHashWithBootstrap( - hash, - { - hash: "0000", - chunk, - codeGenerationResults: context.codeGenerationResults, - chunkGraph: context.chunkGraph, - moduleGraph: context.moduleGraph, - runtimeTemplate: context.runtimeTemplate - }, - hooks - ); - } - }); - compilation.hooks.contentHash.tap(PLUGIN_NAME, chunk => { - const { - chunkGraph, - codeGenerationResults, - moduleGraph, - runtimeTemplate, - outputOptions: { - hashSalt, - hashDigest, - hashDigestLength, - hashFunction - } - } = compilation; - const hash = createHash(hashFunction); - if (hashSalt) hash.update(hashSalt); - if (chunk.hasRuntime()) { - this.updateHashWithBootstrap( - hash, - { - hash: "0000", - chunk, - codeGenerationResults, - chunkGraph: compilation.chunkGraph, - moduleGraph: compilation.moduleGraph, - runtimeTemplate: compilation.runtimeTemplate - }, - hooks - ); - } else { - hash.update(`${chunk.id} `); - hash.update(chunk.ids ? chunk.ids.join(",") : ""); - } - hooks.chunkHash.call(chunk, hash, { - chunkGraph, - codeGenerationResults, - moduleGraph, - runtimeTemplate - }); - const modules = chunkGraph.getChunkModulesIterableBySourceType( - chunk, - "javascript" - ); - if (modules) { - const xor = new StringXor(); - for (const m of modules) { - xor.add(chunkGraph.getModuleHash(m, chunk.runtime)); - } - xor.updateHash(hash); - } - const runtimeModules = chunkGraph.getChunkModulesIterableBySourceType( - chunk, - WEBPACK_MODULE_TYPE_RUNTIME - ); - if (runtimeModules) { - const xor = new StringXor(); - for (const m of runtimeModules) { - xor.add(chunkGraph.getModuleHash(m, chunk.runtime)); - } - xor.updateHash(hash); - } - const digest = /** @type {string} */ (hash.digest(hashDigest)); - chunk.contentHash.javascript = nonNumericOnlyHash( - digest, - hashDigestLength - ); - }); - compilation.hooks.additionalTreeRuntimeRequirements.tap( - PLUGIN_NAME, - (chunk, set, { chunkGraph }) => { - if ( - !set.has(RuntimeGlobals.startupNoDefault) && - chunkGraph.hasChunkEntryDependentChunks(chunk) - ) { - set.add(RuntimeGlobals.onChunksLoaded); - set.add(RuntimeGlobals.require); - } - } - ); - compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => { - const source = options.codeGenerationResult.sources.get("javascript"); - if (source === undefined) return; - const { module, moduleObject } = options; - const code = source.source(); - - const fn = vm.runInThisContext( - `(function(${module.moduleArgument}, ${module.exportsArgument}, ${RuntimeGlobals.require}) {\n${code}\n/**/})`, - { - filename: module.identifier(), - lineOffset: -1 - } - ); - try { - fn.call( - moduleObject.exports, - moduleObject, - moduleObject.exports, - context.__webpack_require__ - ); - } catch (e) { - e.stack += printGeneratedCodeForStack( - options.module, - /** @type {string} */ (code) - ); - throw e; - } - }); - compilation.hooks.executeModule.tap(PLUGIN_NAME, (options, context) => { - const source = options.codeGenerationResult.sources.get("runtime"); - if (source === undefined) return; - let code = source.source(); - if (typeof code !== "string") code = code.toString(); - - const fn = vm.runInThisContext( - `(function(${RuntimeGlobals.require}) {\n${code}\n/**/})`, - { - filename: options.module.identifier(), - lineOffset: -1 - } - ); - try { - fn.call(null, context.__webpack_require__); - } catch (e) { - e.stack += printGeneratedCodeForStack(options.module, code); - throw e; - } - }); - } - ); - } - - static getChunkFilenameTemplate(chunk, outputOptions) { - if (chunk.filenameTemplate) { - return chunk.filenameTemplate; - } else if (chunk instanceof HotUpdateChunk) { - return outputOptions.hotUpdateChunkFilename; - } else if (chunk.canBeInitial()) { - return outputOptions.filename; - } else { - return outputOptions.chunkFilename; - } - } - - /** - * @param {Module} module the rendered module - * @param {ChunkRenderContext} renderContext options object - * @param {CompilationHooks} hooks hooks - * @param {boolean} factory true: renders as factory method, false: pure module content - * @returns {Source} the newly generated source from rendering - */ - renderModule(module, renderContext, hooks, factory) { - const { - chunk, - chunkGraph, - runtimeTemplate, - codeGenerationResults, - strictMode - } = renderContext; - try { - const codeGenResult = codeGenerationResults.get(module, chunk.runtime); - const moduleSource = codeGenResult.sources.get("javascript"); - if (!moduleSource) return null; - if (codeGenResult.data !== undefined) { - const chunkInitFragments = codeGenResult.data.get("chunkInitFragments"); - if (chunkInitFragments) { - for (const i of chunkInitFragments) - renderContext.chunkInitFragments.push(i); - } - } - const moduleSourcePostContent = tryRunOrWebpackError( - () => - hooks.renderModuleContent.call(moduleSource, module, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderModuleContent" - ); - let moduleSourcePostContainer; - if (factory) { - const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements( - module, - chunk.runtime - ); - const needModule = runtimeRequirements.has(RuntimeGlobals.module); - const needExports = runtimeRequirements.has(RuntimeGlobals.exports); - const needRequire = - runtimeRequirements.has(RuntimeGlobals.require) || - runtimeRequirements.has(RuntimeGlobals.requireScope); - const needThisAsExports = runtimeRequirements.has( - RuntimeGlobals.thisAsExports - ); - const needStrict = module.buildInfo.strict && !strictMode; - const cacheEntry = this._moduleFactoryCache.get( - moduleSourcePostContent - ); - let source; - if ( - cacheEntry && - cacheEntry.needModule === needModule && - cacheEntry.needExports === needExports && - cacheEntry.needRequire === needRequire && - cacheEntry.needThisAsExports === needThisAsExports && - cacheEntry.needStrict === needStrict - ) { - source = cacheEntry.source; - } else { - const factorySource = new ConcatSource(); - const args = []; - if (needExports || needRequire || needModule) - args.push( - needModule - ? module.moduleArgument - : "__unused_webpack_" + module.moduleArgument - ); - if (needExports || needRequire) - args.push( - needExports - ? module.exportsArgument - : "__unused_webpack_" + module.exportsArgument - ); - if (needRequire) args.push(RuntimeGlobals.require); - if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) { - factorySource.add("/***/ ((" + args.join(", ") + ") => {\n\n"); - } else { - factorySource.add("/***/ (function(" + args.join(", ") + ") {\n\n"); - } - if (needStrict) { - factorySource.add('"use strict";\n'); - } - factorySource.add(moduleSourcePostContent); - factorySource.add("\n\n/***/ })"); - source = new CachedSource(factorySource); - this._moduleFactoryCache.set(moduleSourcePostContent, { - source, - needModule, - needExports, - needRequire, - needThisAsExports, - needStrict - }); - } - moduleSourcePostContainer = tryRunOrWebpackError( - () => hooks.renderModuleContainer.call(source, module, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer" - ); - } else { - moduleSourcePostContainer = moduleSourcePostContent; - } - return tryRunOrWebpackError( - () => - hooks.renderModulePackage.call( - moduleSourcePostContainer, - module, - renderContext - ), - "JavascriptModulesPlugin.getCompilationHooks().renderModulePackage" - ); - } catch (e) { - e.module = module; - throw e; - } - } - - /** - * @param {RenderContext} renderContext the render context - * @param {CompilationHooks} hooks hooks - * @returns {Source} the rendered source - */ - renderChunk(renderContext, hooks) { - const { chunk, chunkGraph } = renderContext; - const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType( - chunk, - "javascript", - compareModulesByIdentifier - ); - const allModules = modules ? Array.from(modules) : []; - let strictHeader; - let allStrict = renderContext.strictMode; - if (!allStrict && allModules.every(m => m.buildInfo.strict)) { - const strictBailout = hooks.strictRuntimeBailout.call(renderContext); - strictHeader = strictBailout - ? `// runtime can't be in strict mode because ${strictBailout}.\n` - : '"use strict";\n'; - if (!strictBailout) allStrict = true; - } - /** @type {ChunkRenderContext} */ - const chunkRenderContext = { - ...renderContext, - chunkInitFragments: [], - strictMode: allStrict - }; - const moduleSources = - Template.renderChunkModules(chunkRenderContext, allModules, module => - this.renderModule(module, chunkRenderContext, hooks, true) - ) || new RawSource("{}"); - let source = tryRunOrWebpackError( - () => hooks.renderChunk.call(moduleSources, chunkRenderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderChunk" - ); - source = tryRunOrWebpackError( - () => hooks.renderContent.call(source, chunkRenderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderContent" - ); - if (!source) { - throw new Error( - "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something" - ); - } - source = InitFragment.addToSource( - source, - chunkRenderContext.chunkInitFragments, - chunkRenderContext - ); - source = tryRunOrWebpackError( - () => hooks.render.call(source, chunkRenderContext), - "JavascriptModulesPlugin.getCompilationHooks().render" - ); - if (!source) { - throw new Error( - "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something" - ); - } - chunk.rendered = true; - return strictHeader - ? new ConcatSource(strictHeader, source, ";") - : renderContext.runtimeTemplate.isModule() - ? source - : new ConcatSource(source, ";"); - } - - /** - * @param {MainRenderContext} renderContext options object - * @param {CompilationHooks} hooks hooks - * @param {Compilation} compilation the compilation - * @returns {Source} the newly generated source from rendering - */ - renderMain(renderContext, hooks, compilation) { - const { chunk, chunkGraph, runtimeTemplate } = renderContext; - - const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk); - const iife = runtimeTemplate.isIIFE(); - - const bootstrap = this.renderBootstrap(renderContext, hooks); - const useSourceMap = hooks.useSourceMap.call(chunk, renderContext); - - const allModules = Array.from( - chunkGraph.getOrderedChunkModulesIterableBySourceType( - chunk, - "javascript", - compareModulesByIdentifier - ) || [] - ); - - const hasEntryModules = chunkGraph.getNumberOfEntryModules(chunk) > 0; - /** @type {Set<Module> | undefined} */ - let inlinedModules; - if (bootstrap.allowInlineStartup && hasEntryModules) { - inlinedModules = new Set(chunkGraph.getChunkEntryModulesIterable(chunk)); - } - - let source = new ConcatSource(); - let prefix; - if (iife) { - if (runtimeTemplate.supportsArrowFunction()) { - source.add("/******/ (() => { // webpackBootstrap\n"); - } else { - source.add("/******/ (function() { // webpackBootstrap\n"); - } - prefix = "/******/ \t"; - } else { - prefix = "/******/ "; - } - let allStrict = renderContext.strictMode; - if (!allStrict && allModules.every(m => m.buildInfo.strict)) { - const strictBailout = hooks.strictRuntimeBailout.call(renderContext); - if (strictBailout) { - source.add( - prefix + - `// runtime can't be in strict mode because ${strictBailout}.\n` - ); - } else { - allStrict = true; - source.add(prefix + '"use strict";\n'); - } - } - - /** @type {ChunkRenderContext} */ - const chunkRenderContext = { - ...renderContext, - chunkInitFragments: [], - strictMode: allStrict - }; - - const chunkModules = Template.renderChunkModules( - chunkRenderContext, - inlinedModules - ? allModules.filter( - m => !(/** @type {Set<Module>} */ (inlinedModules).has(m)) - ) - : allModules, - module => this.renderModule(module, chunkRenderContext, hooks, true), - prefix - ); - if ( - chunkModules || - runtimeRequirements.has(RuntimeGlobals.moduleFactories) || - runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly) || - runtimeRequirements.has(RuntimeGlobals.require) - ) { - source.add(prefix + "var __webpack_modules__ = ("); - source.add(chunkModules || "{}"); - source.add(");\n"); - source.add( - "/************************************************************************/\n" - ); - } - - if (bootstrap.header.length > 0) { - const header = Template.asString(bootstrap.header) + "\n"; - source.add( - new PrefixSource( - prefix, - useSourceMap - ? new OriginalSource(header, "webpack/bootstrap") - : new RawSource(header) - ) - ); - source.add( - "/************************************************************************/\n" - ); - } - - const runtimeModules = - renderContext.chunkGraph.getChunkRuntimeModulesInOrder(chunk); - - if (runtimeModules.length > 0) { - source.add( - new PrefixSource( - prefix, - Template.renderRuntimeModules(runtimeModules, chunkRenderContext) - ) - ); - source.add( - "/************************************************************************/\n" - ); - // runtimeRuntimeModules calls codeGeneration - for (const module of runtimeModules) { - compilation.codeGeneratedModules.add(module); - } - } - if (inlinedModules) { - if (bootstrap.beforeStartup.length > 0) { - const beforeStartup = Template.asString(bootstrap.beforeStartup) + "\n"; - source.add( - new PrefixSource( - prefix, - useSourceMap - ? new OriginalSource(beforeStartup, "webpack/before-startup") - : new RawSource(beforeStartup) - ) - ); - } - const lastInlinedModule = last(inlinedModules); - const startupSource = new ConcatSource(); - startupSource.add(`var ${RuntimeGlobals.exports} = {};\n`); - for (const m of inlinedModules) { - const renderedModule = this.renderModule( - m, - chunkRenderContext, - hooks, - false - ); - if (renderedModule) { - const innerStrict = !allStrict && m.buildInfo.strict; - const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements( - m, - chunk.runtime - ); - const exports = runtimeRequirements.has(RuntimeGlobals.exports); - const webpackExports = - exports && m.exportsArgument === RuntimeGlobals.exports; - let iife = innerStrict - ? "it need to be in strict mode." - : inlinedModules.size > 1 - ? // TODO check globals and top-level declarations of other entries and chunk modules - // to make a better decision - "it need to be isolated against other entry modules." - : chunkModules - ? "it need to be isolated against other modules in the chunk." - : exports && !webpackExports - ? `it uses a non-standard name for the exports (${m.exportsArgument}).` - : hooks.embedInRuntimeBailout.call(m, renderContext); - let footer; - if (iife !== undefined) { - startupSource.add( - `// This entry need to be wrapped in an IIFE because ${iife}\n` - ); - const arrow = runtimeTemplate.supportsArrowFunction(); - if (arrow) { - startupSource.add("(() => {\n"); - footer = "\n})();\n\n"; - } else { - startupSource.add("!function() {\n"); - footer = "\n}();\n"; - } - if (innerStrict) startupSource.add('"use strict";\n'); - } else { - footer = "\n"; - } - if (exports) { - if (m !== lastInlinedModule) - startupSource.add(`var ${m.exportsArgument} = {};\n`); - else if (m.exportsArgument !== RuntimeGlobals.exports) - startupSource.add( - `var ${m.exportsArgument} = ${RuntimeGlobals.exports};\n` - ); - } - startupSource.add(renderedModule); - startupSource.add(footer); - } - } - if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) { - startupSource.add( - `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});\n` - ); - } - source.add( - hooks.renderStartup.call(startupSource, lastInlinedModule, { - ...renderContext, - inlined: true - }) - ); - if (bootstrap.afterStartup.length > 0) { - const afterStartup = Template.asString(bootstrap.afterStartup) + "\n"; - source.add( - new PrefixSource( - prefix, - useSourceMap - ? new OriginalSource(afterStartup, "webpack/after-startup") - : new RawSource(afterStartup) - ) - ); - } - } else { - const lastEntryModule = last( - chunkGraph.getChunkEntryModulesIterable(chunk) - ); - const toSource = useSourceMap - ? (content, name) => - new OriginalSource(Template.asString(content), name) - : content => new RawSource(Template.asString(content)); - source.add( - new PrefixSource( - prefix, - new ConcatSource( - toSource(bootstrap.beforeStartup, "webpack/before-startup"), - "\n", - hooks.renderStartup.call( - toSource(bootstrap.startup.concat(""), "webpack/startup"), - lastEntryModule, - { - ...renderContext, - inlined: false - } - ), - toSource(bootstrap.afterStartup, "webpack/after-startup"), - "\n" - ) - ) - ); - } - if ( - hasEntryModules && - runtimeRequirements.has(RuntimeGlobals.returnExportsFromRuntime) - ) { - source.add(`${prefix}return ${RuntimeGlobals.exports};\n`); - } - if (iife) { - source.add("/******/ })()\n"); - } - - /** @type {Source} */ - let finalSource = tryRunOrWebpackError( - () => hooks.renderMain.call(source, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderMain" - ); - if (!finalSource) { - throw new Error( - "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderMain plugins should return something" - ); - } - finalSource = tryRunOrWebpackError( - () => hooks.renderContent.call(finalSource, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderContent" - ); - if (!finalSource) { - throw new Error( - "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().renderContent plugins should return something" - ); - } - - finalSource = InitFragment.addToSource( - finalSource, - chunkRenderContext.chunkInitFragments, - chunkRenderContext - ); - finalSource = tryRunOrWebpackError( - () => hooks.render.call(finalSource, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().render" - ); - if (!finalSource) { - throw new Error( - "JavascriptModulesPlugin error: JavascriptModulesPlugin.getCompilationHooks().render plugins should return something" - ); - } - chunk.rendered = true; - return iife ? new ConcatSource(finalSource, ";") : finalSource; - } - - /** - * @param {Hash} hash the hash to be updated - * @param {RenderBootstrapContext} renderContext options object - * @param {CompilationHooks} hooks hooks - */ - updateHashWithBootstrap(hash, renderContext, hooks) { - const bootstrap = this.renderBootstrap(renderContext, hooks); - for (const key of Object.keys(bootstrap)) { - hash.update(key); - if (Array.isArray(bootstrap[key])) { - for (const line of bootstrap[key]) { - hash.update(line); - } - } else { - hash.update(JSON.stringify(bootstrap[key])); - } - } - } - - /** - * @param {RenderBootstrapContext} renderContext options object - * @param {CompilationHooks} hooks hooks - * @returns {{ header: string[], beforeStartup: string[], startup: string[], afterStartup: string[], allowInlineStartup: boolean }} the generated source of the bootstrap code - */ - renderBootstrap(renderContext, hooks) { - const { - chunkGraph, - codeGenerationResults, - moduleGraph, - chunk, - runtimeTemplate - } = renderContext; - - const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk); - - const requireFunction = runtimeRequirements.has(RuntimeGlobals.require); - const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache); - const moduleFactories = runtimeRequirements.has( - RuntimeGlobals.moduleFactories - ); - const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module); - const requireScopeUsed = runtimeRequirements.has( - RuntimeGlobals.requireScope - ); - const interceptModuleExecution = runtimeRequirements.has( - RuntimeGlobals.interceptModuleExecution - ); - - const useRequire = - requireFunction || interceptModuleExecution || moduleUsed; - - /** - * @type {{startup: string[], beforeStartup: string[], header: string[], afterStartup: string[], allowInlineStartup: boolean}} - */ - const result = { - header: [], - beforeStartup: [], - startup: [], - afterStartup: [], - allowInlineStartup: true - }; - - let { header: buf, startup, beforeStartup, afterStartup } = result; - - if (result.allowInlineStartup && moduleFactories) { - startup.push( - "// module factories are used so entry inlining is disabled" - ); - result.allowInlineStartup = false; - } - if (result.allowInlineStartup && moduleCache) { - startup.push("// module cache are used so entry inlining is disabled"); - result.allowInlineStartup = false; - } - if (result.allowInlineStartup && interceptModuleExecution) { - startup.push( - "// module execution is intercepted so entry inlining is disabled" - ); - result.allowInlineStartup = false; - } - - if (useRequire || moduleCache) { - buf.push("// The module cache"); - buf.push("var __webpack_module_cache__ = {};"); - buf.push(""); - } - - if (useRequire) { - buf.push("// The require function"); - buf.push(`function ${RuntimeGlobals.require}(moduleId) {`); - buf.push(Template.indent(this.renderRequire(renderContext, hooks))); - buf.push("}"); - buf.push(""); - } else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) { - buf.push("// The require scope"); - buf.push(`var ${RuntimeGlobals.require} = {};`); - buf.push(""); - } - - if ( - moduleFactories || - runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly) - ) { - buf.push("// expose the modules object (__webpack_modules__)"); - buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`); - buf.push(""); - } - - if (moduleCache) { - buf.push("// expose the module cache"); - buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`); - buf.push(""); - } - - if (interceptModuleExecution) { - buf.push("// expose the module execution interceptor"); - buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`); - buf.push(""); - } - - if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) { - if (chunkGraph.getNumberOfEntryModules(chunk) > 0) { - /** @type {string[]} */ - const buf2 = []; - const runtimeRequirements = - chunkGraph.getTreeRuntimeRequirements(chunk); - buf2.push("// Load entry module and return exports"); - let i = chunkGraph.getNumberOfEntryModules(chunk); - for (const [ - entryModule, - entrypoint - ] of chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)) { - const chunks = entrypoint.chunks.filter(c => c !== chunk); - if (result.allowInlineStartup && chunks.length > 0) { - buf2.push( - "// This entry module depends on other loaded chunks and execution need to be delayed" - ); - result.allowInlineStartup = false; - } - if ( - result.allowInlineStartup && - someInIterable( - moduleGraph.getIncomingConnectionsByOriginModule(entryModule), - ([originModule, connections]) => - originModule && - connections.some(c => c.isTargetActive(chunk.runtime)) && - someInIterable( - chunkGraph.getModuleRuntimes(originModule), - runtime => - intersectRuntime(runtime, chunk.runtime) !== undefined - ) - ) - ) { - buf2.push( - "// This entry module is referenced by other modules so it can't be inlined" - ); - result.allowInlineStartup = false; - } - - let data; - if (codeGenerationResults.has(entryModule, chunk.runtime)) { - const result = codeGenerationResults.get( - entryModule, - chunk.runtime - ); - data = result.data; - } - if ( - result.allowInlineStartup && - (!data || !data.get("topLevelDeclarations")) && - (!entryModule.buildInfo || - !entryModule.buildInfo.topLevelDeclarations) - ) { - buf2.push( - "// This entry module doesn't tell about it's top-level declarations so it can't be inlined" - ); - result.allowInlineStartup = false; - } - if (result.allowInlineStartup) { - const bailout = hooks.inlineInRuntimeBailout.call( - entryModule, - renderContext - ); - if (bailout !== undefined) { - buf2.push( - `// This entry module can't be inlined because ${bailout}` - ); - result.allowInlineStartup = false; - } - } - i--; - const moduleId = chunkGraph.getModuleId(entryModule); - const entryRuntimeRequirements = - chunkGraph.getModuleRuntimeRequirements(entryModule, chunk.runtime); - let moduleIdExpr = JSON.stringify(moduleId); - if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) { - moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`; - } - if ( - result.allowInlineStartup && - entryRuntimeRequirements.has(RuntimeGlobals.module) - ) { - result.allowInlineStartup = false; - buf2.push( - "// This entry module used 'module' so it can't be inlined" - ); - } - if (chunks.length > 0) { - buf2.push( - `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${ - RuntimeGlobals.onChunksLoaded - }(undefined, ${JSON.stringify( - chunks.map(c => c.id) - )}, ${runtimeTemplate.returningFunction( - `${RuntimeGlobals.require}(${moduleIdExpr})` - )})` - ); - } else if (useRequire) { - buf2.push( - `${i === 0 ? `var ${RuntimeGlobals.exports} = ` : ""}${ - RuntimeGlobals.require - }(${moduleIdExpr});` - ); - } else { - if (i === 0) buf2.push(`var ${RuntimeGlobals.exports} = {};`); - if (requireScopeUsed) { - buf2.push( - `__webpack_modules__[${moduleIdExpr}](0, ${ - i === 0 ? RuntimeGlobals.exports : "{}" - }, ${RuntimeGlobals.require});` - ); - } else if (entryRuntimeRequirements.has(RuntimeGlobals.exports)) { - buf2.push( - `__webpack_modules__[${moduleIdExpr}](0, ${ - i === 0 ? RuntimeGlobals.exports : "{}" - });` - ); - } else { - buf2.push(`__webpack_modules__[${moduleIdExpr}]();`); - } - } - } - if (runtimeRequirements.has(RuntimeGlobals.onChunksLoaded)) { - buf2.push( - `${RuntimeGlobals.exports} = ${RuntimeGlobals.onChunksLoaded}(${RuntimeGlobals.exports});` - ); - } - if ( - runtimeRequirements.has(RuntimeGlobals.startup) || - (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) && - runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)) - ) { - result.allowInlineStartup = false; - buf.push("// the startup function"); - buf.push( - `${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction("", [ - ...buf2, - `return ${RuntimeGlobals.exports};` - ])};` - ); - buf.push(""); - startup.push("// run startup"); - startup.push( - `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();` - ); - } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore)) { - buf.push("// the startup function"); - buf.push( - `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};` - ); - beforeStartup.push("// run runtime startup"); - beforeStartup.push(`${RuntimeGlobals.startup}();`); - startup.push("// startup"); - startup.push(Template.asString(buf2)); - } else if (runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter)) { - buf.push("// the startup function"); - buf.push( - `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};` - ); - startup.push("// startup"); - startup.push(Template.asString(buf2)); - afterStartup.push("// run runtime startup"); - afterStartup.push(`${RuntimeGlobals.startup}();`); - } else { - startup.push("// startup"); - startup.push(Template.asString(buf2)); - } - } else if ( - runtimeRequirements.has(RuntimeGlobals.startup) || - runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) || - runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter) - ) { - buf.push( - "// the startup function", - "// It's empty as no entry modules are in this chunk", - `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};`, - "" - ); - } - } else if ( - runtimeRequirements.has(RuntimeGlobals.startup) || - runtimeRequirements.has(RuntimeGlobals.startupOnlyBefore) || - runtimeRequirements.has(RuntimeGlobals.startupOnlyAfter) - ) { - result.allowInlineStartup = false; - buf.push( - "// the startup function", - "// It's empty as some runtime module handles the default behavior", - `${RuntimeGlobals.startup} = ${runtimeTemplate.emptyFunction()};` - ); - startup.push("// run startup"); - startup.push( - `var ${RuntimeGlobals.exports} = ${RuntimeGlobals.startup}();` - ); - } - return result; - } - - /** - * @param {RenderBootstrapContext} renderContext options object - * @param {CompilationHooks} hooks hooks - * @returns {string} the generated source of the require function - */ - renderRequire(renderContext, hooks) { - const { - chunk, - chunkGraph, - runtimeTemplate: { outputOptions } - } = renderContext; - const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk); - const moduleExecution = runtimeRequirements.has( - RuntimeGlobals.interceptModuleExecution - ) - ? Template.asString([ - `var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: ${RuntimeGlobals.require} };`, - `${RuntimeGlobals.interceptModuleExecution}.forEach(function(handler) { handler(execOptions); });`, - "module = execOptions.module;", - "execOptions.factory.call(module.exports, module, module.exports, execOptions.require);" - ]) - : runtimeRequirements.has(RuntimeGlobals.thisAsExports) - ? Template.asString([ - `__webpack_modules__[moduleId].call(module.exports, module, module.exports, ${RuntimeGlobals.require});` - ]) - : Template.asString([ - `__webpack_modules__[moduleId](module, module.exports, ${RuntimeGlobals.require});` - ]); - const needModuleId = runtimeRequirements.has(RuntimeGlobals.moduleId); - const needModuleLoaded = runtimeRequirements.has( - RuntimeGlobals.moduleLoaded - ); - const content = Template.asString([ - "// Check if module is in cache", - "var cachedModule = __webpack_module_cache__[moduleId];", - "if (cachedModule !== undefined) {", - outputOptions.strictModuleErrorHandling - ? Template.indent([ - "if (cachedModule.error !== undefined) throw cachedModule.error;", - "return cachedModule.exports;" - ]) - : Template.indent("return cachedModule.exports;"), - "}", - "// Create a new module (and put it into the cache)", - "var module = __webpack_module_cache__[moduleId] = {", - Template.indent([ - needModuleId ? "id: moduleId," : "// no module.id needed", - needModuleLoaded ? "loaded: false," : "// no module.loaded needed", - "exports: {}" - ]), - "};", - "", - outputOptions.strictModuleExceptionHandling - ? Template.asString([ - "// Execute the module function", - "var threw = true;", - "try {", - Template.indent([moduleExecution, "threw = false;"]), - "} finally {", - Template.indent([ - "if(threw) delete __webpack_module_cache__[moduleId];" - ]), - "}" - ]) - : outputOptions.strictModuleErrorHandling - ? Template.asString([ - "// Execute the module function", - "try {", - Template.indent(moduleExecution), - "} catch(e) {", - Template.indent(["module.error = e;", "throw e;"]), - "}" - ]) - : Template.asString([ - "// Execute the module function", - moduleExecution - ]), - needModuleLoaded - ? Template.asString([ - "", - "// Flag the module as loaded", - `${RuntimeGlobals.moduleLoaded} = true;`, - "" - ]) - : "", - "// Return the exports of the module", - "return module.exports;" - ]); - return tryRunOrWebpackError( - () => hooks.renderRequire.call(content, renderContext), - "JavascriptModulesPlugin.getCompilationHooks().renderRequire" - ); - } -} - -module.exports = JavascriptModulesPlugin; -module.exports.chunkHasJs = chunkHasJs; diff --git a/node_modules/webpack/lib/javascript/JavascriptParser.js b/node_modules/webpack/lib/javascript/JavascriptParser.js deleted file mode 100644 index 827e9bd4..00000000 --- a/node_modules/webpack/lib/javascript/JavascriptParser.js +++ /dev/null @@ -1,4527 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const { Parser: AcornParser } = require("acorn"); -const { importAssertions } = require("acorn-import-assertions"); -const { SyncBailHook, HookMap } = require("tapable"); -const vm = require("vm"); -const Parser = require("../Parser"); -const StackedMap = require("../util/StackedMap"); -const binarySearchBounds = require("../util/binarySearchBounds"); -const memoize = require("../util/memoize"); -const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); - -/** @typedef {import("acorn").Options} AcornOptions */ -/** @typedef {import("estree").AssignmentExpression} AssignmentExpression */ -/** @typedef {import("estree").BinaryExpression} BinaryExpression */ -/** @typedef {import("estree").BlockStatement} BlockStatement */ -/** @typedef {import("estree").SequenceExpression} SequenceExpression */ -/** @typedef {import("estree").CallExpression} CallExpression */ -/** @typedef {import("estree").BaseCallExpression} BaseCallExpression */ -/** @typedef {import("estree").StaticBlock} StaticBlock */ -/** @typedef {import("estree").ImportExpression} ImportExpression */ -/** @typedef {import("estree").ClassDeclaration} ClassDeclaration */ -/** @typedef {import("estree").ForStatement} ForStatement */ -/** @typedef {import("estree").SwitchStatement} SwitchStatement */ -/** @typedef {import("estree").ExportNamedDeclaration} ExportNamedDeclaration */ -/** @typedef {import("estree").ClassExpression} ClassExpression */ -/** @typedef {import("estree").Comment} Comment */ -/** @typedef {import("estree").ConditionalExpression} ConditionalExpression */ -/** @typedef {import("estree").Declaration} Declaration */ -/** @typedef {import("estree").PrivateIdentifier} PrivateIdentifier */ -/** @typedef {import("estree").PropertyDefinition} PropertyDefinition */ -/** @typedef {import("estree").Expression} Expression */ -/** @typedef {import("estree").Identifier} Identifier */ -/** @typedef {import("estree").VariableDeclaration} VariableDeclaration */ -/** @typedef {import("estree").IfStatement} IfStatement */ -/** @typedef {import("estree").LabeledStatement} LabeledStatement */ -/** @typedef {import("estree").Literal} Literal */ -/** @typedef {import("estree").LogicalExpression} LogicalExpression */ -/** @typedef {import("estree").ChainExpression} ChainExpression */ -/** @typedef {import("estree").MemberExpression} MemberExpression */ -/** @typedef {import("estree").YieldExpression} YieldExpression */ -/** @typedef {import("estree").MetaProperty} MetaProperty */ -/** @typedef {import("estree").Property} Property */ -/** @typedef {import("estree").AssignmentPattern} AssignmentPattern */ -/** @typedef {import("estree").ChainElement} ChainElement */ -/** @typedef {import("estree").Pattern} Pattern */ -/** @typedef {import("estree").UpdateExpression} UpdateExpression */ -/** @typedef {import("estree").ObjectExpression} ObjectExpression */ -/** @typedef {import("estree").UnaryExpression} UnaryExpression */ -/** @typedef {import("estree").ArrayExpression} ArrayExpression */ -/** @typedef {import("estree").ArrayPattern} ArrayPattern */ -/** @typedef {import("estree").AwaitExpression} AwaitExpression */ -/** @typedef {import("estree").ThisExpression} ThisExpression */ -/** @typedef {import("estree").RestElement} RestElement */ -/** @typedef {import("estree").ObjectPattern} ObjectPattern */ -/** @typedef {import("estree").SwitchCase} SwitchCase */ -/** @typedef {import("estree").CatchClause} CatchClause */ -/** @typedef {import("estree").VariableDeclarator} VariableDeclarator */ -/** @typedef {import("estree").ForInStatement} ForInStatement */ -/** @typedef {import("estree").ForOfStatement} ForOfStatement */ -/** @typedef {import("estree").ReturnStatement} ReturnStatement */ -/** @typedef {import("estree").WithStatement} WithStatement */ -/** @typedef {import("estree").ThrowStatement} ThrowStatement */ -/** @typedef {import("estree").MethodDefinition} MethodDefinition */ -/** @typedef {import("estree").ModuleDeclaration} ModuleDeclaration */ -/** @typedef {import("estree").NewExpression} NewExpression */ -/** @typedef {import("estree").SpreadElement} SpreadElement */ -/** @typedef {import("estree").FunctionExpression} FunctionExpression */ -/** @typedef {import("estree").WhileStatement} WhileStatement */ -/** @typedef {import("estree").ArrowFunctionExpression} ArrowFunctionExpression */ -/** @typedef {import("estree").ExpressionStatement} ExpressionStatement */ -/** @typedef {import("estree").FunctionDeclaration} FunctionDeclaration */ -/** @typedef {import("estree").DoWhileStatement} DoWhileStatement */ -/** @typedef {import("estree").TryStatement} TryStatement */ -/** @typedef {import("estree").Node} AnyNode */ -/** @typedef {import("estree").Program} Program */ -/** @typedef {import("estree").Directive} Directive */ -/** @typedef {import("estree").Statement} Statement */ -/** @typedef {import("estree").ImportDeclaration} ImportDeclaration */ -/** @typedef {import("estree").ExportDefaultDeclaration} ExportDefaultDeclaration */ -/** @typedef {import("estree").ExportAllDeclaration} ExportAllDeclaration */ -/** @typedef {import("estree").Super} Super */ -/** @typedef {import("estree").TaggedTemplateExpression} TaggedTemplateExpression */ -/** @typedef {import("estree").TemplateLiteral} TemplateLiteral */ -/** @typedef {Record<string, any>} Assertions */ -/** @template T @typedef {import("tapable").AsArray<T>} AsArray<T> */ -/** @typedef {import("../Parser").ParserState} ParserState */ -/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */ -/** @typedef {{declaredScope: ScopeInfo, freeName: string | true, tagInfo: TagInfo | undefined}} VariableInfoInterface */ -/** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[] }} GetInfoResult */ - -const EMPTY_ARRAY = []; -const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01; -const ALLOWED_MEMBER_TYPES_EXPRESSION = 0b10; -const ALLOWED_MEMBER_TYPES_ALL = 0b11; - -// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API - -const parser = AcornParser.extend(importAssertions); - -class VariableInfo { - /** - * @param {ScopeInfo} declaredScope scope in which the variable is declared - * @param {string | true | undefined} freeName which free name the variable aliases, or true when none - * @param {TagInfo | undefined} tagInfo info about tags - */ - constructor(declaredScope, freeName, tagInfo) { - this.declaredScope = declaredScope; - this.freeName = freeName; - this.tagInfo = tagInfo; - } -} - -/** @typedef {string | ScopeInfo | VariableInfo} ExportedVariableInfo */ -/** @typedef {Literal | string | null | undefined} ImportSource */ -/** @typedef {Omit<AcornOptions, "sourceType" | "ecmaVersion"> & { sourceType: "module" | "script" | "auto", ecmaVersion?: AcornOptions["ecmaVersion"] }} ParseOptions */ - -/** - * @typedef {Object} TagInfo - * @property {any} tag - * @property {any} data - * @property {TagInfo | undefined} next - */ - -/** - * @typedef {Object} ScopeInfo - * @property {StackedMap<string, VariableInfo | ScopeInfo>} definitions - * @property {boolean | "arrow"} topLevelScope - * @property {boolean | string} inShorthand - * @property {boolean} inTaggedTemplateTag - * @property {boolean} inTry - * @property {boolean} isStrict - * @property {boolean} isAsmJs - */ - -/** @typedef {[number, number]} Range */ - -/** - * Helper function for joining two ranges into a single range. This is useful - * when working with AST nodes, as it allows you to combine the ranges of child nodes - * to create the range of the _parent node_. - * - * @param {[number, number]} startRange start range to join - * @param {[number, number]} endRange end range to join - * @returns {[number, number]} joined range - * - * @example - * ```js - * const startRange = [0, 5]; - * const endRange = [10, 15]; - * const joinedRange = joinRanges(startRange, endRange); - * console.log(joinedRange); // [0, 15] - * ``` - * - */ -const joinRanges = (startRange, endRange) => { - if (!endRange) return startRange; - if (!startRange) return endRange; - return [startRange[0], endRange[1]]; -}; - -/** - * Helper function used to generate a string representation of a - * [member expression](https://github.com/estree/estree/blob/master/es5.md#memberexpression). - * - * @param {string} object object to name - * @param {string[]} membersReversed reversed list of members - * @returns {string} member expression as a string - * @example - * ```js - * const membersReversed = ["property1", "property2", "property3"]; // Members parsed from the AST - * const name = objectAndMembersToName("myObject", membersReversed); - * - * console.log(name); // "myObject.property1.property2.property3" - * ``` - * - */ -const objectAndMembersToName = (object, membersReversed) => { - let name = object; - for (let i = membersReversed.length - 1; i >= 0; i--) { - name = name + "." + membersReversed[i]; - } - return name; -}; - -/** - * Grabs the name of a given expression and returns it as a string or undefined. Has particular - * handling for [Identifiers](https://github.com/estree/estree/blob/master/es5.md#identifier), - * [ThisExpressions](https://github.com/estree/estree/blob/master/es5.md#identifier), and - * [MetaProperties](https://github.com/estree/estree/blob/master/es2015.md#metaproperty) which is - * specifically for handling the `new.target` meta property. - * - * @param {Expression | Super} expression expression - * @returns {string | "this" | undefined} name or variable info - */ -const getRootName = expression => { - switch (expression.type) { - case "Identifier": - return expression.name; - case "ThisExpression": - return "this"; - case "MetaProperty": - return `${expression.meta.name}.${expression.property.name}`; - default: - return undefined; - } -}; - -/** @type {AcornOptions} */ -const defaultParserOptions = { - ranges: true, - locations: true, - ecmaVersion: "latest", - sourceType: "module", - // https://github.com/tc39/proposal-hashbang - allowHashBang: true, - onComment: null -}; - -// regexp to match at least one "magic comment" -const webpackCommentRegExp = new RegExp(/(^|\W)webpack[A-Z]{1,}[A-Za-z]{1,}:/); - -const EMPTY_COMMENT_OPTIONS = { - options: null, - errors: null -}; - -class JavascriptParser extends Parser { - /** - * @param {"module" | "script" | "auto"} sourceType default source type - */ - constructor(sourceType = "auto") { - super(); - this.hooks = Object.freeze({ - /** @type {HookMap<SyncBailHook<[UnaryExpression], BasicEvaluatedExpression | undefined | null>>} */ - evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap<SyncBailHook<[Expression], BasicEvaluatedExpression | undefined | null>>} */ - evaluate: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap<SyncBailHook<[Identifier | ThisExpression | MemberExpression | MetaProperty], BasicEvaluatedExpression | undefined | null>>} */ - evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap<SyncBailHook<[Identifier | ThisExpression | MemberExpression], BasicEvaluatedExpression | undefined | null>>} */ - evaluateDefinedIdentifier: new HookMap( - () => new SyncBailHook(["expression"]) - ), - /** @type {HookMap<SyncBailHook<[NewExpression], BasicEvaluatedExpression | undefined | null>>} */ - evaluateNewExpression: new HookMap( - () => new SyncBailHook(["expression"]) - ), - /** @type {HookMap<SyncBailHook<[CallExpression], BasicEvaluatedExpression | undefined | null>>} */ - evaluateCallExpression: new HookMap( - () => new SyncBailHook(["expression"]) - ), - /** @type {HookMap<SyncBailHook<[CallExpression, BasicEvaluatedExpression | undefined], BasicEvaluatedExpression | undefined | null>>} */ - evaluateCallExpressionMember: new HookMap( - () => new SyncBailHook(["expression", "param"]) - ), - /** @type {HookMap<SyncBailHook<[Expression | Declaration | PrivateIdentifier, number], boolean | void>>} */ - isPure: new HookMap( - () => new SyncBailHook(["expression", "commentsStartPosition"]) - ), - /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */ - preStatement: new SyncBailHook(["statement"]), - - /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */ - blockPreStatement: new SyncBailHook(["declaration"]), - /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */ - statement: new SyncBailHook(["statement"]), - /** @type {SyncBailHook<[IfStatement], boolean | void>} */ - statementIf: new SyncBailHook(["statement"]), - /** @type {SyncBailHook<[Expression, ClassExpression | ClassDeclaration], boolean | void>} */ - classExtendsExpression: new SyncBailHook([ - "expression", - "classDefinition" - ]), - /** @type {SyncBailHook<[MethodDefinition | PropertyDefinition | StaticBlock, ClassExpression | ClassDeclaration], boolean | void>} */ - classBodyElement: new SyncBailHook(["element", "classDefinition"]), - /** @type {SyncBailHook<[Expression, MethodDefinition | PropertyDefinition, ClassExpression | ClassDeclaration], boolean | void>} */ - classBodyValue: new SyncBailHook([ - "expression", - "element", - "classDefinition" - ]), - /** @type {HookMap<SyncBailHook<[LabeledStatement], boolean | void>>} */ - label: new HookMap(() => new SyncBailHook(["statement"])), - /** @type {SyncBailHook<[ImportDeclaration, ImportSource], boolean | void>} */ - import: new SyncBailHook(["statement", "source"]), - /** @type {SyncBailHook<[ImportDeclaration, ImportSource, string, string], boolean | void>} */ - importSpecifier: new SyncBailHook([ - "statement", - "source", - "exportName", - "identifierName" - ]), - /** @type {SyncBailHook<[ExportNamedDeclaration | ExportAllDeclaration], boolean | void>} */ - export: new SyncBailHook(["statement"]), - /** @type {SyncBailHook<[ExportNamedDeclaration | ExportAllDeclaration, ImportSource], boolean | void>} */ - exportImport: new SyncBailHook(["statement", "source"]), - /** @type {SyncBailHook<[ExportNamedDeclaration | ExportAllDeclaration, Declaration], boolean | void>} */ - exportDeclaration: new SyncBailHook(["statement", "declaration"]), - /** @type {SyncBailHook<[ExportDefaultDeclaration, Declaration], boolean | void>} */ - exportExpression: new SyncBailHook(["statement", "declaration"]), - /** @type {SyncBailHook<[ExportNamedDeclaration | ExportAllDeclaration, string, string, number | undefined], boolean | void>} */ - exportSpecifier: new SyncBailHook([ - "statement", - "identifierName", - "exportName", - "index" - ]), - /** @type {SyncBailHook<[ExportNamedDeclaration | ExportAllDeclaration, ImportSource, string, string, number | undefined], boolean | void>} */ - exportImportSpecifier: new SyncBailHook([ - "statement", - "source", - "identifierName", - "exportName", - "index" - ]), - /** @type {SyncBailHook<[VariableDeclarator, Statement], boolean | void>} */ - preDeclarator: new SyncBailHook(["declarator", "statement"]), - /** @type {SyncBailHook<[VariableDeclarator, Statement], boolean | void>} */ - declarator: new SyncBailHook(["declarator", "statement"]), - /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */ - varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])), - /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */ - varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])), - /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */ - varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])), - /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */ - varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])), - /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */ - pattern: new HookMap(() => new SyncBailHook(["pattern"])), - /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */ - canRename: new HookMap(() => new SyncBailHook(["initExpression"])), - /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */ - rename: new HookMap(() => new SyncBailHook(["initExpression"])), - /** @type {HookMap<SyncBailHook<[AssignmentExpression], boolean | void>>} */ - assign: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap<SyncBailHook<[AssignmentExpression, string[]], boolean | void>>} */ - assignMemberChain: new HookMap( - () => new SyncBailHook(["expression", "members"]) - ), - /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */ - typeof: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {SyncBailHook<[ImportExpression], boolean | void>} */ - importCall: new SyncBailHook(["expression"]), - /** @type {SyncBailHook<[Expression], boolean | void>} */ - topLevelAwait: new SyncBailHook(["expression"]), - /** @type {HookMap<SyncBailHook<[CallExpression], boolean | void>>} */ - call: new HookMap(() => new SyncBailHook(["expression"])), - /** Something like "a.b()" */ - /** @type {HookMap<SyncBailHook<[CallExpression, string[], boolean[], Range[]], boolean | void>>} */ - callMemberChain: new HookMap( - () => - new SyncBailHook([ - "expression", - "members", - "membersOptionals", - "memberRanges" - ]) - ), - /** Something like "a.b().c.d" */ - /** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[], Range[]], boolean | void>>} */ - memberChainOfCallMemberChain: new HookMap( - () => - new SyncBailHook([ - "expression", - "calleeMembers", - "callExpression", - "members", - "memberRanges" - ]) - ), - /** Something like "a.b().c.d()"" */ - /** @type {HookMap<SyncBailHook<[CallExpression, string[], CallExpression, string[], Range[]], boolean | void>>} */ - callMemberChainOfCallMemberChain: new HookMap( - () => - new SyncBailHook([ - "expression", - "calleeMembers", - "innerCallExpression", - "members", - "memberRanges" - ]) - ), - /** @type {SyncBailHook<[ChainExpression], boolean | void>} */ - optionalChaining: new SyncBailHook(["optionalChaining"]), - /** @type {HookMap<SyncBailHook<[NewExpression], boolean | void>>} */ - new: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {SyncBailHook<[BinaryExpression], boolean | void>} */ - binaryExpression: new SyncBailHook(["binaryExpression"]), - /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */ - expression: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap<SyncBailHook<[MemberExpression, string[], boolean[], Range[]], boolean | void>>} */ - expressionMemberChain: new HookMap( - () => - new SyncBailHook([ - "expression", - "members", - "membersOptionals", - "memberRanges" - ]) - ), - /** @type {HookMap<SyncBailHook<[MemberExpression, string[]], boolean | void>>} */ - unhandledExpressionMemberChain: new HookMap( - () => new SyncBailHook(["expression", "members"]) - ), - /** @type {SyncBailHook<[ConditionalExpression], boolean | void>} */ - expressionConditionalOperator: new SyncBailHook(["expression"]), - /** @type {SyncBailHook<[LogicalExpression], boolean | void>} */ - expressionLogicalOperator: new SyncBailHook(["expression"]), - /** @type {SyncBailHook<[Program, Comment[]], boolean | void>} */ - program: new SyncBailHook(["ast", "comments"]), - /** @type {SyncBailHook<[Program, Comment[]], boolean | void>} */ - finish: new SyncBailHook(["ast", "comments"]) - }); - this.sourceType = sourceType; - /** @type {ScopeInfo} */ - this.scope = undefined; - /** @type {ParserState} */ - this.state = undefined; - this.comments = undefined; - this.semicolons = undefined; - /** @type {(Statement | ModuleDeclaration | Expression)[]} */ - this.statementPath = undefined; - /** @type {Statement | ModuleDeclaration | Expression | undefined} */ - this.prevStatement = undefined; - /** @type {WeakMap<Expression, Set<string>>} */ - this.destructuringAssignmentProperties = undefined; - this.currentTagData = undefined; - this._initializeEvaluating(); - } - - _initializeEvaluating() { - this.hooks.evaluate.for("Literal").tap("JavascriptParser", _expr => { - const expr = /** @type {Literal} */ (_expr); - - switch (typeof expr.value) { - case "number": - return new BasicEvaluatedExpression() - .setNumber(expr.value) - .setRange(/** @type {Range} */ (expr.range)); - case "bigint": - return new BasicEvaluatedExpression() - .setBigInt(expr.value) - .setRange(/** @type {Range} */ (expr.range)); - case "string": - return new BasicEvaluatedExpression() - .setString(expr.value) - .setRange(/** @type {Range} */ (expr.range)); - case "boolean": - return new BasicEvaluatedExpression() - .setBoolean(expr.value) - .setRange(/** @type {Range} */ (expr.range)); - } - if (expr.value === null) { - return new BasicEvaluatedExpression() - .setNull() - .setRange(/** @type {Range} */ (expr.range)); - } - if (expr.value instanceof RegExp) { - return new BasicEvaluatedExpression() - .setRegExp(expr.value) - .setRange(/** @type {Range} */ (expr.range)); - } - }); - this.hooks.evaluate.for("NewExpression").tap("JavascriptParser", _expr => { - const expr = /** @type {NewExpression} */ (_expr); - const callee = expr.callee; - if (callee.type !== "Identifier") return; - if (callee.name !== "RegExp") { - return this.callHooksForName( - this.hooks.evaluateNewExpression, - callee.name, - expr - ); - } else if ( - expr.arguments.length > 2 || - this.getVariableInfo("RegExp") !== "RegExp" - ) - return; - - let regExp, flags; - const arg1 = expr.arguments[0]; - - if (arg1) { - if (arg1.type === "SpreadElement") return; - - const evaluatedRegExp = this.evaluateExpression(arg1); - - if (!evaluatedRegExp) return; - - regExp = evaluatedRegExp.asString(); - - if (!regExp) return; - } else { - return new BasicEvaluatedExpression() - .setRegExp(new RegExp("")) - .setRange(/** @type {Range} */ (expr.range)); - } - - const arg2 = expr.arguments[1]; - - if (arg2) { - if (arg2.type === "SpreadElement") return; - - const evaluatedFlags = this.evaluateExpression(arg2); - - if (!evaluatedFlags) return; - - if (!evaluatedFlags.isUndefined()) { - flags = evaluatedFlags.asString(); - - if ( - flags === undefined || - !BasicEvaluatedExpression.isValidRegExpFlags(flags) - ) - return; - } - } - - return new BasicEvaluatedExpression() - .setRegExp(flags ? new RegExp(regExp, flags) : new RegExp(regExp)) - .setRange(/** @type {Range} */ (expr.range)); - }); - this.hooks.evaluate - .for("LogicalExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {LogicalExpression} */ (_expr); - - const left = this.evaluateExpression(expr.left); - let returnRight = false; - /** @type {boolean|undefined} */ - let allowedRight; - if (expr.operator === "&&") { - const leftAsBool = left.asBool(); - if (leftAsBool === false) return left.setRange(expr.range); - returnRight = leftAsBool === true; - allowedRight = false; - } else if (expr.operator === "||") { - const leftAsBool = left.asBool(); - if (leftAsBool === true) return left.setRange(expr.range); - returnRight = leftAsBool === false; - allowedRight = true; - } else if (expr.operator === "??") { - const leftAsNullish = left.asNullish(); - if (leftAsNullish === false) return left.setRange(expr.range); - if (leftAsNullish !== true) return; - returnRight = true; - } else return; - const right = this.evaluateExpression(expr.right); - if (returnRight) { - if (left.couldHaveSideEffects()) right.setSideEffects(); - return right.setRange(expr.range); - } - - const asBool = right.asBool(); - - if (allowedRight === true && asBool === true) { - return new BasicEvaluatedExpression() - .setRange(expr.range) - .setTruthy(); - } else if (allowedRight === false && asBool === false) { - return new BasicEvaluatedExpression().setRange(expr.range).setFalsy(); - } - }); - - /** - * In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on - * either side of a [BinaryExpression](https://github.com/estree/estree/blob/master/es5.md#binaryexpression). - * This supports scenarios in webpack like conditionally `import()`'ing modules based on some simple evaluation: - * - * ```js - * if (1 === 3) { - * import("./moduleA"); // webpack will auto evaluate this and not import the modules - * } - * ``` - * - * Additional scenarios include evaluation of strings inside of dynamic import statements: - * - * ```js - * const foo = "foo"; - * const bar = "bar"; - * - * import("./" + foo + bar); // webpack will auto evaluate this into import("./foobar") - * ``` - * @param {boolean | number | BigInt | string} value the value to convert to an expression - * @param {BinaryExpression | UnaryExpression} expr the expression being evaluated - * @param {boolean} sideEffects whether the expression has side effects - * @returns {BasicEvaluatedExpression | undefined} the evaluated expression - * @example - * - * ```js - * const binaryExpr = new BinaryExpression("+", - * { type: "Literal", value: 2 }, - * { type: "Literal", value: 3 } - * ); - * - * const leftValue = 2; - * const rightValue = 3; - * - * const leftExpr = valueAsExpression(leftValue, binaryExpr.left, false); - * const rightExpr = valueAsExpression(rightValue, binaryExpr.right, false); - * const result = new BasicEvaluatedExpression() - * .setNumber(leftExpr.number + rightExpr.number) - * .setRange(binaryExpr.range); - * - * console.log(result.number); // Output: 5 - * ``` - */ - const valueAsExpression = (value, expr, sideEffects) => { - switch (typeof value) { - case "boolean": - return new BasicEvaluatedExpression() - .setBoolean(value) - .setSideEffects(sideEffects) - .setRange(/** @type {Range} */ (expr.range)); - case "number": - return new BasicEvaluatedExpression() - .setNumber(value) - .setSideEffects(sideEffects) - .setRange(/** @type {Range} */ (expr.range)); - case "bigint": - return new BasicEvaluatedExpression() - .setBigInt(value) - .setSideEffects(sideEffects) - .setRange(/** @type {Range} */ (expr.range)); - case "string": - return new BasicEvaluatedExpression() - .setString(value) - .setSideEffects(sideEffects) - .setRange(/** @type {Range} */ (expr.range)); - } - }; - - this.hooks.evaluate - .for("BinaryExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {BinaryExpression} */ (_expr); - - /** - * Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.). - * - * @template T - * @param {(leftOperand: T, rightOperand: T) => boolean | number | BigInt | string} operandHandler the handler for the operation (e.g. (a, b) => a + b) - * @returns {BasicEvaluatedExpression | undefined} the evaluated expression - */ - const handleConstOperation = operandHandler => { - const left = this.evaluateExpression(expr.left); - if (!left.isCompileTimeValue()) return; - - const right = this.evaluateExpression(expr.right); - if (!right.isCompileTimeValue()) return; - - const result = operandHandler( - left.asCompileTimeValue(), - right.asCompileTimeValue() - ); - return valueAsExpression( - result, - expr, - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - }; - - /** - * Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison` - * to determine if an expressions boolean or nullish conversion is equal or not. - * - * @param {boolean} a first boolean to compare - * @param {boolean} b second boolean to compare - * @returns {boolean} true if the two booleans are always different, false otherwise - */ - const isAlwaysDifferent = (a, b) => - (a === true && b === false) || (a === false && b === true); - - const handleTemplateStringCompare = (left, right, res, eql) => { - const getPrefix = parts => { - let value = ""; - for (const p of parts) { - const v = p.asString(); - if (v !== undefined) value += v; - else break; - } - return value; - }; - const getSuffix = parts => { - let value = ""; - for (let i = parts.length - 1; i >= 0; i--) { - const v = parts[i].asString(); - if (v !== undefined) value = v + value; - else break; - } - return value; - }; - const leftPrefix = getPrefix(left.parts); - const rightPrefix = getPrefix(right.parts); - const leftSuffix = getSuffix(left.parts); - const rightSuffix = getSuffix(right.parts); - const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length); - const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length); - const prefixMismatch = - lenPrefix > 0 && - leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix); - const suffixMismatch = - lenSuffix > 0 && - leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix); - if (prefixMismatch || suffixMismatch) { - return res - .setBoolean(!eql) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - }; - - /** - * Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!=="). - * @param {boolean} eql true for "===" and false for "!==" - * @returns {BasicEvaluatedExpression | undefined} the evaluated expression - */ - const handleStrictEqualityComparison = eql => { - const left = this.evaluateExpression(expr.left); - const right = this.evaluateExpression(expr.right); - const res = new BasicEvaluatedExpression(); - res.setRange(/** @type {Range} */ (expr.range)); - - const leftConst = left.isCompileTimeValue(); - const rightConst = right.isCompileTimeValue(); - - if (leftConst && rightConst) { - return res - .setBoolean( - eql === - (left.asCompileTimeValue() === right.asCompileTimeValue()) - ) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - - if (left.isArray() && right.isArray()) { - return res - .setBoolean(!eql) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - if (left.isTemplateString() && right.isTemplateString()) { - return handleTemplateStringCompare(left, right, res, eql); - } - - const leftPrimitive = left.isPrimitiveType(); - const rightPrimitive = right.isPrimitiveType(); - - if ( - // Primitive !== Object or - // compile-time object types are never equal to something at runtime - (leftPrimitive === false && - (leftConst || rightPrimitive === true)) || - (rightPrimitive === false && - (rightConst || leftPrimitive === true)) || - // Different nullish or boolish status also means not equal - isAlwaysDifferent( - /** @type {boolean} */ (left.asBool()), - /** @type {boolean} */ (right.asBool()) - ) || - isAlwaysDifferent( - /** @type {boolean} */ (left.asNullish()), - /** @type {boolean} */ (right.asNullish()) - ) - ) { - return res - .setBoolean(!eql) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - }; - - /** - * Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!="). - * @param {boolean} eql true for "==" and false for "!=" - * @returns {BasicEvaluatedExpression | undefined} the evaluated expression - */ - const handleAbstractEqualityComparison = eql => { - const left = this.evaluateExpression(expr.left); - const right = this.evaluateExpression(expr.right); - const res = new BasicEvaluatedExpression(); - res.setRange(expr.range); - - const leftConst = left.isCompileTimeValue(); - const rightConst = right.isCompileTimeValue(); - - if (leftConst && rightConst) { - return res - .setBoolean( - eql === - // eslint-disable-next-line eqeqeq - (left.asCompileTimeValue() == right.asCompileTimeValue()) - ) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - - if (left.isArray() && right.isArray()) { - return res - .setBoolean(!eql) - .setSideEffects( - left.couldHaveSideEffects() || right.couldHaveSideEffects() - ); - } - if (left.isTemplateString() && right.isTemplateString()) { - return handleTemplateStringCompare(left, right, res, eql); - } - }; - - if (expr.operator === "+") { - const left = this.evaluateExpression(expr.left); - const right = this.evaluateExpression(expr.right); - const res = new BasicEvaluatedExpression(); - if (left.isString()) { - if (right.isString()) { - res.setString(left.string + right.string); - } else if (right.isNumber()) { - res.setString(left.string + right.number); - } else if ( - right.isWrapped() && - right.prefix && - right.prefix.isString() - ) { - // "left" + ("prefix" + inner + "postfix") - // => ("leftPrefix" + inner + "postfix") - res.setWrapped( - new BasicEvaluatedExpression() - .setString(left.string + right.prefix.string) - .setRange(joinRanges(left.range, right.prefix.range)), - right.postfix, - right.wrappedInnerExpressions - ); - } else if (right.isWrapped()) { - // "left" + ([null] + inner + "postfix") - // => ("left" + inner + "postfix") - res.setWrapped( - left, - right.postfix, - right.wrappedInnerExpressions - ); - } else { - // "left" + expr - // => ("left" + expr + "") - res.setWrapped(left, null, [right]); - } - } else if (left.isNumber()) { - if (right.isString()) { - res.setString(left.number + right.string); - } else if (right.isNumber()) { - res.setNumber(left.number + right.number); - } else { - return; - } - } else if (left.isBigInt()) { - if (right.isBigInt()) { - res.setBigInt(left.bigint + right.bigint); - } - } else if (left.isWrapped()) { - if (left.postfix && left.postfix.isString() && right.isString()) { - // ("prefix" + inner + "postfix") + "right" - // => ("prefix" + inner + "postfixRight") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(left.postfix.string + right.string) - .setRange(joinRanges(left.postfix.range, right.range)), - left.wrappedInnerExpressions - ); - } else if ( - left.postfix && - left.postfix.isString() && - right.isNumber() - ) { - // ("prefix" + inner + "postfix") + 123 - // => ("prefix" + inner + "postfix123") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(left.postfix.string + right.number) - .setRange(joinRanges(left.postfix.range, right.range)), - left.wrappedInnerExpressions - ); - } else if (right.isString()) { - // ("prefix" + inner + [null]) + "right" - // => ("prefix" + inner + "right") - res.setWrapped(left.prefix, right, left.wrappedInnerExpressions); - } else if (right.isNumber()) { - // ("prefix" + inner + [null]) + 123 - // => ("prefix" + inner + "123") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(right.number + "") - .setRange(right.range), - left.wrappedInnerExpressions - ); - } else if (right.isWrapped()) { - // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2") - // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2") - res.setWrapped( - left.prefix, - right.postfix, - left.wrappedInnerExpressions && - right.wrappedInnerExpressions && - left.wrappedInnerExpressions - .concat(left.postfix ? [left.postfix] : []) - .concat(right.prefix ? [right.prefix] : []) - .concat(right.wrappedInnerExpressions) - ); - } else { - // ("prefix" + inner + postfix) + expr - // => ("prefix" + inner + postfix + expr + [null]) - res.setWrapped( - left.prefix, - null, - left.wrappedInnerExpressions && - left.wrappedInnerExpressions.concat( - left.postfix ? [left.postfix, right] : [right] - ) - ); - } - } else { - if (right.isString()) { - // left + "right" - // => ([null] + left + "right") - res.setWrapped(null, right, [left]); - } else if (right.isWrapped()) { - // left + (prefix + inner + "postfix") - // => ([null] + left + prefix + inner + "postfix") - res.setWrapped( - null, - right.postfix, - right.wrappedInnerExpressions && - (right.prefix ? [left, right.prefix] : [left]).concat( - right.wrappedInnerExpressions - ) - ); - } else { - return; - } - } - if (left.couldHaveSideEffects() || right.couldHaveSideEffects()) - res.setSideEffects(); - res.setRange(expr.range); - return res; - } else if (expr.operator === "-") { - return handleConstOperation((l, r) => l - r); - } else if (expr.operator === "*") { - return handleConstOperation((l, r) => l * r); - } else if (expr.operator === "/") { - return handleConstOperation((l, r) => l / r); - } else if (expr.operator === "**") { - return handleConstOperation((l, r) => l ** r); - } else if (expr.operator === "===") { - return handleStrictEqualityComparison(true); - } else if (expr.operator === "==") { - return handleAbstractEqualityComparison(true); - } else if (expr.operator === "!==") { - return handleStrictEqualityComparison(false); - } else if (expr.operator === "!=") { - return handleAbstractEqualityComparison(false); - } else if (expr.operator === "&") { - return handleConstOperation((l, r) => l & r); - } else if (expr.operator === "|") { - return handleConstOperation((l, r) => l | r); - } else if (expr.operator === "^") { - return handleConstOperation((l, r) => l ^ r); - } else if (expr.operator === ">>>") { - return handleConstOperation((l, r) => l >>> r); - } else if (expr.operator === ">>") { - return handleConstOperation((l, r) => l >> r); - } else if (expr.operator === "<<") { - return handleConstOperation((l, r) => l << r); - } else if (expr.operator === "<") { - return handleConstOperation((l, r) => l < r); - } else if (expr.operator === ">") { - return handleConstOperation((l, r) => l > r); - } else if (expr.operator === "<=") { - return handleConstOperation((l, r) => l <= r); - } else if (expr.operator === ">=") { - return handleConstOperation((l, r) => l >= r); - } - }); - this.hooks.evaluate - .for("UnaryExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {UnaryExpression} */ (_expr); - - /** - * Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a). - * - * @template T - * @param {(operand: T) => boolean | number | BigInt | string} operandHandler handler for the operand - * @returns {BasicEvaluatedExpression | undefined} evaluated expression - */ - const handleConstOperation = operandHandler => { - const argument = this.evaluateExpression(expr.argument); - if (!argument.isCompileTimeValue()) return; - const result = operandHandler(argument.asCompileTimeValue()); - return valueAsExpression( - result, - expr, - argument.couldHaveSideEffects() - ); - }; - - if (expr.operator === "typeof") { - switch (expr.argument.type) { - case "Identifier": { - const res = this.callHooksForName( - this.hooks.evaluateTypeof, - expr.argument.name, - expr - ); - if (res !== undefined) return res; - break; - } - case "MetaProperty": { - const res = this.callHooksForName( - this.hooks.evaluateTypeof, - getRootName(expr.argument), - expr - ); - if (res !== undefined) return res; - break; - } - case "MemberExpression": { - const res = this.callHooksForExpression( - this.hooks.evaluateTypeof, - expr.argument, - expr - ); - if (res !== undefined) return res; - break; - } - case "ChainExpression": { - const res = this.callHooksForExpression( - this.hooks.evaluateTypeof, - expr.argument.expression, - expr - ); - if (res !== undefined) return res; - break; - } - case "FunctionExpression": { - return new BasicEvaluatedExpression() - .setString("function") - .setRange(expr.range); - } - } - const arg = this.evaluateExpression(expr.argument); - if (arg.isUnknown()) return; - if (arg.isString()) { - return new BasicEvaluatedExpression() - .setString("string") - .setRange(expr.range); - } - if (arg.isWrapped()) { - return new BasicEvaluatedExpression() - .setString("string") - .setSideEffects() - .setRange(expr.range); - } - if (arg.isUndefined()) { - return new BasicEvaluatedExpression() - .setString("undefined") - .setRange(expr.range); - } - if (arg.isNumber()) { - return new BasicEvaluatedExpression() - .setString("number") - .setRange(expr.range); - } - if (arg.isBigInt()) { - return new BasicEvaluatedExpression() - .setString("bigint") - .setRange(expr.range); - } - if (arg.isBoolean()) { - return new BasicEvaluatedExpression() - .setString("boolean") - .setRange(expr.range); - } - if (arg.isConstArray() || arg.isRegExp() || arg.isNull()) { - return new BasicEvaluatedExpression() - .setString("object") - .setRange(expr.range); - } - if (arg.isArray()) { - return new BasicEvaluatedExpression() - .setString("object") - .setSideEffects(arg.couldHaveSideEffects()) - .setRange(expr.range); - } - } else if (expr.operator === "!") { - const argument = this.evaluateExpression(expr.argument); - const bool = argument.asBool(); - if (typeof bool !== "boolean") return; - return new BasicEvaluatedExpression() - .setBoolean(!bool) - .setSideEffects(argument.couldHaveSideEffects()) - .setRange(expr.range); - } else if (expr.operator === "~") { - return handleConstOperation(v => ~v); - } else if (expr.operator === "+") { - return handleConstOperation(v => +v); - } else if (expr.operator === "-") { - return handleConstOperation(v => -v); - } - }); - this.hooks.evaluateTypeof.for("undefined").tap("JavascriptParser", expr => { - return new BasicEvaluatedExpression() - .setString("undefined") - .setRange(expr.range); - }); - this.hooks.evaluate.for("Identifier").tap("JavascriptParser", expr => { - if (/** @type {Identifier} */ (expr).name === "undefined") { - return new BasicEvaluatedExpression() - .setUndefined() - .setRange(expr.range); - } - }); - /** - * @param {string} exprType expression type name - * @param {function(Expression): GetInfoResult | undefined} getInfo get info - * @returns {void} - */ - const tapEvaluateWithVariableInfo = (exprType, getInfo) => { - /** @type {Expression | undefined} */ - let cachedExpression = undefined; - /** @type {GetInfoResult | undefined} */ - let cachedInfo = undefined; - this.hooks.evaluate.for(exprType).tap("JavascriptParser", expr => { - const expression = /** @type {MemberExpression} */ (expr); - - const info = getInfo(expr); - if (info !== undefined) { - return this.callHooksForInfoWithFallback( - this.hooks.evaluateIdentifier, - info.name, - name => { - cachedExpression = expression; - cachedInfo = info; - }, - name => { - const hook = this.hooks.evaluateDefinedIdentifier.get(name); - if (hook !== undefined) { - return hook.call(expression); - } - }, - expression - ); - } - }); - this.hooks.evaluate - .for(exprType) - .tap({ name: "JavascriptParser", stage: 100 }, expr => { - const info = cachedExpression === expr ? cachedInfo : getInfo(expr); - if (info !== undefined) { - return new BasicEvaluatedExpression() - .setIdentifier( - info.name, - info.rootInfo, - info.getMembers, - info.getMembersOptionals, - info.getMemberRanges - ) - .setRange(expr.range); - } - }); - this.hooks.finish.tap("JavascriptParser", () => { - // Cleanup for GC - cachedExpression = cachedInfo = undefined; - }); - }; - tapEvaluateWithVariableInfo("Identifier", expr => { - const info = this.getVariableInfo(/** @type {Identifier} */ (expr).name); - if ( - typeof info === "string" || - (info instanceof VariableInfo && typeof info.freeName === "string") - ) { - return { - name: info, - rootInfo: info, - getMembers: () => [], - getMembersOptionals: () => [], - getMemberRanges: () => [] - }; - } - }); - tapEvaluateWithVariableInfo("ThisExpression", expr => { - const info = this.getVariableInfo("this"); - if ( - typeof info === "string" || - (info instanceof VariableInfo && typeof info.freeName === "string") - ) { - return { - name: info, - rootInfo: info, - getMembers: () => [], - getMembersOptionals: () => [], - getMemberRanges: () => [] - }; - } - }); - this.hooks.evaluate.for("MetaProperty").tap("JavascriptParser", expr => { - const metaProperty = /** @type {MetaProperty} */ (expr); - - return this.callHooksForName( - this.hooks.evaluateIdentifier, - getRootName(expr), - metaProperty - ); - }); - tapEvaluateWithVariableInfo("MemberExpression", expr => - this.getMemberExpressionInfo( - /** @type {MemberExpression} */ (expr), - ALLOWED_MEMBER_TYPES_EXPRESSION - ) - ); - - this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", _expr => { - const expr = /** @type {CallExpression} */ (_expr); - if ( - expr.callee.type === "MemberExpression" && - expr.callee.property.type === - (expr.callee.computed ? "Literal" : "Identifier") - ) { - // type Super also possible here - const param = this.evaluateExpression( - /** @type {Expression} */ (expr.callee.object) - ); - const property = - expr.callee.property.type === "Literal" - ? `${expr.callee.property.value}` - : expr.callee.property.name; - const hook = this.hooks.evaluateCallExpressionMember.get(property); - if (hook !== undefined) { - return hook.call(expr, param); - } - } else if (expr.callee.type === "Identifier") { - return this.callHooksForName( - this.hooks.evaluateCallExpression, - expr.callee.name, - expr - ); - } - }); - this.hooks.evaluateCallExpressionMember - .for("indexOf") - .tap("JavascriptParser", (expr, param) => { - if (!param.isString()) return; - if (expr.arguments.length === 0) return; - const [arg1, arg2] = expr.arguments; - if (arg1.type === "SpreadElement") return; - const arg1Eval = this.evaluateExpression(arg1); - if (!arg1Eval.isString()) return; - const arg1Value = arg1Eval.string; - - let result; - if (arg2) { - if (arg2.type === "SpreadElement") return; - const arg2Eval = this.evaluateExpression(arg2); - if (!arg2Eval.isNumber()) return; - result = param.string.indexOf(arg1Value, arg2Eval.number); - } else { - result = param.string.indexOf(arg1Value); - } - return new BasicEvaluatedExpression() - .setNumber(result) - .setSideEffects(param.couldHaveSideEffects()) - .setRange(expr.range); - }); - this.hooks.evaluateCallExpressionMember - .for("replace") - .tap("JavascriptParser", (expr, param) => { - if (!param.isString()) return; - if (expr.arguments.length !== 2) return; - if (expr.arguments[0].type === "SpreadElement") return; - if (expr.arguments[1].type === "SpreadElement") return; - let arg1 = this.evaluateExpression(expr.arguments[0]); - let arg2 = this.evaluateExpression(expr.arguments[1]); - if (!arg1.isString() && !arg1.isRegExp()) return; - const arg1Value = arg1.regExp || arg1.string; - if (!arg2.isString()) return; - const arg2Value = arg2.string; - return new BasicEvaluatedExpression() - .setString(param.string.replace(arg1Value, arg2Value)) - .setSideEffects(param.couldHaveSideEffects()) - .setRange(expr.range); - }); - ["substr", "substring", "slice"].forEach(fn => { - this.hooks.evaluateCallExpressionMember - .for(fn) - .tap("JavascriptParser", (expr, param) => { - if (!param.isString()) return; - let arg1; - let result, - str = param.string; - switch (expr.arguments.length) { - case 1: - if (expr.arguments[0].type === "SpreadElement") return; - arg1 = this.evaluateExpression(expr.arguments[0]); - if (!arg1.isNumber()) return; - result = str[fn](arg1.number); - break; - case 2: { - if (expr.arguments[0].type === "SpreadElement") return; - if (expr.arguments[1].type === "SpreadElement") return; - arg1 = this.evaluateExpression(expr.arguments[0]); - const arg2 = this.evaluateExpression(expr.arguments[1]); - if (!arg1.isNumber()) return; - if (!arg2.isNumber()) return; - result = str[fn](arg1.number, arg2.number); - break; - } - default: - return; - } - return new BasicEvaluatedExpression() - .setString(result) - .setSideEffects(param.couldHaveSideEffects()) - .setRange(expr.range); - }); - }); - - /** - * @param {"cooked" | "raw"} kind kind of values to get - * @param {TemplateLiteral} templateLiteralExpr TemplateLiteral expr - * @returns {{quasis: BasicEvaluatedExpression[], parts: BasicEvaluatedExpression[]}} Simplified template - */ - const getSimplifiedTemplateResult = (kind, templateLiteralExpr) => { - /** @type {BasicEvaluatedExpression[]} */ - const quasis = []; - /** @type {BasicEvaluatedExpression[]} */ - const parts = []; - - for (let i = 0; i < templateLiteralExpr.quasis.length; i++) { - const quasiExpr = templateLiteralExpr.quasis[i]; - const quasi = quasiExpr.value[kind]; - - if (i > 0) { - const prevExpr = parts[parts.length - 1]; - const expr = this.evaluateExpression( - templateLiteralExpr.expressions[i - 1] - ); - const exprAsString = expr.asString(); - if ( - typeof exprAsString === "string" && - !expr.couldHaveSideEffects() - ) { - // We can merge quasi + expr + quasi when expr - // is a const string - - prevExpr.setString(prevExpr.string + exprAsString + quasi); - prevExpr.setRange([prevExpr.range[0], quasiExpr.range[1]]); - // We unset the expression as it doesn't match to a single expression - prevExpr.setExpression(undefined); - continue; - } - parts.push(expr); - } - - const part = new BasicEvaluatedExpression() - .setString(quasi) - .setRange(/** @type {Range} */ (quasiExpr.range)) - .setExpression(quasiExpr); - quasis.push(part); - parts.push(part); - } - return { - quasis, - parts - }; - }; - - this.hooks.evaluate - .for("TemplateLiteral") - .tap("JavascriptParser", _node => { - const node = /** @type {TemplateLiteral} */ (_node); - - const { quasis, parts } = getSimplifiedTemplateResult("cooked", node); - if (parts.length === 1) { - return parts[0].setRange(/** @type {Range} */ (node.range)); - } - return new BasicEvaluatedExpression() - .setTemplateString(quasis, parts, "cooked") - .setRange(/** @type {Range} */ (node.range)); - }); - this.hooks.evaluate - .for("TaggedTemplateExpression") - .tap("JavascriptParser", _node => { - const node = /** @type {TaggedTemplateExpression} */ (_node); - const tag = this.evaluateExpression(node.tag); - - if (tag.isIdentifier() && tag.identifier === "String.raw") { - const { quasis, parts } = getSimplifiedTemplateResult( - "raw", - node.quasi - ); - return new BasicEvaluatedExpression() - .setTemplateString(quasis, parts, "raw") - .setRange(/** @type {Range} */ (node.range)); - } - }); - - this.hooks.evaluateCallExpressionMember - .for("concat") - .tap("JavascriptParser", (expr, param) => { - if (!param.isString() && !param.isWrapped()) return; - - let stringSuffix = null; - let hasUnknownParams = false; - const innerExpressions = []; - for (let i = expr.arguments.length - 1; i >= 0; i--) { - const arg = expr.arguments[i]; - if (arg.type === "SpreadElement") return; - const argExpr = this.evaluateExpression(arg); - if ( - hasUnknownParams || - (!argExpr.isString() && !argExpr.isNumber()) - ) { - hasUnknownParams = true; - innerExpressions.push(argExpr); - continue; - } - - const value = argExpr.isString() - ? argExpr.string - : "" + argExpr.number; - - const newString = value + (stringSuffix ? stringSuffix.string : ""); - const newRange = /** @type {Range} */ ([ - argExpr.range[0], - (stringSuffix || argExpr).range[1] - ]); - stringSuffix = new BasicEvaluatedExpression() - .setString(newString) - .setSideEffects( - (stringSuffix && stringSuffix.couldHaveSideEffects()) || - argExpr.couldHaveSideEffects() - ) - .setRange(newRange); - } - - if (hasUnknownParams) { - const prefix = param.isString() ? param : param.prefix; - const inner = - param.isWrapped() && param.wrappedInnerExpressions - ? param.wrappedInnerExpressions.concat(innerExpressions.reverse()) - : innerExpressions.reverse(); - return new BasicEvaluatedExpression() - .setWrapped(prefix, stringSuffix, inner) - .setRange(expr.range); - } else if (param.isWrapped()) { - const postfix = stringSuffix || param.postfix; - const inner = param.wrappedInnerExpressions - ? param.wrappedInnerExpressions.concat(innerExpressions.reverse()) - : innerExpressions.reverse(); - return new BasicEvaluatedExpression() - .setWrapped(param.prefix, postfix, inner) - .setRange(expr.range); - } else { - const newString = - param.string + (stringSuffix ? stringSuffix.string : ""); - return new BasicEvaluatedExpression() - .setString(newString) - .setSideEffects( - (stringSuffix && stringSuffix.couldHaveSideEffects()) || - param.couldHaveSideEffects() - ) - .setRange(expr.range); - } - }); - this.hooks.evaluateCallExpressionMember - .for("split") - .tap("JavascriptParser", (expr, param) => { - if (!param.isString()) return; - if (expr.arguments.length !== 1) return; - if (expr.arguments[0].type === "SpreadElement") return; - let result; - const arg = this.evaluateExpression(expr.arguments[0]); - if (arg.isString()) { - result = param.string.split(arg.string); - } else if (arg.isRegExp()) { - result = param.string.split(arg.regExp); - } else { - return; - } - return new BasicEvaluatedExpression() - .setArray(result) - .setSideEffects(param.couldHaveSideEffects()) - .setRange(/** @type {Range} */ (expr.range)); - }); - this.hooks.evaluate - .for("ConditionalExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {ConditionalExpression} */ (_expr); - - const condition = this.evaluateExpression(expr.test); - const conditionValue = condition.asBool(); - let res; - if (conditionValue === undefined) { - const consequent = this.evaluateExpression(expr.consequent); - const alternate = this.evaluateExpression(expr.alternate); - res = new BasicEvaluatedExpression(); - if (consequent.isConditional()) { - res.setOptions( - /** @type {BasicEvaluatedExpression[]} */ (consequent.options) - ); - } else { - res.setOptions([consequent]); - } - if (alternate.isConditional()) { - res.addOptions( - /** @type {BasicEvaluatedExpression[]} */ (alternate.options) - ); - } else { - res.addOptions([alternate]); - } - } else { - res = this.evaluateExpression( - conditionValue ? expr.consequent : expr.alternate - ); - if (condition.couldHaveSideEffects()) res.setSideEffects(); - } - res.setRange(/** @type {Range} */ (expr.range)); - return res; - }); - this.hooks.evaluate - .for("ArrayExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {ArrayExpression} */ (_expr); - - const items = expr.elements.map(element => { - return ( - element !== null && - element.type !== "SpreadElement" && - this.evaluateExpression(element) - ); - }); - if (!items.every(Boolean)) return; - return new BasicEvaluatedExpression() - .setItems(items) - .setRange(/** @type {Range} */ (expr.range)); - }); - this.hooks.evaluate - .for("ChainExpression") - .tap("JavascriptParser", _expr => { - const expr = /** @type {ChainExpression} */ (_expr); - /** @type {Expression[]} */ - const optionalExpressionsStack = []; - /** @type {Expression|Super} */ - let next = expr.expression; - - while ( - next.type === "MemberExpression" || - next.type === "CallExpression" - ) { - if (next.type === "MemberExpression") { - if (next.optional) { - // SuperNode can not be optional - optionalExpressionsStack.push( - /** @type {Expression} */ (next.object) - ); - } - next = next.object; - } else { - if (next.optional) { - // SuperNode can not be optional - optionalExpressionsStack.push( - /** @type {Expression} */ (next.callee) - ); - } - next = next.callee; - } - } - - while (optionalExpressionsStack.length > 0) { - const expression = - /** @type {Expression} */ - (optionalExpressionsStack.pop()); - const evaluated = this.evaluateExpression(expression); - - if (evaluated.asNullish()) { - return evaluated.setRange(/** @type {Range} */ (_expr.range)); - } - } - return this.evaluateExpression(expr.expression); - }); - } - - /** - * @param {Expression} node node - * @returns {Set<string>|undefined} destructured identifiers - */ - destructuringAssignmentPropertiesFor(node) { - if (!this.destructuringAssignmentProperties) return undefined; - return this.destructuringAssignmentProperties.get(node); - } - - /** - * @param {Expression} expr expression - * @returns {string | VariableInfoInterface | undefined} identifier - */ - getRenameIdentifier(expr) { - const result = this.evaluateExpression(expr); - if (result.isIdentifier()) { - return result.identifier; - } - } - - /** - * @param {ClassExpression | ClassDeclaration} classy a class node - * @returns {void} - */ - walkClass(classy) { - if (classy.superClass) { - if (!this.hooks.classExtendsExpression.call(classy.superClass, classy)) { - this.walkExpression(classy.superClass); - } - } - if (classy.body && classy.body.type === "ClassBody") { - const scopeParams = []; - // Add class name in scope for recursive calls - if (classy.id) { - scopeParams.push(classy.id); - } - this.inClassScope(true, scopeParams, () => { - for (const classElement of /** @type {TODO} */ (classy.body.body)) { - if (!this.hooks.classBodyElement.call(classElement, classy)) { - if (classElement.computed && classElement.key) { - this.walkExpression(classElement.key); - } - if (classElement.value) { - if ( - !this.hooks.classBodyValue.call( - classElement.value, - classElement, - classy - ) - ) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - this.walkExpression(classElement.value); - this.scope.topLevelScope = wasTopLevel; - } - } else if (classElement.type === "StaticBlock") { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - this.walkBlockStatement(classElement); - this.scope.topLevelScope = wasTopLevel; - } - } - } - }); - } - } - - /** - * Pre walking iterates the scope for variable declarations - * - * @param {(Statement | ModuleDeclaration)[]} statements statements - */ - preWalkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.preWalkStatement(statement); - } - } - - /** - * Block pre walking iterates the scope for block variable declarations - * - * @param {(Statement | ModuleDeclaration)[]} statements statements - */ - blockPreWalkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.blockPreWalkStatement(statement); - } - } - - /** - * Walking iterates the statements and expressions and processes them - * - * @param {(Statement | ModuleDeclaration)[]} statements statements - */ - walkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.walkStatement(statement); - } - } - - /** - * Walking iterates the statements and expressions and processes them - * - * @param {Statement | ModuleDeclaration} statement statement - */ - preWalkStatement(statement) { - this.statementPath.push(statement); - if (this.hooks.preStatement.call(statement)) { - this.prevStatement = this.statementPath.pop(); - return; - } - switch (statement.type) { - case "BlockStatement": - this.preWalkBlockStatement(statement); - break; - case "DoWhileStatement": - this.preWalkDoWhileStatement(statement); - break; - case "ForInStatement": - this.preWalkForInStatement(statement); - break; - case "ForOfStatement": - this.preWalkForOfStatement(statement); - break; - case "ForStatement": - this.preWalkForStatement(statement); - break; - case "FunctionDeclaration": - this.preWalkFunctionDeclaration(statement); - break; - case "IfStatement": - this.preWalkIfStatement(statement); - break; - case "LabeledStatement": - this.preWalkLabeledStatement(statement); - break; - case "SwitchStatement": - this.preWalkSwitchStatement(statement); - break; - case "TryStatement": - this.preWalkTryStatement(statement); - break; - case "VariableDeclaration": - this.preWalkVariableDeclaration(statement); - break; - case "WhileStatement": - this.preWalkWhileStatement(statement); - break; - case "WithStatement": - this.preWalkWithStatement(statement); - break; - } - this.prevStatement = this.statementPath.pop(); - } - - /** - * @param {Statement | ModuleDeclaration} statement statement - */ - blockPreWalkStatement(statement) { - this.statementPath.push(statement); - if (this.hooks.blockPreStatement.call(statement)) { - this.prevStatement = this.statementPath.pop(); - return; - } - switch (statement.type) { - case "ImportDeclaration": - this.blockPreWalkImportDeclaration(statement); - break; - case "ExportAllDeclaration": - this.blockPreWalkExportAllDeclaration(statement); - break; - case "ExportDefaultDeclaration": - this.blockPreWalkExportDefaultDeclaration(statement); - break; - case "ExportNamedDeclaration": - this.blockPreWalkExportNamedDeclaration(statement); - break; - case "VariableDeclaration": - this.blockPreWalkVariableDeclaration(statement); - break; - case "ClassDeclaration": - this.blockPreWalkClassDeclaration(statement); - break; - case "ExpressionStatement": - this.blockPreWalkExpressionStatement(statement); - } - this.prevStatement = this.statementPath.pop(); - } - - /** - * @param {Statement | ModuleDeclaration} statement statement - */ - walkStatement(statement) { - this.statementPath.push(statement); - if (this.hooks.statement.call(statement) !== undefined) { - this.prevStatement = this.statementPath.pop(); - return; - } - switch (statement.type) { - case "BlockStatement": - this.walkBlockStatement(statement); - break; - case "ClassDeclaration": - this.walkClassDeclaration(statement); - break; - case "DoWhileStatement": - this.walkDoWhileStatement(statement); - break; - case "ExportDefaultDeclaration": - this.walkExportDefaultDeclaration(statement); - break; - case "ExportNamedDeclaration": - this.walkExportNamedDeclaration(statement); - break; - case "ExpressionStatement": - this.walkExpressionStatement(statement); - break; - case "ForInStatement": - this.walkForInStatement(statement); - break; - case "ForOfStatement": - this.walkForOfStatement(statement); - break; - case "ForStatement": - this.walkForStatement(statement); - break; - case "FunctionDeclaration": - this.walkFunctionDeclaration(statement); - break; - case "IfStatement": - this.walkIfStatement(statement); - break; - case "LabeledStatement": - this.walkLabeledStatement(statement); - break; - case "ReturnStatement": - this.walkReturnStatement(statement); - break; - case "SwitchStatement": - this.walkSwitchStatement(statement); - break; - case "ThrowStatement": - this.walkThrowStatement(statement); - break; - case "TryStatement": - this.walkTryStatement(statement); - break; - case "VariableDeclaration": - this.walkVariableDeclaration(statement); - break; - case "WhileStatement": - this.walkWhileStatement(statement); - break; - case "WithStatement": - this.walkWithStatement(statement); - break; - } - this.prevStatement = this.statementPath.pop(); - } - - /** - * Walks a statements that is nested within a parent statement - * and can potentially be a non-block statement. - * This enforces the nested statement to never be in ASI position. - * - * @param {Statement} statement the nested statement - */ - walkNestedStatement(statement) { - this.prevStatement = undefined; - this.walkStatement(statement); - } - - // Real Statements - /** - * @param {BlockStatement} statement block statement - */ - preWalkBlockStatement(statement) { - this.preWalkStatements(statement.body); - } - - /** - * @param {BlockStatement} statement block statement - */ - walkBlockStatement(statement) { - this.inBlockScope(() => { - const body = statement.body; - const prev = this.prevStatement; - this.blockPreWalkStatements(body); - this.prevStatement = prev; - this.walkStatements(body); - }); - } - - /** - * @param {ExpressionStatement} statement expression statement - */ - walkExpressionStatement(statement) { - this.walkExpression(statement.expression); - } - - /** - * @param {IfStatement} statement if statement - */ - preWalkIfStatement(statement) { - this.preWalkStatement(statement.consequent); - if (statement.alternate) { - this.preWalkStatement(statement.alternate); - } - } - - /** - * @param {IfStatement} statement if statement - */ - walkIfStatement(statement) { - const result = this.hooks.statementIf.call(statement); - if (result === undefined) { - this.walkExpression(statement.test); - this.walkNestedStatement(statement.consequent); - if (statement.alternate) { - this.walkNestedStatement(statement.alternate); - } - } else { - if (result) { - this.walkNestedStatement(statement.consequent); - } else if (statement.alternate) { - this.walkNestedStatement(statement.alternate); - } - } - } - - /** - * @param {LabeledStatement} statement with statement - */ - preWalkLabeledStatement(statement) { - this.preWalkStatement(statement.body); - } - - /** - * @param {LabeledStatement} statement with statement - */ - walkLabeledStatement(statement) { - const hook = this.hooks.label.get(statement.label.name); - if (hook !== undefined) { - const result = hook.call(statement); - if (result === true) return; - } - this.walkNestedStatement(statement.body); - } - - /** - * @param {WithStatement} statement with statement - */ - preWalkWithStatement(statement) { - this.preWalkStatement(statement.body); - } - - /** - * @param {WithStatement} statement with statement - */ - walkWithStatement(statement) { - this.walkExpression(statement.object); - this.walkNestedStatement(statement.body); - } - - /** - * @param {SwitchStatement} statement switch statement - */ - preWalkSwitchStatement(statement) { - this.preWalkSwitchCases(statement.cases); - } - - /** - * @param {SwitchStatement} statement switch statement - */ - walkSwitchStatement(statement) { - this.walkExpression(statement.discriminant); - this.walkSwitchCases(statement.cases); - } - - /** - * @param {ReturnStatement | ThrowStatement} statement return or throw statement - */ - walkTerminatingStatement(statement) { - if (statement.argument) this.walkExpression(statement.argument); - } - - /** - * @param {ReturnStatement} statement return statement - */ - walkReturnStatement(statement) { - this.walkTerminatingStatement(statement); - } - - /** - * @param {ThrowStatement} statement return statement - */ - walkThrowStatement(statement) { - this.walkTerminatingStatement(statement); - } - - /** - * @param {TryStatement} statement try statement - */ - preWalkTryStatement(statement) { - this.preWalkStatement(statement.block); - if (statement.handler) this.preWalkCatchClause(statement.handler); - if (statement.finalizer) this.preWalkStatement(statement.finalizer); - } - - /** - * @param {TryStatement} statement try statement - */ - walkTryStatement(statement) { - if (this.scope.inTry) { - this.walkStatement(statement.block); - } else { - this.scope.inTry = true; - this.walkStatement(statement.block); - this.scope.inTry = false; - } - if (statement.handler) this.walkCatchClause(statement.handler); - if (statement.finalizer) this.walkStatement(statement.finalizer); - } - - /** - * @param {WhileStatement} statement while statement - */ - preWalkWhileStatement(statement) { - this.preWalkStatement(statement.body); - } - - /** - * @param {WhileStatement} statement while statement - */ - walkWhileStatement(statement) { - this.walkExpression(statement.test); - this.walkNestedStatement(statement.body); - } - - /** - * @param {DoWhileStatement} statement do while statement - */ - preWalkDoWhileStatement(statement) { - this.preWalkStatement(statement.body); - } - - /** - * @param {DoWhileStatement} statement do while statement - */ - walkDoWhileStatement(statement) { - this.walkNestedStatement(statement.body); - this.walkExpression(statement.test); - } - - /** - * @param {ForStatement} statement for statement - */ - preWalkForStatement(statement) { - if (statement.init) { - if (statement.init.type === "VariableDeclaration") { - this.preWalkStatement(statement.init); - } - } - this.preWalkStatement(statement.body); - } - - /** - * @param {ForStatement} statement for statement - */ - walkForStatement(statement) { - this.inBlockScope(() => { - if (statement.init) { - if (statement.init.type === "VariableDeclaration") { - this.blockPreWalkVariableDeclaration(statement.init); - this.prevStatement = undefined; - this.walkStatement(statement.init); - } else { - this.walkExpression(statement.init); - } - } - if (statement.test) { - this.walkExpression(statement.test); - } - if (statement.update) { - this.walkExpression(statement.update); - } - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - const prev = this.prevStatement; - this.blockPreWalkStatements(body.body); - this.prevStatement = prev; - this.walkStatements(body.body); - } else { - this.walkNestedStatement(body); - } - }); - } - - /** - * @param {ForInStatement} statement for statement - */ - preWalkForInStatement(statement) { - if (statement.left.type === "VariableDeclaration") { - this.preWalkVariableDeclaration(statement.left); - } - this.preWalkStatement(statement.body); - } - - /** - * @param {ForInStatement} statement for statement - */ - walkForInStatement(statement) { - this.inBlockScope(() => { - if (statement.left.type === "VariableDeclaration") { - this.blockPreWalkVariableDeclaration(statement.left); - this.walkVariableDeclaration(statement.left); - } else { - this.walkPattern(statement.left); - } - this.walkExpression(statement.right); - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - const prev = this.prevStatement; - this.blockPreWalkStatements(body.body); - this.prevStatement = prev; - this.walkStatements(body.body); - } else { - this.walkNestedStatement(body); - } - }); - } - - preWalkForOfStatement(statement) { - if (statement.await && this.scope.topLevelScope === true) { - this.hooks.topLevelAwait.call(statement); - } - if (statement.left.type === "VariableDeclaration") { - this.preWalkVariableDeclaration(statement.left); - } - this.preWalkStatement(statement.body); - } - - /** - * @param {ForOfStatement} statement for statement - */ - walkForOfStatement(statement) { - this.inBlockScope(() => { - if (statement.left.type === "VariableDeclaration") { - this.blockPreWalkVariableDeclaration(statement.left); - this.walkVariableDeclaration(statement.left); - } else { - this.walkPattern(statement.left); - } - this.walkExpression(statement.right); - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - const prev = this.prevStatement; - this.blockPreWalkStatements(body.body); - this.prevStatement = prev; - this.walkStatements(body.body); - } else { - this.walkNestedStatement(body); - } - }); - } - - /** - * @param {FunctionDeclaration} statement function declaration - */ - preWalkFunctionDeclaration(statement) { - if (statement.id) { - this.defineVariable(statement.id.name); - } - } - - /** - * @param {FunctionDeclaration} statement function declaration - */ - walkFunctionDeclaration(statement) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - this.inFunctionScope(true, statement.params, () => { - for (const param of statement.params) { - this.walkPattern(param); - } - if (statement.body.type === "BlockStatement") { - this.detectMode(statement.body.body); - const prev = this.prevStatement; - this.preWalkStatement(statement.body); - this.prevStatement = prev; - this.walkStatement(statement.body); - } else { - this.walkExpression(statement.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - /** - * @param {ExpressionStatement} statement expression statement - */ - blockPreWalkExpressionStatement(statement) { - const expression = statement.expression; - switch (expression.type) { - case "AssignmentExpression": - this.preWalkAssignmentExpression(expression); - } - } - - /** - * @param {AssignmentExpression} expression assignment expression - */ - preWalkAssignmentExpression(expression) { - if ( - expression.left.type !== "ObjectPattern" || - !this.destructuringAssignmentProperties - ) - return; - const keys = this._preWalkObjectPattern(expression.left); - if (!keys) return; - - // check multiple assignments - if (this.destructuringAssignmentProperties.has(expression)) { - const set = this.destructuringAssignmentProperties.get(expression); - this.destructuringAssignmentProperties.delete(expression); - for (const id of set) keys.add(id); - } - - this.destructuringAssignmentProperties.set( - expression.right.type === "AwaitExpression" - ? expression.right.argument - : expression.right, - keys - ); - - if (expression.right.type === "AssignmentExpression") { - this.preWalkAssignmentExpression(expression.right); - } - } - - blockPreWalkImportDeclaration(statement) { - const source = statement.source.value; - this.hooks.import.call(statement, source); - for (const specifier of statement.specifiers) { - const name = specifier.local.name; - switch (specifier.type) { - case "ImportDefaultSpecifier": - if ( - !this.hooks.importSpecifier.call(statement, source, "default", name) - ) { - this.defineVariable(name); - } - break; - case "ImportSpecifier": - if ( - !this.hooks.importSpecifier.call( - statement, - source, - specifier.imported.name || specifier.imported.value, - name - ) - ) { - this.defineVariable(name); - } - break; - case "ImportNamespaceSpecifier": - if (!this.hooks.importSpecifier.call(statement, source, null, name)) { - this.defineVariable(name); - } - break; - default: - this.defineVariable(name); - } - } - } - - enterDeclaration(declaration, onIdent) { - switch (declaration.type) { - case "VariableDeclaration": - for (const declarator of declaration.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - this.enterPattern(declarator.id, onIdent); - break; - } - } - } - break; - case "FunctionDeclaration": - this.enterPattern(declaration.id, onIdent); - break; - case "ClassDeclaration": - this.enterPattern(declaration.id, onIdent); - break; - } - } - - blockPreWalkExportNamedDeclaration(statement) { - let source; - if (statement.source) { - source = statement.source.value; - this.hooks.exportImport.call(statement, source); - } else { - this.hooks.export.call(statement); - } - if (statement.declaration) { - if ( - !this.hooks.exportDeclaration.call(statement, statement.declaration) - ) { - const prev = this.prevStatement; - this.preWalkStatement(statement.declaration); - this.prevStatement = prev; - this.blockPreWalkStatement(statement.declaration); - let index = 0; - this.enterDeclaration(statement.declaration, def => { - this.hooks.exportSpecifier.call(statement, def, def, index++); - }); - } - } - if (statement.specifiers) { - for ( - let specifierIndex = 0; - specifierIndex < statement.specifiers.length; - specifierIndex++ - ) { - const specifier = statement.specifiers[specifierIndex]; - switch (specifier.type) { - case "ExportSpecifier": { - const name = specifier.exported.name || specifier.exported.value; - if (source) { - this.hooks.exportImportSpecifier.call( - statement, - source, - specifier.local.name, - name, - specifierIndex - ); - } else { - this.hooks.exportSpecifier.call( - statement, - specifier.local.name, - name, - specifierIndex - ); - } - break; - } - } - } - } - } - - /** - * @param {ExportNamedDeclaration} statement the statement - */ - walkExportNamedDeclaration(statement) { - if (statement.declaration) { - this.walkStatement(statement.declaration); - } - } - - blockPreWalkExportDefaultDeclaration(statement) { - const prev = this.prevStatement; - this.preWalkStatement(statement.declaration); - this.prevStatement = prev; - this.blockPreWalkStatement(statement.declaration); - if ( - statement.declaration.id && - statement.declaration.type !== "FunctionExpression" && - statement.declaration.type !== "ClassExpression" - ) { - this.hooks.exportSpecifier.call( - statement, - statement.declaration.id.name, - "default", - undefined - ); - } - } - - walkExportDefaultDeclaration(statement) { - this.hooks.export.call(statement); - if ( - statement.declaration.id && - statement.declaration.type !== "FunctionExpression" && - statement.declaration.type !== "ClassExpression" - ) { - if ( - !this.hooks.exportDeclaration.call(statement, statement.declaration) - ) { - this.walkStatement(statement.declaration); - } - } else { - // Acorn parses `export default function() {}` as `FunctionDeclaration` and - // `export default class {}` as `ClassDeclaration`, both with `id = null`. - // These nodes must be treated as expressions. - if ( - statement.declaration.type === "FunctionDeclaration" || - statement.declaration.type === "ClassDeclaration" - ) { - this.walkStatement(statement.declaration); - } else { - this.walkExpression(statement.declaration); - } - if (!this.hooks.exportExpression.call(statement, statement.declaration)) { - this.hooks.exportSpecifier.call( - statement, - statement.declaration, - "default", - undefined - ); - } - } - } - - blockPreWalkExportAllDeclaration(statement) { - const source = statement.source.value; - const name = statement.exported ? statement.exported.name : null; - this.hooks.exportImport.call(statement, source); - this.hooks.exportImportSpecifier.call(statement, source, null, name, 0); - } - - /** - * @param {VariableDeclaration} statement variable declaration - */ - preWalkVariableDeclaration(statement) { - if (statement.kind !== "var") return; - this._preWalkVariableDeclaration(statement, this.hooks.varDeclarationVar); - } - - /** - * @param {VariableDeclaration} statement variable declaration - */ - blockPreWalkVariableDeclaration(statement) { - if (statement.kind === "var") return; - const hookMap = - statement.kind === "const" - ? this.hooks.varDeclarationConst - : this.hooks.varDeclarationLet; - this._preWalkVariableDeclaration(statement, hookMap); - } - - /** - * @param {VariableDeclaration} statement variable declaration - * @param {TODO} hookMap map of hooks - */ - _preWalkVariableDeclaration(statement, hookMap) { - for (const declarator of statement.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - this.preWalkVariableDeclarator(declarator); - if (!this.hooks.preDeclarator.call(declarator, statement)) { - this.enterPattern(declarator.id, (name, decl) => { - let hook = hookMap.get(name); - if (hook === undefined || !hook.call(decl)) { - hook = this.hooks.varDeclaration.get(name); - if (hook === undefined || !hook.call(decl)) { - this.defineVariable(name); - } - } - }); - } - break; - } - } - } - } - - /** - * @param {ObjectPattern} objectPattern object pattern - * @returns {Set<string> | undefined} set of names or undefined if not all keys are identifiers - */ - _preWalkObjectPattern(objectPattern) { - const ids = new Set(); - const properties = objectPattern.properties; - for (let i = 0; i < properties.length; i++) { - const property = properties[i]; - if (property.type !== "Property") return; - const key = property.key; - if (key.type === "Identifier") { - ids.add(key.name); - } else { - const id = this.evaluateExpression(key); - const str = id.asString(); - if (str) { - ids.add(str); - } else { - // could not evaluate key - return; - } - } - } - - return ids; - } - - /** - * @param {VariableDeclarator} declarator variable declarator - */ - preWalkVariableDeclarator(declarator) { - if ( - !declarator.init || - declarator.id.type !== "ObjectPattern" || - !this.destructuringAssignmentProperties - ) - return; - const keys = this._preWalkObjectPattern(declarator.id); - - if (!keys) return; - this.destructuringAssignmentProperties.set( - declarator.init.type === "AwaitExpression" - ? declarator.init.argument - : declarator.init, - keys - ); - - if (declarator.init.type === "AssignmentExpression") { - this.preWalkAssignmentExpression(declarator.init); - } - } - - /** - * @param {VariableDeclaration} statement variable declaration - */ - walkVariableDeclaration(statement) { - for (const declarator of statement.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - const renameIdentifier = - declarator.init && this.getRenameIdentifier(declarator.init); - if (renameIdentifier && declarator.id.type === "Identifier") { - const hook = this.hooks.canRename.get(renameIdentifier); - if (hook !== undefined && hook.call(declarator.init)) { - // renaming with "var a = b;" - const hook = this.hooks.rename.get(renameIdentifier); - if (hook === undefined || !hook.call(declarator.init)) { - this.setVariable(declarator.id.name, renameIdentifier); - } - break; - } - } - if (!this.hooks.declarator.call(declarator, statement)) { - this.walkPattern(declarator.id); - if (declarator.init) this.walkExpression(declarator.init); - } - break; - } - } - } - } - - /** - * @param {ClassDeclaration} statement class declaration - */ - blockPreWalkClassDeclaration(statement) { - if (statement.id) { - this.defineVariable(statement.id.name); - } - } - - /** - * @param {ClassDeclaration} statement class declaration - */ - walkClassDeclaration(statement) { - this.walkClass(statement); - } - - /** - * @param {SwitchCase[]} switchCases switch statement - */ - preWalkSwitchCases(switchCases) { - for (let index = 0, len = switchCases.length; index < len; index++) { - const switchCase = switchCases[index]; - this.preWalkStatements(switchCase.consequent); - } - } - - /** - * @param {SwitchCase[]} switchCases switch statement - */ - walkSwitchCases(switchCases) { - this.inBlockScope(() => { - const len = switchCases.length; - - // we need to pre walk all statements first since we can have invalid code - // import A from "module"; - // switch(1) { - // case 1: - // console.log(A); // should fail at runtime - // case 2: - // const A = 1; - // } - for (let index = 0; index < len; index++) { - const switchCase = switchCases[index]; - - if (switchCase.consequent.length > 0) { - const prev = this.prevStatement; - this.blockPreWalkStatements(switchCase.consequent); - this.prevStatement = prev; - } - } - - for (let index = 0; index < len; index++) { - const switchCase = switchCases[index]; - - if (switchCase.test) { - this.walkExpression(switchCase.test); - } - if (switchCase.consequent.length > 0) { - this.walkStatements(switchCase.consequent); - } - } - }); - } - - /** - * @param {CatchClause} catchClause catch clause - */ - preWalkCatchClause(catchClause) { - this.preWalkStatement(catchClause.body); - } - - /** - * @param {CatchClause} catchClause catch clause - */ - walkCatchClause(catchClause) { - this.inBlockScope(() => { - // Error binding is optional in catch clause since ECMAScript 2019 - if (catchClause.param !== null) { - this.enterPattern(catchClause.param, ident => { - this.defineVariable(ident); - }); - this.walkPattern(catchClause.param); - } - const prev = this.prevStatement; - this.blockPreWalkStatement(catchClause.body); - this.prevStatement = prev; - this.walkStatement(catchClause.body); - }); - } - - /** - * @param {Pattern} pattern pattern - */ - walkPattern(pattern) { - switch (pattern.type) { - case "ArrayPattern": - this.walkArrayPattern(pattern); - break; - case "AssignmentPattern": - this.walkAssignmentPattern(pattern); - break; - case "MemberExpression": - this.walkMemberExpression(pattern); - break; - case "ObjectPattern": - this.walkObjectPattern(pattern); - break; - case "RestElement": - this.walkRestElement(pattern); - break; - } - } - - /** - * @param {AssignmentPattern} pattern assignment pattern - */ - walkAssignmentPattern(pattern) { - this.walkExpression(pattern.right); - this.walkPattern(pattern.left); - } - - walkObjectPattern(pattern) { - for (let i = 0, len = pattern.properties.length; i < len; i++) { - const prop = pattern.properties[i]; - if (prop) { - if (prop.computed) this.walkExpression(prop.key); - if (prop.value) this.walkPattern(prop.value); - } - } - } - - /** - * @param {ArrayPattern} pattern array pattern - */ - walkArrayPattern(pattern) { - for (let i = 0, len = pattern.elements.length; i < len; i++) { - const element = pattern.elements[i]; - if (element) this.walkPattern(element); - } - } - - /** - * @param {RestElement} pattern rest element - */ - walkRestElement(pattern) { - this.walkPattern(pattern.argument); - } - - /** - * @param {(Expression | SpreadElement | null)[]} expressions expressions - */ - walkExpressions(expressions) { - for (const expression of expressions) { - if (expression) { - this.walkExpression(expression); - } - } - } - - /** - * @param {TODO} expression expression - */ - walkExpression(expression) { - switch (expression.type) { - case "ArrayExpression": - this.walkArrayExpression(expression); - break; - case "ArrowFunctionExpression": - this.walkArrowFunctionExpression(expression); - break; - case "AssignmentExpression": - this.walkAssignmentExpression(expression); - break; - case "AwaitExpression": - this.walkAwaitExpression(expression); - break; - case "BinaryExpression": - this.walkBinaryExpression(expression); - break; - case "CallExpression": - this.walkCallExpression(expression); - break; - case "ChainExpression": - this.walkChainExpression(expression); - break; - case "ClassExpression": - this.walkClassExpression(expression); - break; - case "ConditionalExpression": - this.walkConditionalExpression(expression); - break; - case "FunctionExpression": - this.walkFunctionExpression(expression); - break; - case "Identifier": - this.walkIdentifier(expression); - break; - case "ImportExpression": - this.walkImportExpression(expression); - break; - case "LogicalExpression": - this.walkLogicalExpression(expression); - break; - case "MetaProperty": - this.walkMetaProperty(expression); - break; - case "MemberExpression": - this.walkMemberExpression(expression); - break; - case "NewExpression": - this.walkNewExpression(expression); - break; - case "ObjectExpression": - this.walkObjectExpression(expression); - break; - case "SequenceExpression": - this.walkSequenceExpression(expression); - break; - case "SpreadElement": - this.walkSpreadElement(expression); - break; - case "TaggedTemplateExpression": - this.walkTaggedTemplateExpression(expression); - break; - case "TemplateLiteral": - this.walkTemplateLiteral(expression); - break; - case "ThisExpression": - this.walkThisExpression(expression); - break; - case "UnaryExpression": - this.walkUnaryExpression(expression); - break; - case "UpdateExpression": - this.walkUpdateExpression(expression); - break; - case "YieldExpression": - this.walkYieldExpression(expression); - break; - } - } - - /** - * @param {AwaitExpression} expression await expression - */ - walkAwaitExpression(expression) { - if (this.scope.topLevelScope === true) - this.hooks.topLevelAwait.call(expression); - this.walkExpression(expression.argument); - } - - /** - * @param {ArrayExpression} expression array expression - */ - walkArrayExpression(expression) { - if (expression.elements) { - this.walkExpressions(expression.elements); - } - } - - /** - * @param {SpreadElement} expression spread element - */ - walkSpreadElement(expression) { - if (expression.argument) { - this.walkExpression(expression.argument); - } - } - - /** - * @param {ObjectExpression} expression object expression - */ - walkObjectExpression(expression) { - for ( - let propIndex = 0, len = expression.properties.length; - propIndex < len; - propIndex++ - ) { - const prop = expression.properties[propIndex]; - this.walkProperty(prop); - } - } - - /** - * @param {Property | SpreadElement} prop property or spread element - */ - walkProperty(prop) { - if (prop.type === "SpreadElement") { - this.walkExpression(prop.argument); - return; - } - if (prop.computed) { - this.walkExpression(prop.key); - } - if (prop.shorthand && prop.value && prop.value.type === "Identifier") { - this.scope.inShorthand = prop.value.name; - this.walkIdentifier(prop.value); - this.scope.inShorthand = false; - } else { - this.walkExpression(prop.value); - } - } - - /** - * @param {FunctionExpression} expression arrow function expression - */ - walkFunctionExpression(expression) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - const scopeParams = [...expression.params]; - - // Add function name in scope for recursive calls - if (expression.id) { - scopeParams.push(expression.id); - } - - this.inFunctionScope(true, scopeParams, () => { - for (const param of expression.params) { - this.walkPattern(param); - } - if (expression.body.type === "BlockStatement") { - this.detectMode(expression.body.body); - const prev = this.prevStatement; - this.preWalkStatement(expression.body); - this.prevStatement = prev; - this.walkStatement(expression.body); - } else { - this.walkExpression(expression.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - /** - * @param {ArrowFunctionExpression} expression arrow function expression - */ - walkArrowFunctionExpression(expression) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = wasTopLevel ? "arrow" : false; - this.inFunctionScope(false, expression.params, () => { - for (const param of expression.params) { - this.walkPattern(param); - } - if (expression.body.type === "BlockStatement") { - this.detectMode(expression.body.body); - const prev = this.prevStatement; - this.preWalkStatement(expression.body); - this.prevStatement = prev; - this.walkStatement(expression.body); - } else { - this.walkExpression(expression.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - /** - * @param {SequenceExpression} expression the sequence - */ - walkSequenceExpression(expression) { - if (!expression.expressions) return; - // We treat sequence expressions like statements when they are one statement level - // This has some benefits for optimizations that only work on statement level - const currentStatement = this.statementPath[this.statementPath.length - 1]; - if ( - currentStatement === expression || - (currentStatement.type === "ExpressionStatement" && - currentStatement.expression === expression) - ) { - const old = this.statementPath.pop(); - for (const expr of expression.expressions) { - this.statementPath.push(expr); - this.walkExpression(expr); - this.statementPath.pop(); - } - this.statementPath.push(old); - } else { - this.walkExpressions(expression.expressions); - } - } - - /** - * @param {UpdateExpression} expression the update expression - */ - walkUpdateExpression(expression) { - this.walkExpression(expression.argument); - } - - /** - * @param {UnaryExpression} expression the unary expression - */ - walkUnaryExpression(expression) { - if (expression.operator === "typeof") { - const result = this.callHooksForExpression( - this.hooks.typeof, - expression.argument, - expression - ); - if (result === true) return; - if (expression.argument.type === "ChainExpression") { - const result = this.callHooksForExpression( - this.hooks.typeof, - expression.argument.expression, - expression - ); - if (result === true) return; - } - } - this.walkExpression(expression.argument); - } - - /** - * @param {LogicalExpression | BinaryExpression} expression the expression - */ - walkLeftRightExpression(expression) { - this.walkExpression(expression.left); - this.walkExpression(expression.right); - } - - /** - * @param {BinaryExpression} expression the binary expression - */ - walkBinaryExpression(expression) { - if (this.hooks.binaryExpression.call(expression) === undefined) { - this.walkLeftRightExpression(expression); - } - } - - /** - * @param {LogicalExpression} expression the logical expression - */ - walkLogicalExpression(expression) { - const result = this.hooks.expressionLogicalOperator.call(expression); - if (result === undefined) { - this.walkLeftRightExpression(expression); - } else { - if (result) { - this.walkExpression(expression.right); - } - } - } - - /** - * @param {AssignmentExpression} expression assignment expression - */ - walkAssignmentExpression(expression) { - if (expression.left.type === "Identifier") { - const renameIdentifier = this.getRenameIdentifier(expression.right); - if (renameIdentifier) { - if ( - this.callHooksForInfo( - this.hooks.canRename, - renameIdentifier, - expression.right - ) - ) { - // renaming "a = b;" - if ( - !this.callHooksForInfo( - this.hooks.rename, - renameIdentifier, - expression.right - ) - ) { - this.setVariable( - expression.left.name, - typeof renameIdentifier === "string" - ? this.getVariableInfo(renameIdentifier) - : renameIdentifier - ); - } - return; - } - } - this.walkExpression(expression.right); - this.enterPattern(expression.left, (name, decl) => { - if (!this.callHooksForName(this.hooks.assign, name, expression)) { - this.walkExpression(expression.left); - } - }); - return; - } - if (expression.left.type.endsWith("Pattern")) { - this.walkExpression(expression.right); - this.enterPattern(expression.left, (name, decl) => { - if (!this.callHooksForName(this.hooks.assign, name, expression)) { - this.defineVariable(name); - } - }); - this.walkPattern(expression.left); - } else if (expression.left.type === "MemberExpression") { - const exprName = this.getMemberExpressionInfo( - expression.left, - ALLOWED_MEMBER_TYPES_EXPRESSION - ); - if (exprName) { - if ( - this.callHooksForInfo( - this.hooks.assignMemberChain, - exprName.rootInfo, - expression, - exprName.getMembers() - ) - ) { - return; - } - } - this.walkExpression(expression.right); - this.walkExpression(expression.left); - } else { - this.walkExpression(expression.right); - this.walkExpression(expression.left); - } - } - - /** - * @param {ConditionalExpression} expression conditional expression - */ - walkConditionalExpression(expression) { - const result = this.hooks.expressionConditionalOperator.call(expression); - if (result === undefined) { - this.walkExpression(expression.test); - this.walkExpression(expression.consequent); - if (expression.alternate) { - this.walkExpression(expression.alternate); - } - } else { - if (result) { - this.walkExpression(expression.consequent); - } else if (expression.alternate) { - this.walkExpression(expression.alternate); - } - } - } - - /** - * @param {NewExpression} expression new expression - */ - walkNewExpression(expression) { - const result = this.callHooksForExpression( - this.hooks.new, - expression.callee, - expression - ); - if (result === true) return; - this.walkExpression(expression.callee); - if (expression.arguments) { - this.walkExpressions(expression.arguments); - } - } - - /** - * @param {YieldExpression} expression yield expression - */ - walkYieldExpression(expression) { - if (expression.argument) { - this.walkExpression(expression.argument); - } - } - - /** - * @param {TemplateLiteral} expression template literal - */ - walkTemplateLiteral(expression) { - if (expression.expressions) { - this.walkExpressions(expression.expressions); - } - } - - /** - * @param {TaggedTemplateExpression} expression tagged template expression - */ - walkTaggedTemplateExpression(expression) { - if (expression.tag) { - this.scope.inTaggedTemplateTag = true; - this.walkExpression(expression.tag); - this.scope.inTaggedTemplateTag = false; - } - if (expression.quasi && expression.quasi.expressions) { - this.walkExpressions(expression.quasi.expressions); - } - } - - /** - * @param {ClassExpression} expression the class expression - */ - walkClassExpression(expression) { - this.walkClass(expression); - } - - /** - * @param {ChainExpression} expression expression - */ - walkChainExpression(expression) { - const result = this.hooks.optionalChaining.call(expression); - - if (result === undefined) { - if (expression.expression.type === "CallExpression") { - this.walkCallExpression(expression.expression); - } else { - this.walkMemberExpression(expression.expression); - } - } - } - - _walkIIFE(functionExpression, options, currentThis) { - const getVarInfo = argOrThis => { - const renameIdentifier = this.getRenameIdentifier(argOrThis); - if (renameIdentifier) { - if ( - this.callHooksForInfo( - this.hooks.canRename, - renameIdentifier, - argOrThis - ) - ) { - if ( - !this.callHooksForInfo( - this.hooks.rename, - renameIdentifier, - argOrThis - ) - ) { - return typeof renameIdentifier === "string" - ? this.getVariableInfo(renameIdentifier) - : renameIdentifier; - } - } - } - this.walkExpression(argOrThis); - }; - const { params, type } = functionExpression; - const arrow = type === "ArrowFunctionExpression"; - const renameThis = currentThis ? getVarInfo(currentThis) : null; - const varInfoForArgs = options.map(getVarInfo); - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = wasTopLevel && arrow ? "arrow" : false; - const scopeParams = params.filter( - (identifier, idx) => !varInfoForArgs[idx] - ); - - // Add function name in scope for recursive calls - if (functionExpression.id) { - scopeParams.push(functionExpression.id.name); - } - - this.inFunctionScope(true, scopeParams, () => { - if (renameThis && !arrow) { - this.setVariable("this", renameThis); - } - for (let i = 0; i < varInfoForArgs.length; i++) { - const varInfo = varInfoForArgs[i]; - if (!varInfo) continue; - if (!params[i] || params[i].type !== "Identifier") continue; - this.setVariable(params[i].name, varInfo); - } - if (functionExpression.body.type === "BlockStatement") { - this.detectMode(functionExpression.body.body); - const prev = this.prevStatement; - this.preWalkStatement(functionExpression.body); - this.prevStatement = prev; - this.walkStatement(functionExpression.body); - } else { - this.walkExpression(functionExpression.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - /** - * @param {ImportExpression} expression import expression - */ - walkImportExpression(expression) { - let result = this.hooks.importCall.call(expression); - if (result === true) return; - - this.walkExpression(expression.source); - } - - walkCallExpression(expression) { - const isSimpleFunction = fn => { - return fn.params.every(p => p.type === "Identifier"); - }; - if ( - expression.callee.type === "MemberExpression" && - expression.callee.object.type.endsWith("FunctionExpression") && - !expression.callee.computed && - (expression.callee.property.name === "call" || - expression.callee.property.name === "bind") && - expression.arguments.length > 0 && - isSimpleFunction(expression.callee.object) - ) { - // (function(…) { }.call/bind(?, …)) - this._walkIIFE( - expression.callee.object, - expression.arguments.slice(1), - expression.arguments[0] - ); - } else if ( - expression.callee.type.endsWith("FunctionExpression") && - isSimpleFunction(expression.callee) - ) { - // (function(…) { }(…)) - this._walkIIFE(expression.callee, expression.arguments, null); - } else { - if (expression.callee.type === "MemberExpression") { - const exprInfo = this.getMemberExpressionInfo( - expression.callee, - ALLOWED_MEMBER_TYPES_CALL_EXPRESSION - ); - if (exprInfo && exprInfo.type === "call") { - const result = this.callHooksForInfo( - this.hooks.callMemberChainOfCallMemberChain, - exprInfo.rootInfo, - expression, - exprInfo.getCalleeMembers(), - exprInfo.call, - exprInfo.getMembers(), - exprInfo.getMemberRanges() - ); - if (result === true) return; - } - } - const callee = this.evaluateExpression(expression.callee); - if (callee.isIdentifier()) { - const result1 = this.callHooksForInfo( - this.hooks.callMemberChain, - callee.rootInfo, - expression, - callee.getMembers(), - callee.getMembersOptionals - ? callee.getMembersOptionals() - : callee.getMembers().map(() => false), - callee.getMemberRanges ? callee.getMemberRanges() : [] - ); - if (result1 === true) return; - const result2 = this.callHooksForInfo( - this.hooks.call, - callee.identifier, - expression - ); - if (result2 === true) return; - } - - if (expression.callee) { - if (expression.callee.type === "MemberExpression") { - // because of call context we need to walk the call context as expression - this.walkExpression(expression.callee.object); - if (expression.callee.computed === true) - this.walkExpression(expression.callee.property); - } else { - this.walkExpression(expression.callee); - } - } - if (expression.arguments) this.walkExpressions(expression.arguments); - } - } - - /** - * @param {MemberExpression} expression member expression - */ - walkMemberExpression(expression) { - const exprInfo = this.getMemberExpressionInfo( - expression, - ALLOWED_MEMBER_TYPES_ALL - ); - if (exprInfo) { - switch (exprInfo.type) { - case "expression": { - const result1 = this.callHooksForInfo( - this.hooks.expression, - exprInfo.name, - expression - ); - if (result1 === true) return; - const members = exprInfo.getMembers(); - const membersOptionals = exprInfo.getMembersOptionals(); - const memberRanges = exprInfo.getMemberRanges(); - const result2 = this.callHooksForInfo( - this.hooks.expressionMemberChain, - exprInfo.rootInfo, - expression, - members, - membersOptionals, - memberRanges - ); - if (result2 === true) return; - this.walkMemberExpressionWithExpressionName( - expression, - exprInfo.name, - exprInfo.rootInfo, - members.slice(), - () => - this.callHooksForInfo( - this.hooks.unhandledExpressionMemberChain, - exprInfo.rootInfo, - expression, - members - ) - ); - return; - } - case "call": { - const result = this.callHooksForInfo( - this.hooks.memberChainOfCallMemberChain, - exprInfo.rootInfo, - expression, - exprInfo.getCalleeMembers(), - exprInfo.call, - exprInfo.getMembers(), - exprInfo.getMemberRanges() - ); - if (result === true) return; - // Fast skip over the member chain as we already called memberChainOfCallMemberChain - // and call computed property are literals anyway - this.walkExpression(exprInfo.call); - return; - } - } - } - this.walkExpression(expression.object); - if (expression.computed === true) this.walkExpression(expression.property); - } - - walkMemberExpressionWithExpressionName( - expression, - name, - rootInfo, - members, - onUnhandled - ) { - if (expression.object.type === "MemberExpression") { - // optimize the case where expression.object is a MemberExpression too. - // we can keep info here when calling walkMemberExpression directly - const property = - expression.property.name || `${expression.property.value}`; - name = name.slice(0, -property.length - 1); - members.pop(); - const result = this.callHooksForInfo( - this.hooks.expression, - name, - expression.object - ); - if (result === true) return; - this.walkMemberExpressionWithExpressionName( - expression.object, - name, - rootInfo, - members, - onUnhandled - ); - } else if (!onUnhandled || !onUnhandled()) { - this.walkExpression(expression.object); - } - if (expression.computed === true) this.walkExpression(expression.property); - } - - /** - * @param {ThisExpression} expression this expression - */ - walkThisExpression(expression) { - this.callHooksForName(this.hooks.expression, "this", expression); - } - - /** - * @param {Identifier} expression identifier - */ - walkIdentifier(expression) { - this.callHooksForName(this.hooks.expression, expression.name, expression); - } - - /** - * @param {MetaProperty} metaProperty meta property - */ - walkMetaProperty(metaProperty) { - this.hooks.expression.for(getRootName(metaProperty)).call(metaProperty); - } - - callHooksForExpression(hookMap, expr, ...args) { - return this.callHooksForExpressionWithFallback( - hookMap, - expr, - undefined, - undefined, - ...args - ); - } - - /** - * @template T - * @template R - * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called - * @param {MemberExpression} expr expression info - * @param {(function(string, string | ScopeInfo | VariableInfo, function(): string[]): any) | undefined} fallback callback when variable in not handled by hooks - * @param {(function(string): any) | undefined} defined callback when variable is defined - * @param {AsArray<T>} args args for the hook - * @returns {R | undefined} result of hook - */ - callHooksForExpressionWithFallback( - hookMap, - expr, - fallback, - defined, - ...args - ) { - const exprName = this.getMemberExpressionInfo( - expr, - ALLOWED_MEMBER_TYPES_EXPRESSION - ); - if (exprName !== undefined) { - const members = exprName.getMembers(); - return this.callHooksForInfoWithFallback( - hookMap, - members.length === 0 ? exprName.rootInfo : exprName.name, - fallback && - (name => fallback(name, exprName.rootInfo, exprName.getMembers)), - defined && (() => defined(exprName.name)), - ...args - ); - } - } - - /** - * @template T - * @template R - * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called - * @param {string} name key in map - * @param {AsArray<T>} args args for the hook - * @returns {R | undefined} result of hook - */ - callHooksForName(hookMap, name, ...args) { - return this.callHooksForNameWithFallback( - hookMap, - name, - undefined, - undefined, - ...args - ); - } - - /** - * @template T - * @template R - * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called - * @param {ExportedVariableInfo} info variable info - * @param {AsArray<T>} args args for the hook - * @returns {R | undefined} result of hook - */ - callHooksForInfo(hookMap, info, ...args) { - return this.callHooksForInfoWithFallback( - hookMap, - info, - undefined, - undefined, - ...args - ); - } - - /** - * @template T - * @template R - * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called - * @param {ExportedVariableInfo} info variable info - * @param {(function(string): any) | undefined} fallback callback when variable in not handled by hooks - * @param {(function(): any) | undefined} defined callback when variable is defined - * @param {AsArray<T>} args args for the hook - * @returns {R | undefined} result of hook - */ - callHooksForInfoWithFallback(hookMap, info, fallback, defined, ...args) { - let name; - if (typeof info === "string") { - name = info; - } else { - if (!(info instanceof VariableInfo)) { - if (defined !== undefined) { - return defined(); - } - return; - } - let tagInfo = info.tagInfo; - while (tagInfo !== undefined) { - const hook = hookMap.get(tagInfo.tag); - if (hook !== undefined) { - this.currentTagData = tagInfo.data; - const result = hook.call(...args); - this.currentTagData = undefined; - if (result !== undefined) return result; - } - tagInfo = tagInfo.next; - } - if (info.freeName === true) { - if (defined !== undefined) { - return defined(); - } - return; - } - name = info.freeName; - } - const hook = hookMap.get(name); - if (hook !== undefined) { - const result = hook.call(...args); - if (result !== undefined) return result; - } - if (fallback !== undefined) { - return fallback(name); - } - } - - /** - * @template T - * @template R - * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called - * @param {string} name key in map - * @param {(function(string): any) | undefined} fallback callback when variable in not handled by hooks - * @param {(function(): any) | undefined} defined callback when variable is defined - * @param {AsArray<T>} args args for the hook - * @returns {R | undefined} result of hook - */ - callHooksForNameWithFallback(hookMap, name, fallback, defined, ...args) { - return this.callHooksForInfoWithFallback( - hookMap, - this.getVariableInfo(name), - fallback, - defined, - ...args - ); - } - - /** - * @deprecated - * @param {any} params scope params - * @param {function(): void} fn inner function - * @returns {void} - */ - inScope(params, fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: false, - inShorthand: false, - inTaggedTemplateTag: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild() - }; - - this.undefineVariable("this"); - - this.enterPatterns(params, (ident, pattern) => { - this.defineVariable(ident); - }); - - fn(); - - this.scope = oldScope; - } - - /** - * @param {boolean} hasThis true, when this is defined - * @param {any} params scope params - * @param {function(): void} fn inner function - * @returns {void} - */ - inClassScope(hasThis, params, fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: false, - inShorthand: false, - inTaggedTemplateTag: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild() - }; - - if (hasThis) { - this.undefineVariable("this"); - } - - this.enterPatterns(params, (ident, pattern) => { - this.defineVariable(ident); - }); - - fn(); - - this.scope = oldScope; - } - - /** - * @param {boolean} hasThis true, when this is defined - * @param {any} params scope params - * @param {function(): void} fn inner function - * @returns {void} - */ - inFunctionScope(hasThis, params, fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: false, - inShorthand: false, - inTaggedTemplateTag: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild() - }; - - if (hasThis) { - this.undefineVariable("this"); - } - - this.enterPatterns(params, (ident, pattern) => { - this.defineVariable(ident); - }); - - fn(); - - this.scope = oldScope; - } - - /** - * @param {function(): void} fn inner function - * @returns {void} - */ - inBlockScope(fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: oldScope.inTry, - inShorthand: false, - inTaggedTemplateTag: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild() - }; - - fn(); - - this.scope = oldScope; - } - - /** - * @param {Array<Directive | Statement | ModuleDeclaration>} statements statements - */ - detectMode(statements) { - const isLiteral = - statements.length >= 1 && - statements[0].type === "ExpressionStatement" && - statements[0].expression.type === "Literal"; - if ( - isLiteral && - /** @type {Literal} */ - (/** @type {ExpressionStatement} */ (statements[0]).expression).value === - "use strict" - ) { - this.scope.isStrict = true; - } - if ( - isLiteral && - /** @type {Literal} */ - (/** @type {ExpressionStatement} */ (statements[0]).expression).value === - "use asm" - ) { - this.scope.isAsmJs = true; - } - } - - enterPatterns(patterns, onIdent) { - for (const pattern of patterns) { - if (typeof pattern !== "string") { - this.enterPattern(pattern, onIdent); - } else if (pattern) { - onIdent(pattern); - } - } - } - - enterPattern(pattern, onIdent) { - if (!pattern) return; - switch (pattern.type) { - case "ArrayPattern": - this.enterArrayPattern(pattern, onIdent); - break; - case "AssignmentPattern": - this.enterAssignmentPattern(pattern, onIdent); - break; - case "Identifier": - this.enterIdentifier(pattern, onIdent); - break; - case "ObjectPattern": - this.enterObjectPattern(pattern, onIdent); - break; - case "RestElement": - this.enterRestElement(pattern, onIdent); - break; - case "Property": - if (pattern.shorthand && pattern.value.type === "Identifier") { - this.scope.inShorthand = pattern.value.name; - this.enterIdentifier(pattern.value, onIdent); - this.scope.inShorthand = false; - } else { - this.enterPattern(pattern.value, onIdent); - } - break; - } - } - - /** - * @param {Identifier} pattern identifier pattern - * @param {TODO} onIdent callback - */ - enterIdentifier(pattern, onIdent) { - if (!this.callHooksForName(this.hooks.pattern, pattern.name, pattern)) { - onIdent(pattern.name, pattern); - } - } - - /** - * @param {ObjectPattern} pattern object pattern - * @param {TODO} onIdent callback - */ - enterObjectPattern(pattern, onIdent) { - for ( - let propIndex = 0, len = pattern.properties.length; - propIndex < len; - propIndex++ - ) { - const prop = pattern.properties[propIndex]; - this.enterPattern(prop, onIdent); - } - } - - /** - * @param {ArrayPattern} pattern object pattern - * @param {TODO} onIdent callback - */ - enterArrayPattern(pattern, onIdent) { - for ( - let elementIndex = 0, len = pattern.elements.length; - elementIndex < len; - elementIndex++ - ) { - const element = pattern.elements[elementIndex]; - // TODO check on `null`? - this.enterPattern(element, onIdent); - } - } - - /** - * @param {RestElement} pattern object pattern - * @param {TODO} onIdent callback - */ - enterRestElement(pattern, onIdent) { - this.enterPattern(pattern.argument, onIdent); - } - - /** - * @param {AssignmentPattern} pattern object pattern - * @param {TODO} onIdent callback - */ - enterAssignmentPattern(pattern, onIdent) { - this.enterPattern(pattern.left, onIdent); - } - - /** - * @param {TODO} expression expression node - * @returns {BasicEvaluatedExpression} evaluation result - */ - evaluateExpression(expression) { - try { - const hook = this.hooks.evaluate.get(expression.type); - if (hook !== undefined) { - const result = hook.call(expression); - if (result !== undefined && result !== null) { - result.setExpression(expression); - return result; - } - } - } catch (e) { - console.warn(e); - // ignore error - } - return new BasicEvaluatedExpression() - .setRange(/** @type {Range} */ (expression.range)) - .setExpression(expression); - } - - /** - * @param {Expression} expression expression - * @returns {string} parsed string - */ - parseString(expression) { - switch (expression.type) { - case "BinaryExpression": - if (expression.operator === "+") { - return ( - this.parseString(expression.left) + - this.parseString(expression.right) - ); - } - break; - case "Literal": - return expression.value + ""; - } - throw new Error( - expression.type + " is not supported as parameter for require" - ); - } - - parseCalculatedString(expression) { - switch (expression.type) { - case "BinaryExpression": - if (expression.operator === "+") { - const left = this.parseCalculatedString(expression.left); - const right = this.parseCalculatedString(expression.right); - if (left.code) { - return { - range: left.range, - value: left.value, - code: true, - conditional: false - }; - } else if (right.code) { - return { - range: [ - left.range[0], - right.range ? right.range[1] : left.range[1] - ], - value: left.value + right.value, - code: true, - conditional: false - }; - } else { - return { - range: [left.range[0], right.range[1]], - value: left.value + right.value, - code: false, - conditional: false - }; - } - } - break; - case "ConditionalExpression": { - const consequent = this.parseCalculatedString(expression.consequent); - const alternate = this.parseCalculatedString(expression.alternate); - const items = []; - if (consequent.conditional) { - items.push(...consequent.conditional); - } else if (!consequent.code) { - items.push(consequent); - } else { - break; - } - if (alternate.conditional) { - items.push(...alternate.conditional); - } else if (!alternate.code) { - items.push(alternate); - } else { - break; - } - return { - range: undefined, - value: "", - code: true, - conditional: items - }; - } - case "Literal": - return { - range: expression.range, - value: expression.value + "", - code: false, - conditional: false - }; - } - return { - range: undefined, - value: "", - code: true, - conditional: false - }; - } - - /** - * @param {string | Buffer | PreparsedAst} source the source to parse - * @param {ParserState} state the parser state - * @returns {ParserState} the parser state - */ - parse(source, state) { - let ast; - let comments; - const semicolons = new Set(); - if (source === null) { - throw new Error("source must not be null"); - } - if (Buffer.isBuffer(source)) { - source = source.toString("utf-8"); - } - if (typeof source === "object") { - ast = /** @type {Program} */ (source); - comments = source.comments; - } else { - comments = []; - ast = JavascriptParser._parse(source, { - sourceType: this.sourceType, - onComment: comments, - onInsertedSemicolon: pos => semicolons.add(pos) - }); - } - - const oldScope = this.scope; - const oldState = this.state; - const oldComments = this.comments; - const oldSemicolons = this.semicolons; - const oldStatementPath = this.statementPath; - const oldPrevStatement = this.prevStatement; - this.scope = { - topLevelScope: true, - inTry: false, - inShorthand: false, - inTaggedTemplateTag: false, - isStrict: false, - isAsmJs: false, - definitions: new StackedMap() - }; - /** @type {ParserState} */ - this.state = state; - this.comments = comments; - this.semicolons = semicolons; - this.statementPath = []; - this.prevStatement = undefined; - if (this.hooks.program.call(ast, comments) === undefined) { - this.destructuringAssignmentProperties = new WeakMap(); - this.detectMode(ast.body); - this.preWalkStatements(ast.body); - this.prevStatement = undefined; - this.blockPreWalkStatements(ast.body); - this.prevStatement = undefined; - this.walkStatements(ast.body); - this.destructuringAssignmentProperties = undefined; - } - this.hooks.finish.call(ast, comments); - this.scope = oldScope; - /** @type {ParserState} */ - this.state = oldState; - this.comments = oldComments; - this.semicolons = oldSemicolons; - this.statementPath = oldStatementPath; - this.prevStatement = oldPrevStatement; - return state; - } - - /** - * @param {string} source source code - * @returns {BasicEvaluatedExpression} evaluation result - */ - evaluate(source) { - const ast = JavascriptParser._parse("(" + source + ")", { - sourceType: this.sourceType, - locations: false - }); - if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") { - throw new Error("evaluate: Source is not a expression"); - } - return this.evaluateExpression(ast.body[0].expression); - } - - /** - * @param {Expression | Declaration | PrivateIdentifier | null | undefined} expr an expression - * @param {number} commentsStartPos source position from which annotation comments are checked - * @returns {boolean} true, when the expression is pure - */ - isPure(expr, commentsStartPos) { - if (!expr) return true; - const result = this.hooks.isPure - .for(expr.type) - .call(expr, commentsStartPos); - if (typeof result === "boolean") return result; - switch (expr.type) { - // TODO handle more cases - case "ClassDeclaration": - case "ClassExpression": { - if (expr.body.type !== "ClassBody") return false; - if (expr.superClass && !this.isPure(expr.superClass, expr.range[0])) { - return false; - } - const items = - /** @type {TODO[]} */ - (expr.body.body); - return items.every(item => { - if ( - item.computed && - item.key && - !this.isPure(item.key, item.range[0]) - ) { - return false; - } - - if ( - item.static && - item.value && - !this.isPure( - item.value, - item.key ? item.key.range[1] : item.range[0] - ) - ) { - return false; - } - - if (item.type === "StaticBlock") { - return false; - } - - return true; - }); - } - - case "FunctionDeclaration": - case "FunctionExpression": - case "ArrowFunctionExpression": - case "ThisExpression": - case "Literal": - case "TemplateLiteral": - case "Identifier": - case "PrivateIdentifier": - return true; - - case "VariableDeclaration": - return expr.declarations.every(decl => - this.isPure(decl.init, /** @type {Range} */ (decl.range)[0]) - ); - - case "ConditionalExpression": - return ( - this.isPure(expr.test, commentsStartPos) && - this.isPure( - expr.consequent, - /** @type {Range} */ (expr.test.range)[1] - ) && - this.isPure( - expr.alternate, - /** @type {Range} */ (expr.consequent.range)[1] - ) - ); - - case "LogicalExpression": - return ( - this.isPure(expr.left, commentsStartPos) && - this.isPure(expr.right, /** @type {Range} */ (expr.left.range)[1]) - ); - - case "SequenceExpression": - return expr.expressions.every(expr => { - const pureFlag = this.isPure(expr, commentsStartPos); - commentsStartPos = /** @type {Range} */ (expr.range)[1]; - return pureFlag; - }); - - case "CallExpression": { - const pureFlag = - /** @type {Range} */ (expr.range)[0] - commentsStartPos > 12 && - this.getComments([ - commentsStartPos, - /** @type {Range} */ (expr.range)[0] - ]).some( - comment => - comment.type === "Block" && - /^\s*(#|@)__PURE__\s*$/.test(comment.value) - ); - if (!pureFlag) return false; - commentsStartPos = /** @type {Range} */ (expr.callee.range)[1]; - return expr.arguments.every(arg => { - if (arg.type === "SpreadElement") return false; - const pureFlag = this.isPure(arg, commentsStartPos); - commentsStartPos = /** @type {Range} */ (arg.range)[1]; - return pureFlag; - }); - } - } - const evaluated = this.evaluateExpression(expr); - return !evaluated.couldHaveSideEffects(); - } - - /** - * @param {Range} range range - * @returns {TODO[]} comments in the range - */ - getComments(range) { - const [rangeStart, rangeEnd] = range; - const compare = (comment, needle) => comment.range[0] - needle; - let idx = binarySearchBounds.ge(this.comments, rangeStart, compare); - let commentsInRange = []; - while (this.comments[idx] && this.comments[idx].range[1] <= rangeEnd) { - commentsInRange.push(this.comments[idx]); - idx++; - } - - return commentsInRange; - } - - /** - * @param {number} pos source code position - * @returns {boolean} true when a semicolon has been inserted before this position, false if not - */ - isAsiPosition(pos) { - const currentStatement = this.statementPath[this.statementPath.length - 1]; - if (currentStatement === undefined) throw new Error("Not in statement"); - return ( - // Either asking directly for the end position of the current statement - (currentStatement.range[1] === pos && this.semicolons.has(pos)) || - // Or asking for the start position of the current statement, - // here we have to check multiple things - (currentStatement.range[0] === pos && - // is there a previous statement which might be relevant? - this.prevStatement !== undefined && - // is the end position of the previous statement an ASI position? - this.semicolons.has(this.prevStatement.range[1])) - ); - } - - /** - * @param {number} pos source code position - * @returns {void} - */ - unsetAsiPosition(pos) { - this.semicolons.delete(pos); - } - - /** - * @param {Expression} expr expression - * @returns {boolean} true, when the expression is a statement level expression - */ - isStatementLevelExpression(expr) { - const currentStatement = this.statementPath[this.statementPath.length - 1]; - return ( - expr === currentStatement || - (currentStatement.type === "ExpressionStatement" && - currentStatement.expression === expr) - ); - } - - getTagData(name, tag) { - const info = this.scope.definitions.get(name); - if (info instanceof VariableInfo) { - let tagInfo = info.tagInfo; - while (tagInfo !== undefined) { - if (tagInfo.tag === tag) return tagInfo.data; - tagInfo = tagInfo.next; - } - } - } - - tagVariable(name, tag, data) { - const oldInfo = this.scope.definitions.get(name); - /** @type {VariableInfo} */ - let newInfo; - if (oldInfo === undefined) { - newInfo = new VariableInfo(this.scope, name, { - tag, - data, - next: undefined - }); - } else if (oldInfo instanceof VariableInfo) { - newInfo = new VariableInfo(oldInfo.declaredScope, oldInfo.freeName, { - tag, - data, - next: oldInfo.tagInfo - }); - } else { - newInfo = new VariableInfo(oldInfo, true, { - tag, - data, - next: undefined - }); - } - this.scope.definitions.set(name, newInfo); - } - - /** - * @param {string} name variable name - */ - defineVariable(name) { - const oldInfo = this.scope.definitions.get(name); - // Don't redefine variable in same scope to keep existing tags - if (oldInfo instanceof VariableInfo && oldInfo.declaredScope === this.scope) - return; - this.scope.definitions.set(name, this.scope); - } - - /** - * @param {string} name variable name - */ - undefineVariable(name) { - this.scope.definitions.delete(name); - } - - /** - * @param {string} name variable name - * @returns {boolean} true, when variable is defined - */ - isVariableDefined(name) { - const info = this.scope.definitions.get(name); - if (info === undefined) return false; - if (info instanceof VariableInfo) { - return info.freeName === true; - } - return true; - } - - /** - * @param {string} name variable name - * @returns {ExportedVariableInfo} info for this variable - */ - getVariableInfo(name) { - const value = this.scope.definitions.get(name); - if (value === undefined) { - return name; - } else { - return value; - } - } - - /** - * @param {string} name variable name - * @param {ExportedVariableInfo} variableInfo new info for this variable - * @returns {void} - */ - setVariable(name, variableInfo) { - if (typeof variableInfo === "string") { - if (variableInfo === name) { - this.scope.definitions.delete(name); - } else { - this.scope.definitions.set( - name, - new VariableInfo(this.scope, variableInfo, undefined) - ); - } - } else { - this.scope.definitions.set(name, variableInfo); - } - } - - /** - * @param {TagInfo} tagInfo tag info - * @returns {VariableInfo} variable info - */ - evaluatedVariable(tagInfo) { - return new VariableInfo(this.scope, undefined, tagInfo); - } - - /** - * @param {Range} range range of the comment - * @returns {TODO} TODO - */ - parseCommentOptions(range) { - const comments = this.getComments(range); - if (comments.length === 0) { - return EMPTY_COMMENT_OPTIONS; - } - let options = {}; - /** @type {unknown[]} */ - let errors = []; - for (const comment of comments) { - const { value } = comment; - if (value && webpackCommentRegExp.test(value)) { - // try compile only if webpack options comment is present - try { - for (let [key, val] of Object.entries( - vm.runInNewContext(`(function(){return {${value}};})()`) - )) { - if (typeof val === "object" && val !== null) { - if (val.constructor.name === "RegExp") val = new RegExp(val); - else val = JSON.parse(JSON.stringify(val)); - } - options[key] = val; - } - } catch (e) { - const newErr = new Error(String(e.message)); - newErr.stack = String(e.stack); - Object.assign(newErr, { comment }); - errors.push(newErr); - } - } - } - return { options, errors }; - } - - /** - * @param {MemberExpression} expression a member expression - * @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRanges: Range[] }} member names (reverse order) and remaining object - */ - extractMemberExpressionChain(expression) { - /** @type {AnyNode} */ - let expr = expression; - const members = []; - const membersOptionals = []; - const memberRanges = []; - while (expr.type === "MemberExpression") { - if (expr.computed) { - if (expr.property.type !== "Literal") break; - members.push(`${expr.property.value}`); // the literal - memberRanges.push(expr.object.range); // the range of the expression fragment before the literal - } else { - if (expr.property.type !== "Identifier") break; - members.push(expr.property.name); // the identifier - memberRanges.push(expr.object.range); // the range of the expression fragment before the identifier - } - membersOptionals.push(expr.optional); - expr = expr.object; - } - - return { - members, - membersOptionals, - memberRanges, - object: expr - }; - } - - /** - * @param {string} varName variable name - * @returns {{name: string, info: VariableInfo | string} | undefined} name of the free variable and variable info for that - */ - getFreeInfoFromVariable(varName) { - const info = this.getVariableInfo(varName); - let name; - if (info instanceof VariableInfo) { - name = info.freeName; - if (typeof name !== "string") return undefined; - } else if (typeof info !== "string") { - return undefined; - } else { - name = info; - } - return { info, name }; - } - - /** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} CallExpressionInfo */ - /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} ExpressionExpressionInfo */ - - /** - * @param {MemberExpression} expression a member expression - * @param {number} allowedTypes which types should be returned, presented in bit mask - * @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info - */ - getMemberExpressionInfo(expression, allowedTypes) { - const { object, members, membersOptionals, memberRanges } = - this.extractMemberExpressionChain(expression); - switch (object.type) { - case "CallExpression": { - if ((allowedTypes & ALLOWED_MEMBER_TYPES_CALL_EXPRESSION) === 0) - return undefined; - let callee = object.callee; - let rootMembers = EMPTY_ARRAY; - if (callee.type === "MemberExpression") { - ({ object: callee, members: rootMembers } = - this.extractMemberExpressionChain(callee)); - } - const rootName = getRootName(callee); - if (!rootName) return undefined; - const result = this.getFreeInfoFromVariable(rootName); - if (!result) return undefined; - const { info: rootInfo, name: resolvedRoot } = result; - const calleeName = objectAndMembersToName(resolvedRoot, rootMembers); - return { - type: "call", - call: object, - calleeName, - rootInfo, - getCalleeMembers: memoize(() => rootMembers.reverse()), - name: objectAndMembersToName(`${calleeName}()`, members), - getMembers: memoize(() => members.reverse()), - getMembersOptionals: memoize(() => membersOptionals.reverse()), - getMemberRanges: memoize(() => memberRanges.reverse()) - }; - } - case "Identifier": - case "MetaProperty": - case "ThisExpression": { - if ((allowedTypes & ALLOWED_MEMBER_TYPES_EXPRESSION) === 0) - return undefined; - const rootName = getRootName(object); - if (!rootName) return undefined; - - const result = this.getFreeInfoFromVariable(rootName); - if (!result) return undefined; - const { info: rootInfo, name: resolvedRoot } = result; - return { - type: "expression", - name: objectAndMembersToName(resolvedRoot, members), - rootInfo, - getMembers: memoize(() => members.reverse()), - getMembersOptionals: memoize(() => membersOptionals.reverse()), - getMemberRanges: memoize(() => memberRanges.reverse()) - }; - } - } - } - - /** - * @param {MemberExpression} expression an expression - * @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => string[]} | undefined} name info - */ - getNameForExpression(expression) { - return this.getMemberExpressionInfo( - expression, - ALLOWED_MEMBER_TYPES_EXPRESSION - ); - } - - /** - * @param {string} code source code - * @param {ParseOptions} options parsing options - * @returns {Program} parsed ast - */ - static _parse(code, options) { - const type = options ? options.sourceType : "module"; - /** @type {AcornOptions} */ - const parserOptions = { - ...defaultParserOptions, - allowReturnOutsideFunction: type === "script", - ...options, - sourceType: type === "auto" ? "module" : type - }; - - /** @type {AnyNode | undefined} */ - let ast; - let error; - let threw = false; - try { - ast = /** @type {AnyNode} */ (parser.parse(code, parserOptions)); - } catch (e) { - error = e; - threw = true; - } - - if (threw && type === "auto") { - parserOptions.sourceType = "script"; - if (!("allowReturnOutsideFunction" in options)) { - parserOptions.allowReturnOutsideFunction = true; - } - if (Array.isArray(parserOptions.onComment)) { - parserOptions.onComment.length = 0; - } - try { - ast = /** @type {AnyNode} */ (parser.parse(code, parserOptions)); - threw = false; - } catch (e) { - // we use the error from first parse try - // so nothing to do here - } - } - - if (threw) { - throw error; - } - - return /** @type {Program} */ (ast); - } -} - -module.exports = JavascriptParser; -module.exports.ALLOWED_MEMBER_TYPES_ALL = ALLOWED_MEMBER_TYPES_ALL; -module.exports.ALLOWED_MEMBER_TYPES_EXPRESSION = - ALLOWED_MEMBER_TYPES_EXPRESSION; -module.exports.ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = - ALLOWED_MEMBER_TYPES_CALL_EXPRESSION; diff --git a/node_modules/webpack/lib/javascript/JavascriptParserHelpers.js b/node_modules/webpack/lib/javascript/JavascriptParserHelpers.js deleted file mode 100644 index 4d529887..00000000 --- a/node_modules/webpack/lib/javascript/JavascriptParserHelpers.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); -const ConstDependency = require("../dependencies/ConstDependency"); -const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); - -/** @typedef {import("estree").Expression} Expression */ -/** @typedef {import("estree").Node} Node */ -/** @typedef {import("estree").SourceLocation} SourceLocation */ -/** @typedef {import("./JavascriptParser")} JavascriptParser */ -/** @typedef {import("./JavascriptParser").Range} Range */ - -/** - * @param {JavascriptParser} parser the parser - * @param {string} value the const value - * @param {string[]=} runtimeRequirements runtime requirements - * @returns {function(Expression): true} plugin function - */ -exports.toConstantDependency = (parser, value, runtimeRequirements) => { - return function constDependency(expr) { - const dep = new ConstDependency( - value, - /** @type {Range} */ (expr.range), - runtimeRequirements - ); - dep.loc = /** @type {SourceLocation} */ (expr.loc); - parser.state.module.addPresentationalDependency(dep); - return true; - }; -}; - -/** - * @param {string} value the string value - * @returns {function(Expression): BasicEvaluatedExpression} plugin function - */ -exports.evaluateToString = value => { - return function stringExpression(expr) { - return new BasicEvaluatedExpression() - .setString(value) - .setRange(/** @type {Range} */ (expr.range)); - }; -}; - -/** - * @param {number} value the number value - * @returns {function(Expression): BasicEvaluatedExpression} plugin function - */ -exports.evaluateToNumber = value => { - return function stringExpression(expr) { - return new BasicEvaluatedExpression() - .setNumber(value) - .setRange(/** @type {Range} */ (expr.range)); - }; -}; - -/** - * @param {boolean} value the boolean value - * @returns {function(Expression): BasicEvaluatedExpression} plugin function - */ -exports.evaluateToBoolean = value => { - return function booleanExpression(expr) { - return new BasicEvaluatedExpression() - .setBoolean(value) - .setRange(/** @type {Range} */ (expr.range)); - }; -}; - -/** - * @param {string} identifier identifier - * @param {string} rootInfo rootInfo - * @param {function(): string[]} getMembers getMembers - * @param {boolean|null=} truthy is truthy, null if nullish - * @returns {function(Expression): BasicEvaluatedExpression} callback - */ -exports.evaluateToIdentifier = (identifier, rootInfo, getMembers, truthy) => { - return function identifierExpression(expr) { - let evaluatedExpression = new BasicEvaluatedExpression() - .setIdentifier(identifier, rootInfo, getMembers) - .setSideEffects(false) - .setRange(/** @type {Range} */ (expr.range)); - switch (truthy) { - case true: - evaluatedExpression.setTruthy(); - break; - case null: - evaluatedExpression.setNullish(true); - break; - case false: - evaluatedExpression.setFalsy(); - break; - } - - return evaluatedExpression; - }; -}; - -/** - * @param {JavascriptParser} parser the parser - * @param {string} message the message - * @returns {function(Expression): boolean | undefined} callback to handle unsupported expression - */ -exports.expressionIsUnsupported = (parser, message) => { - return function unsupportedExpression(expr) { - const dep = new ConstDependency( - "(void 0)", - /** @type {Range} */ (expr.range), - null - ); - dep.loc = /** @type {SourceLocation} */ (expr.loc); - parser.state.module.addPresentationalDependency(dep); - if (!parser.state.module) return; - parser.state.module.addWarning( - new UnsupportedFeatureWarning( - message, - /** @type {SourceLocation} */ (expr.loc) - ) - ); - return true; - }; -}; - -exports.skipTraversal = () => true; - -exports.approve = () => true; diff --git a/node_modules/webpack/lib/javascript/StartupHelpers.js b/node_modules/webpack/lib/javascript/StartupHelpers.js deleted file mode 100644 index d1f3b660..00000000 --- a/node_modules/webpack/lib/javascript/StartupHelpers.js +++ /dev/null @@ -1,132 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const RuntimeGlobals = require("../RuntimeGlobals"); -const Template = require("../Template"); -const { isSubset } = require("../util/SetHelpers"); -const { getAllChunks } = require("./ChunkHelpers"); - -/** @typedef {import("../util/Hash")} Hash */ -/** @typedef {import("../Chunk")} Chunk */ -/** @typedef {import("../Compilation")} Compilation */ -/** @typedef {import("../ChunkGraph")} ChunkGraph */ -/** @typedef {import("../ChunkGraph").EntryModuleWithChunkGroup} EntryModuleWithChunkGroup */ -/** @typedef {import("../ChunkGroup")} ChunkGroup */ -/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ -/** @typedef {(string|number)[]} EntryItem */ - -const EXPORT_PREFIX = `var ${RuntimeGlobals.exports} = `; - -/** - * @param {ChunkGraph} chunkGraph chunkGraph - * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate - * @param {EntryModuleWithChunkGroup[]} entries entries - * @param {Chunk} chunk chunk - * @param {boolean} passive true: passive startup with on chunks loaded - * @returns {string} runtime code - */ -exports.generateEntryStartup = ( - chunkGraph, - runtimeTemplate, - entries, - chunk, - passive -) => { - /** @type {string[]} */ - const runtime = [ - `var __webpack_exec__ = ${runtimeTemplate.returningFunction( - `${RuntimeGlobals.require}(${RuntimeGlobals.entryModuleId} = moduleId)`, - "moduleId" - )}` - ]; - - const runModule = id => { - return `__webpack_exec__(${JSON.stringify(id)})`; - }; - const outputCombination = (chunks, moduleIds, final) => { - if (chunks.size === 0) { - runtime.push( - `${final ? EXPORT_PREFIX : ""}(${moduleIds.map(runModule).join(", ")});` - ); - } else { - const fn = runtimeTemplate.returningFunction( - moduleIds.map(runModule).join(", ") - ); - runtime.push( - `${final && !passive ? EXPORT_PREFIX : ""}${ - passive - ? RuntimeGlobals.onChunksLoaded - : RuntimeGlobals.startupEntrypoint - }(0, ${JSON.stringify(Array.from(chunks, c => c.id))}, ${fn});` - ); - if (final && passive) { - runtime.push(`${EXPORT_PREFIX}${RuntimeGlobals.onChunksLoaded}();`); - } - } - }; - - let currentChunks = undefined; - let currentModuleIds = undefined; - - for (const [module, entrypoint] of entries) { - const runtimeChunk = entrypoint.getRuntimeChunk(); - const moduleId = chunkGraph.getModuleId(module); - const chunks = getAllChunks(entrypoint, chunk, runtimeChunk); - if ( - currentChunks && - currentChunks.size === chunks.size && - isSubset(currentChunks, chunks) - ) { - currentModuleIds.push(moduleId); - } else { - if (currentChunks) { - outputCombination(currentChunks, currentModuleIds); - } - currentChunks = chunks; - currentModuleIds = [moduleId]; - } - } - - // output current modules with export prefix - if (currentChunks) { - outputCombination(currentChunks, currentModuleIds, true); - } - runtime.push(""); - return Template.asString(runtime); -}; - -/** - * @param {Hash} hash the hash to update - * @param {ChunkGraph} chunkGraph chunkGraph - * @param {EntryModuleWithChunkGroup[]} entries entries - * @param {Chunk} chunk chunk - * @returns {void} - */ -exports.updateHashForEntryStartup = (hash, chunkGraph, entries, chunk) => { - for (const [module, entrypoint] of entries) { - const runtimeChunk = entrypoint.getRuntimeChunk(); - const moduleId = chunkGraph.getModuleId(module); - hash.update(`${moduleId}`); - for (const c of getAllChunks(entrypoint, chunk, runtimeChunk)) - hash.update(`${c.id}`); - } -}; - -/** - * @param {Chunk} chunk the chunk - * @param {ChunkGraph} chunkGraph the chunk graph - * @param {function(Chunk, ChunkGraph): boolean} filterFn filter function - * @returns {Set<number | string>} initially fulfilled chunk ids - */ -exports.getInitialChunkIds = (chunk, chunkGraph, filterFn) => { - const initialChunkIds = new Set(chunk.ids); - for (const c of chunk.getAllInitialChunks()) { - if (c === chunk || filterFn(c, chunkGraph)) continue; - for (const id of c.ids) initialChunkIds.add(id); - } - return initialChunkIds; -}; |
