| | |
| | | |
| | | "use strict"; |
| | | |
| | | const { SyncWaterfallHook } = require("tapable"); |
| | | const { |
| | | JAVASCRIPT_MODULE_TYPE_AUTO, |
| | | JAVASCRIPT_MODULE_TYPE_DYNAMIC, |
| | |
| | | /** @typedef {import("./javascript/JavascriptParser").DestructuringAssignmentProperties} DestructuringAssignmentProperties */ |
| | | /** @typedef {import("./javascript/JavascriptParser").Range} Range */ |
| | | /** @typedef {import("./logging/Logger").Logger} Logger */ |
| | | /** @typedef {import("./Compilation")} Compilation */ |
| | | |
| | | /** @typedef {null | undefined | RegExp | EXPECTED_FUNCTION | string | number | boolean | bigint | undefined} CodeValuePrimitive */ |
| | | /** @typedef {RecursiveArrayOrRecord<CodeValuePrimitive | RuntimeValue>} CodeValue */ |
| | | |
| | | /** |
| | | * Defines the runtime value options type used by this module. |
| | | * @typedef {object} RuntimeValueOptions |
| | | * @property {string[]=} fileDependencies |
| | | * @property {string[]=} contextDependencies |
| | | * @property {string[]=} missingDependencies |
| | | * @property {string[]=} buildDependencies |
| | | * @property {string| (() => string)=} version |
| | | * @property {string | (() => string)=} version |
| | | */ |
| | | |
| | | /** @typedef {(value: { module: NormalModule, key: string, readonly version: ValueCacheVersion }) => CodeValuePrimitive} GeneratorFn */ |
| | | |
| | | class RuntimeValue { |
| | | /** |
| | | * Creates an instance of RuntimeValue. |
| | | * @param {GeneratorFn} fn generator function |
| | | * @param {true | string[] | RuntimeValueOptions=} options options |
| | | */ |
| | | constructor(fn, options) { |
| | | /** @type {GeneratorFn} */ |
| | | this.fn = fn; |
| | | if (Array.isArray(options)) { |
| | | options = { |
| | | fileDependencies: options |
| | | }; |
| | | } |
| | | /** @type {true | RuntimeValueOptions} */ |
| | | this.options = options || {}; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns code. |
| | | * @param {JavascriptParser} parser the parser |
| | | * @param {ValueCacheVersions} valueCacheVersions valueCacheVersions |
| | | * @param {string} key the defined key |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns used keys. |
| | | * @param {DestructuringAssignmentProperties | undefined} properties properties |
| | | * @returns {Set<string> | undefined} used keys |
| | | */ |
| | |
| | | /** @typedef {boolean | undefined | null} AsiSafe */ |
| | | |
| | | /** |
| | | * @param {EXPECTED_ANY[] | {[k: string]: EXPECTED_ANY}} obj obj |
| | | * Returns code converted to string that evaluates. |
| | | * @param {EXPECTED_ANY[] | { [k: string]: EXPECTED_ANY }} obj obj |
| | | * @param {JavascriptParser} parser Parser |
| | | * @param {ValueCacheVersions} valueCacheVersions valueCacheVersions |
| | | * @param {string} key the defined key |
| | |
| | | asiSafe, |
| | | objKeys |
| | | ) => { |
| | | /** @type {string} */ |
| | | let code; |
| | | const arr = Array.isArray(obj); |
| | | if (arr) { |
| | |
| | | code = `{${keys |
| | | .map((key) => { |
| | | const code = obj[key]; |
| | | return `${JSON.stringify(key)}:${toCode( |
| | | return `${key === "__proto__" ? '["__proto__"]' : JSON.stringify(key)}:${toCode( |
| | | code, |
| | | parser, |
| | | valueCacheVersions, |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Returns result. |
| | | * @param {CodeValue} code code |
| | | * @returns {string | undefined} result |
| | | */ |
| | |
| | | ); |
| | | const WEBPACK_REQUIRE_IDENTIFIER_REGEXP = new RegExp(RuntimeGlobals.require); |
| | | |
| | | /** |
| | | * Defines the define plugin hooks type used by this module. |
| | | * @typedef {object} DefinePluginHooks |
| | | * @property {SyncWaterfallHook<[Record<string, CodeValue>]>} definitions |
| | | */ |
| | | |
| | | /** @typedef {Record<string, CodeValue>} Definitions */ |
| | | |
| | | /** @type {WeakMap<Compilation, DefinePluginHooks>} */ |
| | | const compilationHooksMap = new WeakMap(); |
| | | |
| | | class DefinePlugin { |
| | | /** |
| | | * Returns the attached hooks. |
| | | * @param {Compilation} compilation the compilation |
| | | * @returns {DefinePluginHooks} the attached hooks |
| | | */ |
| | | static getCompilationHooks(compilation) { |
| | | let hooks = compilationHooksMap.get(compilation); |
| | | if (hooks === undefined) { |
| | | hooks = { |
| | | definitions: new SyncWaterfallHook(["definitions"]) |
| | | }; |
| | | compilationHooksMap.set(compilation, hooks); |
| | | } |
| | | return hooks; |
| | | } |
| | | |
| | | /** |
| | | * Create a new define plugin |
| | | * @param {Record<string, CodeValue>} definitions A map of global object definitions |
| | | * @param {Definitions} definitions A map of global object definitions |
| | | */ |
| | | constructor(definitions) { |
| | | /** @type {Definitions} */ |
| | | this.definitions = definitions; |
| | | } |
| | | |
| | | /** |
| | | * Returns runtime value. |
| | | * @param {GeneratorFn} fn generator function |
| | | * @param {true | string[] | RuntimeValueOptions=} options options |
| | | * @returns {RuntimeValue} runtime value |
| | |
| | | } |
| | | |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler the compiler instance |
| | | * @returns {void} |
| | | */ |
| | |
| | | PLUGIN_NAME, |
| | | (compilation, { normalModuleFactory }) => { |
| | | const definitions = this.definitions; |
| | | const hooks = DefinePlugin.getCompilationHooks(compilation); |
| | | |
| | | hooks.definitions.tap(PLUGIN_NAME, (previousDefinitions) => ({ |
| | | ...previousDefinitions, |
| | | ...definitions |
| | | })); |
| | | |
| | | /** |
| | | * @type {Map<string, Set<string>>} |
| | |
| | | ); |
| | | |
| | | /** |
| | | * Handler |
| | | * Handles the hook callback for this code path. |
| | | * @param {JavascriptParser} parser Parser |
| | | * @returns {void} |
| | | */ |
| | | const handler = (parser) => { |
| | | /** @type {Set<string>} */ |
| | | const hooked = new Set(); |
| | | const mainValue = |
| | | /** @type {ValueCacheVersion} */ |
| | |
| | | }); |
| | | |
| | | /** |
| | | * Adds value dependency. |
| | | * @param {string} key key |
| | | */ |
| | | const addValueDependency = (key) => { |
| | |
| | | }; |
| | | |
| | | /** |
| | | * With value dependency. |
| | | * @template T |
| | | * @param {string} key key |
| | | * @param {(expression: Expression) => T} fn fn |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Walk definitions |
| | | * @param {Record<string, CodeValue>} definitions Definitions map |
| | | * Processes the provided definition. |
| | | * @param {Definitions} definitions Definitions map |
| | | * @param {string} prefix Prefix string |
| | | * @returns {void} |
| | | */ |
| | |
| | | !(code instanceof RegExp) |
| | | ) { |
| | | walkDefinitions( |
| | | /** @type {Record<string, CodeValue>} */ (code), |
| | | /** @type {Definitions} */ (code), |
| | | `${prefix + key}.` |
| | | ); |
| | | applyObjectDefine(prefix + key, code); |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Apply define key |
| | | * Processes the provided prefix. |
| | | * @param {string} prefix Prefix |
| | | * @param {string} key Key |
| | | * @returns {void} |
| | |
| | | if (destructed === undefined) { |
| | | return; |
| | | } |
| | | /** @type {Record<string, CodeValue>} */ |
| | | const obj = {}; |
| | | /** @type {Definitions} */ |
| | | const obj = Object.create(null); |
| | | const finalSet = finalByNestedKey.get(nested); |
| | | for (const { id } of destructed) { |
| | | const fullKey = `${nested}.${id}`; |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Apply Code |
| | | * Processes the provided key. |
| | | * @param {string} key Key |
| | | * @param {CodeValue} code Code |
| | | * @returns {void} |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Apply Object |
| | | * Processes the provided key. |
| | | * @param {string} key Key |
| | | * @param {object} obj Object |
| | | * @returns {void} |
| | |
| | | .tap(PLUGIN_NAME, handler); |
| | | |
| | | /** |
| | | * Walk definitions |
| | | * @param {Record<string, CodeValue>} definitions Definitions map |
| | | * Processes the provided definition. |
| | | * @param {Definitions} definitions Definitions map |
| | | * @param {string} prefix Prefix string |
| | | * @returns {void} |
| | | */ |
| | |
| | | !(code instanceof RegExp) |
| | | ) { |
| | | walkDefinitionsForValues( |
| | | /** @type {Record<string, CodeValue>} */ (code), |
| | | /** @type {Definitions} */ (code), |
| | | `${prefix + key}.` |
| | | ); |
| | | } |
| | |
| | | }; |
| | | |
| | | /** |
| | | * @param {Record<string, CodeValue>} definitions Definitions map |
| | | * Walk definitions for keys. |
| | | * @param {Definitions} definitions Definitions map |
| | | * @returns {void} |
| | | */ |
| | | const walkDefinitionsForKeys = (definitions) => { |
| | | /** |
| | | * Adds the provided map to the define plugin. |
| | | * @param {Map<string, Set<string>>} map Map |
| | | * @param {string} key key |
| | | * @param {string} value v |