diff options
Diffstat (limited to 'node_modules/webpack/lib/config')
| -rw-r--r-- | node_modules/webpack/lib/config/browserslistTargetHandler.js | 333 | ||||
| -rw-r--r-- | node_modules/webpack/lib/config/defaults.js | 1526 | ||||
| -rw-r--r-- | node_modules/webpack/lib/config/normalization.js | 567 | ||||
| -rw-r--r-- | node_modules/webpack/lib/config/target.js | 375 |
4 files changed, 2801 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/config/browserslistTargetHandler.js b/node_modules/webpack/lib/config/browserslistTargetHandler.js new file mode 100644 index 00000000..6a0e8a73 --- /dev/null +++ b/node_modules/webpack/lib/config/browserslistTargetHandler.js @@ -0,0 +1,333 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sergey Melyukov @smelukov +*/ + +"use strict"; + +const browserslist = require("browserslist"); +const path = require("path"); + +/** @typedef {import("./target").ApiTargetProperties} ApiTargetProperties */ +/** @typedef {import("./target").EcmaTargetProperties} EcmaTargetProperties */ +/** @typedef {import("./target").PlatformTargetProperties} PlatformTargetProperties */ + +// [[C:]/path/to/config][:env] +const inputRx = /^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$/i; + +/** + * @typedef {Object} BrowserslistHandlerConfig + * @property {string=} configPath + * @property {string=} env + * @property {string=} query + */ + +/** + * @param {string | null | undefined} input input string + * @param {string} context the context directory + * @returns {BrowserslistHandlerConfig} config + */ +const parse = (input, context) => { + if (!input) { + return {}; + } + + if (path.isAbsolute(input)) { + const [, configPath, env] = inputRx.exec(input) || []; + return { configPath, env }; + } + + const config = browserslist.findConfig(context); + + if (config && Object.keys(config).includes(input)) { + return { env: input }; + } + + return { query: input }; +}; + +/** + * @param {string | null | undefined} input input string + * @param {string} context the context directory + * @returns {string[] | undefined} selected browsers + */ +const load = (input, context) => { + const { configPath, env, query } = parse(input, context); + + // if a query is specified, then use it, else + // if a path to a config is specified then load it, else + // find a nearest config + const config = query + ? query + : configPath + ? browserslist.loadConfig({ + config: configPath, + env + }) + : browserslist.loadConfig({ path: context, env }); + + if (!config) return; + return browserslist(config); +}; + +/** + * @param {string[]} browsers supported browsers list + * @returns {EcmaTargetProperties & PlatformTargetProperties & ApiTargetProperties} target properties + */ +const resolve = browsers => { + /** + * Checks all against a version number + * @param {Record<string, number | [number, number]>} versions first supported version + * @returns {boolean} true if supports + */ + const rawChecker = versions => { + return browsers.every(v => { + const [name, parsedVersion] = v.split(" "); + if (!name) return false; + const requiredVersion = versions[name]; + if (!requiredVersion) return false; + const [parsedMajor, parserMinor] = + // safari TP supports all features for normal safari + parsedVersion === "TP" + ? [Infinity, Infinity] + : parsedVersion.split("."); + if (typeof requiredVersion === "number") { + return +parsedMajor >= requiredVersion; + } + return requiredVersion[0] === +parsedMajor + ? +parserMinor >= requiredVersion[1] + : +parsedMajor > requiredVersion[0]; + }); + }; + const anyNode = browsers.some(b => /^node /.test(b)); + const anyBrowser = browsers.some(b => /^(?!node)/.test(b)); + const browserProperty = !anyBrowser ? false : anyNode ? null : true; + const nodeProperty = !anyNode ? false : anyBrowser ? null : true; + // Internet Explorer Mobile, Blackberry browser and Opera Mini are very old browsers, they do not support new features + const es6DynamicImport = rawChecker({ + chrome: 63, + and_chr: 63, + edge: 79, + firefox: 67, + and_ff: 67, + // ie: Not supported + opera: 50, + op_mob: 46, + safari: [11, 1], + ios_saf: [11, 3], + samsung: [8, 2], + android: 63, + and_qq: [10, 4], + // baidu: Not supported + // and_uc: Not supported + kaios: [3, 0], + node: [12, 17] + }); + + return { + const: rawChecker({ + chrome: 49, + and_chr: 49, + edge: 12, + // Prior to Firefox 13, <code>const</code> is implemented, but re-assignment is not failing. + // Prior to Firefox 46, a <code>TypeError</code> was thrown on redeclaration instead of a <code>SyntaxError</code>. + firefox: 36, + and_ff: 36, + // Not supported in for-in and for-of loops + // ie: Not supported + opera: 36, + op_mob: 36, + safari: [10, 0], + ios_saf: [10, 0], + // Before 5.0 supported correctly in strict mode, otherwise supported without block scope + samsung: [5, 0], + android: 37, + and_qq: [10, 4], + // Supported correctly in strict mode, otherwise supported without block scope + // baidu: Not supported + and_uc: [12, 12], + kaios: [2, 5], + node: [6, 0] + }), + arrowFunction: rawChecker({ + chrome: 45, + and_chr: 45, + edge: 12, + // The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of <code>'use strict';</code> is now required. + // Prior to Firefox 39, a line terminator (<code>\\n</code>) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like <code>() \\n => {}</code> will now throw a <code>SyntaxError</code> in this and later versions. + firefox: 39, + and_ff: 39, + // ie: Not supported, + opera: 32, + op_mob: 32, + safari: 10, + ios_saf: 10, + samsung: [5, 0], + android: 45, + and_qq: [10, 4], + baidu: [7, 12], + and_uc: [12, 12], + kaios: [2, 5], + node: [6, 0] + }), + forOf: rawChecker({ + chrome: 38, + and_chr: 38, + edge: 12, + // Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration"). + firefox: 51, + and_ff: 51, + // ie: Not supported, + opera: 25, + op_mob: 25, + safari: 7, + ios_saf: 7, + samsung: [3, 0], + android: 38, + // and_qq: Unknown support + // baidu: Unknown support + // and_uc: Unknown support + kaios: [3, 0], + node: [0, 12] + }), + destructuring: rawChecker({ + chrome: 49, + and_chr: 49, + edge: 14, + firefox: 41, + and_ff: 41, + // ie: Not supported, + opera: 36, + op_mob: 36, + safari: 8, + ios_saf: 8, + samsung: [5, 0], + android: 49, + // and_qq: Unknown support + // baidu: Unknown support + // and_uc: Unknown support + kaios: [2, 5], + node: [6, 0] + }), + bigIntLiteral: rawChecker({ + chrome: 67, + and_chr: 67, + edge: 79, + firefox: 68, + and_ff: 68, + // ie: Not supported, + opera: 54, + op_mob: 48, + safari: 14, + ios_saf: 14, + samsung: [9, 2], + android: 67, + // and_qq: Not supported + // baidu: Not supported + // and_uc: Not supported + kaios: [3, 0], + node: [10, 4] + }), + // Support syntax `import` and `export` and no limitations and bugs on Node.js + // Not include `export * as namespace` + module: rawChecker({ + chrome: 61, + and_chr: 61, + edge: 16, + firefox: 60, + and_ff: 60, + // ie: Not supported, + opera: 48, + op_mob: 45, + safari: [10, 1], + ios_saf: [10, 3], + samsung: [8, 0], + android: 61, + and_qq: [10, 4], + // baidu: Not supported + // and_uc: Not supported + kaios: [3, 0], + node: [12, 17] + }), + dynamicImport: es6DynamicImport, + dynamicImportInWorker: es6DynamicImport && !anyNode, + // browserslist does not have info about globalThis + // so this is based on mdn-browser-compat-data + globalThis: rawChecker({ + chrome: 71, + and_chr: 71, + edge: 79, + firefox: 65, + and_ff: 65, + // ie: Not supported, + opera: 58, + op_mob: 50, + safari: [12, 1], + ios_saf: [12, 2], + samsung: [10, 1], + android: 71, + // and_qq: Unknown support + // baidu: Unknown support + // and_uc: Unknown support + kaios: [3, 0], + node: 12 + }), + optionalChaining: rawChecker({ + chrome: 80, + and_chr: 80, + edge: 80, + firefox: 74, + and_ff: 79, + // ie: Not supported, + opera: 67, + op_mob: 64, + safari: [13, 1], + ios_saf: [13, 4], + samsung: 13, + android: 80, + // and_qq: Not supported + // baidu: Not supported + // and_uc: Not supported + kaios: [3, 0], + node: 14 + }), + templateLiteral: rawChecker({ + chrome: 41, + and_chr: 41, + edge: 13, + firefox: 34, + and_ff: 34, + // ie: Not supported, + opera: 29, + op_mob: 64, + safari: [9, 1], + ios_saf: 9, + samsung: 4, + android: 41, + and_qq: [10, 4], + baidu: [7, 12], + and_uc: [12, 12], + kaios: [2, 5], + node: 4 + }), + browser: browserProperty, + electron: false, + node: nodeProperty, + nwjs: false, + web: browserProperty, + webworker: false, + + document: browserProperty, + fetchWasm: browserProperty, + global: nodeProperty, + importScripts: false, + importScriptsInWorker: true, + nodeBuiltins: nodeProperty, + require: nodeProperty + }; +}; + +module.exports = { + resolve, + load +}; diff --git a/node_modules/webpack/lib/config/defaults.js b/node_modules/webpack/lib/config/defaults.js new file mode 100644 index 00000000..097e62ea --- /dev/null +++ b/node_modules/webpack/lib/config/defaults.js @@ -0,0 +1,1526 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const { + JAVASCRIPT_MODULE_TYPE_AUTO, + JSON_MODULE_TYPE, + WEBASSEMBLY_MODULE_TYPE_ASYNC, + JAVASCRIPT_MODULE_TYPE_ESM, + JAVASCRIPT_MODULE_TYPE_DYNAMIC, + WEBASSEMBLY_MODULE_TYPE_SYNC, + ASSET_MODULE_TYPE, + CSS_MODULE_TYPE_AUTO, + CSS_MODULE_TYPE, + CSS_MODULE_TYPE_MODULE +} = require("../ModuleTypeConstants"); +const Template = require("../Template"); +const { cleverMerge } = require("../util/cleverMerge"); +const { + getTargetsProperties, + getTargetProperties, + getDefaultTarget +} = require("./target"); + +/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */ +/** @typedef {import("../../declarations/WebpackOptions").Context} Context */ +/** @typedef {import("../../declarations/WebpackOptions").CssExperimentOptions} CssExperimentOptions */ +/** @typedef {import("../../declarations/WebpackOptions").EntryDescription} EntryDescription */ +/** @typedef {import("../../declarations/WebpackOptions").EntryNormalized} Entry */ +/** @typedef {import("../../declarations/WebpackOptions").EntryStaticNormalized} EntryStaticNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").Environment} Environment */ +/** @typedef {import("../../declarations/WebpackOptions").Experiments} Experiments */ +/** @typedef {import("../../declarations/WebpackOptions").ExperimentsNormalized} ExperimentsNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").ExternalsPresets} ExternalsPresets */ +/** @typedef {import("../../declarations/WebpackOptions").ExternalsType} ExternalsType */ +/** @typedef {import("../../declarations/WebpackOptions").FileCacheOptions} FileCacheOptions */ +/** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */ +/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ +/** @typedef {import("../../declarations/WebpackOptions").Library} Library */ +/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */ +/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */ +/** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */ +/** @typedef {import("../../declarations/WebpackOptions").Loader} Loader */ +/** @typedef {import("../../declarations/WebpackOptions").Mode} Mode */ +/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */ +/** @typedef {import("../../declarations/WebpackOptions").Node} WebpackNode */ +/** @typedef {import("../../declarations/WebpackOptions").Optimization} Optimization */ +/** @typedef {import("../../declarations/WebpackOptions").OptimizationSplitChunksOptions} OptimizationSplitChunksOptions */ +/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */ +/** @typedef {import("../../declarations/WebpackOptions").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */ +/** @typedef {import("../../declarations/WebpackOptions").Performance} Performance */ +/** @typedef {import("../../declarations/WebpackOptions").ResolveOptions} ResolveOptions */ +/** @typedef {import("../../declarations/WebpackOptions").RuleSetRules} RuleSetRules */ +/** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */ +/** @typedef {import("../../declarations/WebpackOptions").Target} Target */ +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */ +/** @typedef {import("../Compiler")} Compiler */ +/** @typedef {import("../Module")} Module */ +/** @typedef {import("./target").TargetProperties} TargetProperties */ + +const NODE_MODULES_REGEXP = /[\\/]node_modules[\\/]/i; + +/** + * Sets a constant default value when undefined + * @template T + * @template {keyof T} P + * @param {T} obj an object + * @param {P} prop a property of this object + * @param {T[P]} value a default value of the property + * @returns {void} + */ +const D = (obj, prop, value) => { + if (obj[prop] === undefined) { + obj[prop] = value; + } +}; + +/** + * Sets a dynamic default value when undefined, by calling the factory function + * @template T + * @template {keyof T} P + * @param {T} obj an object + * @param {P} prop a property of this object + * @param {function(): T[P]} factory a default value factory for the property + * @returns {void} + */ +const F = (obj, prop, factory) => { + if (obj[prop] === undefined) { + obj[prop] = factory(); + } +}; + +/** + * Sets a dynamic default value when undefined, by calling the factory function. + * factory must return an array or undefined + * When the current value is already an array an contains "..." it's replaced with + * the result of the factory function + * @template T + * @template {keyof T} P + * @param {T} obj an object + * @param {P} prop a property of this object + * @param {function(): T[P]} factory a default value factory for the property + * @returns {void} + */ +const A = (obj, prop, factory) => { + const value = obj[prop]; + if (value === undefined) { + obj[prop] = factory(); + } else if (Array.isArray(value)) { + /** @type {any[] | undefined} */ + let newArray = undefined; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + if (item === "...") { + if (newArray === undefined) { + newArray = value.slice(0, i); + obj[prop] = /** @type {T[P]} */ (/** @type {unknown} */ (newArray)); + } + const items = /** @type {any[]} */ (/** @type {unknown} */ (factory())); + if (items !== undefined) { + for (const item of items) { + newArray.push(item); + } + } + } else if (newArray !== undefined) { + newArray.push(item); + } + } + } +}; + +/** + * @param {WebpackOptions} options options to be modified + * @returns {void} + */ +const applyWebpackOptionsBaseDefaults = options => { + F(options, "context", () => process.cwd()); + applyInfrastructureLoggingDefaults(options.infrastructureLogging); +}; + +/** + * @param {WebpackOptions} options options to be modified + * @returns {void} + */ +const applyWebpackOptionsDefaults = options => { + F(options, "context", () => process.cwd()); + F(options, "target", () => { + return getDefaultTarget(/** @type {string} */ (options.context)); + }); + + const { mode, name, target } = options; + + let targetProperties = + target === false + ? /** @type {false} */ (false) + : typeof target === "string" + ? getTargetProperties(target, /** @type {Context} */ (options.context)) + : getTargetsProperties( + /** @type {string[]} */ (target), + /** @type {Context} */ (options.context) + ); + + const development = mode === "development"; + const production = mode === "production" || !mode; + + if (typeof options.entry !== "function") { + for (const key of Object.keys(options.entry)) { + F( + options.entry[key], + "import", + () => /** @type {[string]} */ (["./src"]) + ); + } + } + + F(options, "devtool", () => (development ? "eval" : false)); + D(options, "watch", false); + D(options, "profile", false); + D(options, "parallelism", 100); + D(options, "recordsInputPath", false); + D(options, "recordsOutputPath", false); + + applyExperimentsDefaults(options.experiments, { + production, + development, + targetProperties + }); + + const futureDefaults = + /** @type {NonNullable<ExperimentsNormalized["futureDefaults"]>} */ + (options.experiments.futureDefaults); + + F(options, "cache", () => + development ? { type: /** @type {"memory"} */ ("memory") } : false + ); + applyCacheDefaults(options.cache, { + name: name || "default", + mode: mode || "production", + development, + cacheUnaffected: options.experiments.cacheUnaffected + }); + const cache = !!options.cache; + + applySnapshotDefaults(options.snapshot, { + production, + futureDefaults + }); + + applyModuleDefaults(options.module, { + cache, + syncWebAssembly: + /** @type {NonNullable<ExperimentsNormalized["syncWebAssembly"]>} */ + (options.experiments.syncWebAssembly), + asyncWebAssembly: + /** @type {NonNullable<ExperimentsNormalized["asyncWebAssembly"]>} */ + (options.experiments.asyncWebAssembly), + css: + /** @type {NonNullable<ExperimentsNormalized["css"]>} */ + (options.experiments.css), + futureDefaults, + isNode: targetProperties && targetProperties.node === true + }); + + applyOutputDefaults(options.output, { + context: /** @type {Context} */ (options.context), + targetProperties, + isAffectedByBrowserslist: + target === undefined || + (typeof target === "string" && target.startsWith("browserslist")) || + (Array.isArray(target) && + target.some(target => target.startsWith("browserslist"))), + outputModule: + /** @type {NonNullable<ExperimentsNormalized["outputModule"]>} */ + (options.experiments.outputModule), + development, + entry: options.entry, + module: options.module, + futureDefaults + }); + + applyExternalsPresetsDefaults(options.externalsPresets, { + targetProperties, + buildHttp: !!options.experiments.buildHttp + }); + + applyLoaderDefaults( + /** @type {NonNullable<WebpackOptions["loader"]>} */ (options.loader), + { targetProperties, environment: options.output.environment } + ); + + F(options, "externalsType", () => { + const validExternalTypes = require("../../schemas/WebpackOptions.json") + .definitions.ExternalsType.enum; + return options.output.library && + validExternalTypes.includes(options.output.library.type) + ? /** @type {ExternalsType} */ (options.output.library.type) + : options.output.module + ? "module" + : "var"; + }); + + applyNodeDefaults(options.node, { + futureDefaults: + /** @type {NonNullable<WebpackOptions["experiments"]["futureDefaults"]>} */ + (options.experiments.futureDefaults), + targetProperties + }); + + F(options, "performance", () => + production && + targetProperties && + (targetProperties.browser || targetProperties.browser === null) + ? {} + : false + ); + applyPerformanceDefaults( + /** @type {NonNullable<WebpackOptions["performance"]>} */ + (options.performance), + { + production + } + ); + + applyOptimizationDefaults(options.optimization, { + development, + production, + css: + /** @type {NonNullable<ExperimentsNormalized["css"]>} */ + (options.experiments.css), + records: !!(options.recordsInputPath || options.recordsOutputPath) + }); + + options.resolve = cleverMerge( + getResolveDefaults({ + cache, + context: /** @type {Context} */ (options.context), + targetProperties, + mode: /** @type {Mode} */ (options.mode), + css: + /** @type {NonNullable<ExperimentsNormalized["css"]>} */ + (options.experiments.css) + }), + options.resolve + ); + + options.resolveLoader = cleverMerge( + getResolveLoaderDefaults({ cache }), + options.resolveLoader + ); +}; + +/** + * @param {ExperimentsNormalized} experiments options + * @param {Object} options options + * @param {boolean} options.production is production + * @param {boolean} options.development is development mode + * @param {TargetProperties | false} options.targetProperties target properties + * @returns {void} + */ +const applyExperimentsDefaults = ( + experiments, + { production, development, targetProperties } +) => { + D(experiments, "futureDefaults", false); + D(experiments, "backCompat", !experiments.futureDefaults); + D(experiments, "syncWebAssembly", false); + D(experiments, "asyncWebAssembly", experiments.futureDefaults); + D(experiments, "outputModule", false); + D(experiments, "layers", false); + D(experiments, "lazyCompilation", undefined); + D(experiments, "buildHttp", undefined); + D(experiments, "cacheUnaffected", experiments.futureDefaults); + F(experiments, "css", () => (experiments.futureDefaults ? {} : undefined)); + + // TODO webpack 6: remove this. topLevelAwait should be enabled by default + let shouldEnableTopLevelAwait = true; + if (typeof experiments.topLevelAwait === "boolean") { + shouldEnableTopLevelAwait = experiments.topLevelAwait; + } + D(experiments, "topLevelAwait", shouldEnableTopLevelAwait); + + if (typeof experiments.buildHttp === "object") { + D(experiments.buildHttp, "frozen", production); + D(experiments.buildHttp, "upgrade", false); + } + + if (typeof experiments.css === "object") { + D( + experiments.css, + "exportsOnly", + !targetProperties || !targetProperties.document + ); + } +}; + +/** + * @param {CacheOptions} cache options + * @param {Object} options options + * @param {string} options.name name + * @param {Mode} options.mode mode + * @param {boolean} options.development is development mode + * @param {Experiments["cacheUnaffected"]} options.cacheUnaffected the cacheUnaffected experiment is enabled + * @returns {void} + */ +const applyCacheDefaults = ( + cache, + { name, mode, development, cacheUnaffected } +) => { + if (cache === false) return; + switch (cache.type) { + case "filesystem": + F(cache, "name", () => name + "-" + mode); + D(cache, "version", ""); + F(cache, "cacheDirectory", () => { + const cwd = process.cwd(); + /** @type {string | undefined} */ + let dir = cwd; + for (;;) { + try { + if (fs.statSync(path.join(dir, "package.json")).isFile()) break; + // eslint-disable-next-line no-empty + } catch (e) {} + const parent = path.dirname(dir); + if (dir === parent) { + dir = undefined; + break; + } + dir = parent; + } + if (!dir) { + return path.resolve(cwd, ".cache/webpack"); + } else if (process.versions.pnp === "1") { + return path.resolve(dir, ".pnp/.cache/webpack"); + } else if (process.versions.pnp === "3") { + return path.resolve(dir, ".yarn/.cache/webpack"); + } else { + return path.resolve(dir, "node_modules/.cache/webpack"); + } + }); + F(cache, "cacheLocation", () => + path.resolve( + /** @type {NonNullable<FileCacheOptions["cacheDirectory"]>} */ + (cache.cacheDirectory), + /** @type {NonNullable<FileCacheOptions["name"]>} */ (cache.name) + ) + ); + D(cache, "hashAlgorithm", "md4"); + D(cache, "store", "pack"); + D(cache, "compression", false); + D(cache, "profile", false); + D(cache, "idleTimeout", 60000); + D(cache, "idleTimeoutForInitialStore", 5000); + D(cache, "idleTimeoutAfterLargeChanges", 1000); + D(cache, "maxMemoryGenerations", development ? 5 : Infinity); + D(cache, "maxAge", 1000 * 60 * 60 * 24 * 60); // 1 month + D(cache, "allowCollectingMemory", development); + D(cache, "memoryCacheUnaffected", development && cacheUnaffected); + D(cache, "readonly", false); + D( + /** @type {NonNullable<FileCacheOptions["buildDependencies"]>} */ + (cache.buildDependencies), + "defaultWebpack", + [path.resolve(__dirname, "..") + path.sep] + ); + break; + case "memory": + D(cache, "maxGenerations", Infinity); + D(cache, "cacheUnaffected", development && cacheUnaffected); + break; + } +}; + +/** + * @param {SnapshotOptions} snapshot options + * @param {Object} options options + * @param {boolean} options.production is production + * @param {boolean} options.futureDefaults is future defaults enabled + * @returns {void} + */ +const applySnapshotDefaults = (snapshot, { production, futureDefaults }) => { + if (futureDefaults) { + F(snapshot, "managedPaths", () => + process.versions.pnp === "3" + ? [ + /^(.+?(?:[\\/]\.yarn[\\/]unplugged[\\/][^\\/]+)?[\\/]node_modules[\\/])/ + ] + : [/^(.+?[\\/]node_modules[\\/])/] + ); + F(snapshot, "immutablePaths", () => + process.versions.pnp === "3" + ? [/^(.+?[\\/]cache[\\/][^\\/]+\.zip[\\/]node_modules[\\/])/] + : [] + ); + } else { + A(snapshot, "managedPaths", () => { + if (process.versions.pnp === "3") { + const match = + /^(.+?)[\\/]cache[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec( + require.resolve("watchpack") + ); + if (match) { + return [path.resolve(match[1], "unplugged")]; + } + } else { + const match = /^(.+?[\\/]node_modules[\\/])/.exec( + // eslint-disable-next-line node/no-extraneous-require + require.resolve("watchpack") + ); + if (match) { + return [match[1]]; + } + } + return []; + }); + A(snapshot, "immutablePaths", () => { + if (process.versions.pnp === "1") { + const match = + /^(.+?[\\/]v4)[\\/]npm-watchpack-[^\\/]+-[\da-f]{40}[\\/]node_modules[\\/]/.exec( + require.resolve("watchpack") + ); + if (match) { + return [match[1]]; + } + } else if (process.versions.pnp === "3") { + const match = + /^(.+?)[\\/]watchpack-npm-[^\\/]+\.zip[\\/]node_modules[\\/]/.exec( + require.resolve("watchpack") + ); + if (match) { + return [match[1]]; + } + } + return []; + }); + } + F(snapshot, "resolveBuildDependencies", () => ({ + timestamp: true, + hash: true + })); + F(snapshot, "buildDependencies", () => ({ timestamp: true, hash: true })); + F(snapshot, "module", () => + production ? { timestamp: true, hash: true } : { timestamp: true } + ); + F(snapshot, "resolve", () => + production ? { timestamp: true, hash: true } : { timestamp: true } + ); +}; + +/** + * @param {JavascriptParserOptions} parserOptions parser options + * @param {Object} options options + * @param {boolean} options.futureDefaults is future defaults enabled + * @param {boolean} options.isNode is node target platform + * @returns {void} + */ +const applyJavascriptParserOptionsDefaults = ( + parserOptions, + { futureDefaults, isNode } +) => { + D(parserOptions, "unknownContextRequest", "."); + D(parserOptions, "unknownContextRegExp", false); + D(parserOptions, "unknownContextRecursive", true); + D(parserOptions, "unknownContextCritical", true); + D(parserOptions, "exprContextRequest", "."); + D(parserOptions, "exprContextRegExp", false); + D(parserOptions, "exprContextRecursive", true); + D(parserOptions, "exprContextCritical", true); + D(parserOptions, "wrappedContextRegExp", /.*/); + D(parserOptions, "wrappedContextRecursive", true); + D(parserOptions, "wrappedContextCritical", false); + D(parserOptions, "strictThisContextOnImports", false); + D(parserOptions, "importMeta", true); + D(parserOptions, "dynamicImportMode", "lazy"); + D(parserOptions, "dynamicImportPrefetch", false); + D(parserOptions, "dynamicImportPreload", false); + D(parserOptions, "dynamicImportFetchPriority", false); + D(parserOptions, "createRequire", isNode); + if (futureDefaults) D(parserOptions, "exportsPresence", "error"); +}; + +/** + * @param {ModuleOptions} module options + * @param {Object} options options + * @param {boolean} options.cache is caching enabled + * @param {boolean} options.syncWebAssembly is syncWebAssembly enabled + * @param {boolean} options.asyncWebAssembly is asyncWebAssembly enabled + * @param {CssExperimentOptions|false} options.css is css enabled + * @param {boolean} options.futureDefaults is future defaults enabled + * @param {boolean} options.isNode is node target platform + * @returns {void} + */ +const applyModuleDefaults = ( + module, + { cache, syncWebAssembly, asyncWebAssembly, css, futureDefaults, isNode } +) => { + if (cache) { + D( + module, + "unsafeCache", + /** + * @param {Module} module module + * @returns {boolean | null | string} true, if we want to cache the module + */ + module => { + const name = module.nameForCondition(); + return name && NODE_MODULES_REGEXP.test(name); + } + ); + } else { + D(module, "unsafeCache", false); + } + + F(module.parser, ASSET_MODULE_TYPE, () => ({})); + F( + /** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */ + (module.parser.asset), + "dataUrlCondition", + () => ({}) + ); + if ( + typeof ( + /** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */ + (module.parser.asset).dataUrlCondition + ) === "object" + ) { + D( + /** @type {NonNullable<ParserOptionsByModuleTypeKnown["asset"]>} */ + (module.parser.asset).dataUrlCondition, + "maxSize", + 8096 + ); + } + + F(module.parser, "javascript", () => ({})); + + applyJavascriptParserOptionsDefaults( + /** @type {NonNullable<ParserOptionsByModuleTypeKnown["javascript"]>} */ + (module.parser.javascript), + { + futureDefaults, + isNode + } + ); + + A(module, "defaultRules", () => { + const esm = { + type: JAVASCRIPT_MODULE_TYPE_ESM, + resolve: { + byDependency: { + esm: { + fullySpecified: true + } + } + } + }; + const commonjs = { + type: JAVASCRIPT_MODULE_TYPE_DYNAMIC + }; + /** @type {RuleSetRules} */ + const rules = [ + { + mimetype: "application/node", + type: JAVASCRIPT_MODULE_TYPE_AUTO + }, + { + test: /\.json$/i, + type: JSON_MODULE_TYPE + }, + { + mimetype: "application/json", + type: JSON_MODULE_TYPE + }, + { + test: /\.mjs$/i, + ...esm + }, + { + test: /\.js$/i, + descriptionData: { + type: "module" + }, + ...esm + }, + { + test: /\.cjs$/i, + ...commonjs + }, + { + test: /\.js$/i, + descriptionData: { + type: "commonjs" + }, + ...commonjs + }, + { + mimetype: { + or: ["text/javascript", "application/javascript"] + }, + ...esm + } + ]; + if (asyncWebAssembly) { + const wasm = { + type: WEBASSEMBLY_MODULE_TYPE_ASYNC, + rules: [ + { + descriptionData: { + type: "module" + }, + resolve: { + fullySpecified: true + } + } + ] + }; + rules.push({ + test: /\.wasm$/i, + ...wasm + }); + rules.push({ + mimetype: "application/wasm", + ...wasm + }); + } else if (syncWebAssembly) { + const wasm = { + type: WEBASSEMBLY_MODULE_TYPE_SYNC, + rules: [ + { + descriptionData: { + type: "module" + }, + resolve: { + fullySpecified: true + } + } + ] + }; + rules.push({ + test: /\.wasm$/i, + ...wasm + }); + rules.push({ + mimetype: "application/wasm", + ...wasm + }); + } + if (css) { + const resolve = { + fullySpecified: true, + preferRelative: true + }; + rules.push({ + test: /\.css$/i, + type: CSS_MODULE_TYPE_AUTO, + resolve + }); + rules.push({ + mimetype: "text/css+module", + type: CSS_MODULE_TYPE_MODULE, + resolve + }); + rules.push({ + mimetype: "text/css", + type: CSS_MODULE_TYPE, + resolve + }); + } + rules.push( + { + dependency: "url", + oneOf: [ + { + scheme: /^data$/, + type: "asset/inline" + }, + { + type: "asset/resource" + } + ] + }, + { + assert: { type: "json" }, + type: JSON_MODULE_TYPE + } + ); + return rules; + }); +}; + +/** + * @param {Output} output options + * @param {Object} options options + * @param {string} options.context context + * @param {TargetProperties | false} options.targetProperties target properties + * @param {boolean} options.isAffectedByBrowserslist is affected by browserslist + * @param {boolean} options.outputModule is outputModule experiment enabled + * @param {boolean} options.development is development mode + * @param {Entry} options.entry entry option + * @param {ModuleOptions} options.module module option + * @param {boolean} options.futureDefaults is future defaults enabled + * @returns {void} + */ +const applyOutputDefaults = ( + output, + { + context, + targetProperties: tp, + isAffectedByBrowserslist, + outputModule, + development, + entry, + module, + futureDefaults + } +) => { + /** + * @param {Library=} library the library option + * @returns {string} a readable library name + */ + const getLibraryName = library => { + const libraryName = + typeof library === "object" && + library && + !Array.isArray(library) && + "type" in library + ? library.name + : /** @type {LibraryName} */ (library); + if (Array.isArray(libraryName)) { + return libraryName.join("."); + } else if (typeof libraryName === "object") { + return getLibraryName(libraryName.root); + } else if (typeof libraryName === "string") { + return libraryName; + } + return ""; + }; + + F(output, "uniqueName", () => { + const libraryName = getLibraryName(output.library).replace( + /^\[(\\*[\w:]+\\*)\](\.)|(\.)\[(\\*[\w:]+\\*)\](?=\.|$)|\[(\\*[\w:]+\\*)\]/g, + (m, a, d1, d2, b, c) => { + const content = a || b || c; + return content.startsWith("\\") && content.endsWith("\\") + ? `${d2 || ""}[${content.slice(1, -1)}]${d1 || ""}` + : ""; + } + ); + if (libraryName) return libraryName; + const pkgPath = path.resolve(context, "package.json"); + try { + const packageInfo = JSON.parse(fs.readFileSync(pkgPath, "utf-8")); + return packageInfo.name || ""; + } catch (e) { + if (/** @type {Error & { code: string }} */ (e).code !== "ENOENT") { + /** @type {Error & { code: string }} */ + ( + e + ).message += `\nwhile determining default 'output.uniqueName' from 'name' in ${pkgPath}`; + throw e; + } + return ""; + } + }); + + F(output, "module", () => !!outputModule); + D(output, "filename", output.module ? "[name].mjs" : "[name].js"); + F(output, "iife", () => !output.module); + D(output, "importFunctionName", "import"); + D(output, "importMetaName", "import.meta"); + F(output, "chunkFilename", () => { + const filename = + /** @type {NonNullable<Output["chunkFilename"]>} */ + (output.filename); + if (typeof filename !== "function") { + const hasName = filename.includes("[name]"); + const hasId = filename.includes("[id]"); + const hasChunkHash = filename.includes("[chunkhash]"); + const hasContentHash = filename.includes("[contenthash]"); + // Anything changing depending on chunk is fine + if (hasChunkHash || hasContentHash || hasName || hasId) return filename; + // Otherwise prefix "[id]." in front of the basename to make it changing + return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2"); + } + return output.module ? "[id].mjs" : "[id].js"; + }); + F(output, "cssFilename", () => { + const filename = + /** @type {NonNullable<Output["cssFilename"]>} */ + (output.filename); + if (typeof filename !== "function") { + return filename.replace(/\.[mc]?js(\?|$)/, ".css$1"); + } + return "[id].css"; + }); + F(output, "cssChunkFilename", () => { + const chunkFilename = + /** @type {NonNullable<Output["cssChunkFilename"]>} */ + (output.chunkFilename); + if (typeof chunkFilename !== "function") { + return chunkFilename.replace(/\.[mc]?js(\?|$)/, ".css$1"); + } + return "[id].css"; + }); + D(output, "assetModuleFilename", "[hash][ext][query]"); + D(output, "webassemblyModuleFilename", "[hash].module.wasm"); + D(output, "compareBeforeEmit", true); + D(output, "charset", true); + F(output, "hotUpdateGlobal", () => + Template.toIdentifier( + "webpackHotUpdate" + + Template.toIdentifier( + /** @type {NonNullable<Output["uniqueName"]>} */ (output.uniqueName) + ) + ) + ); + F(output, "chunkLoadingGlobal", () => + Template.toIdentifier( + "webpackChunk" + + Template.toIdentifier( + /** @type {NonNullable<Output["uniqueName"]>} */ (output.uniqueName) + ) + ) + ); + F(output, "globalObject", () => { + if (tp) { + if (tp.global) return "global"; + if (tp.globalThis) return "globalThis"; + } + return "self"; + }); + F(output, "chunkFormat", () => { + if (tp) { + const helpMessage = isAffectedByBrowserslist + ? "Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly." + : "Select an appropriate 'target' to allow selecting one by default, or specify the 'output.chunkFormat' directly."; + if (output.module) { + if (tp.dynamicImport) return "module"; + if (tp.document) return "array-push"; + throw new Error( + "For the selected environment is no default ESM chunk format available:\n" + + "ESM exports can be chosen when 'import()' is available.\n" + + "JSONP Array push can be chosen when 'document' is available.\n" + + helpMessage + ); + } else { + if (tp.document) return "array-push"; + if (tp.require) return "commonjs"; + if (tp.nodeBuiltins) return "commonjs"; + if (tp.importScripts) return "array-push"; + throw new Error( + "For the selected environment is no default script chunk format available:\n" + + "JSONP Array push can be chosen when 'document' or 'importScripts' is available.\n" + + "CommonJs exports can be chosen when 'require' or node builtins are available.\n" + + helpMessage + ); + } + } + throw new Error( + "Chunk format can't be selected by default when no target is specified" + ); + }); + D(output, "asyncChunks", true); + F(output, "chunkLoading", () => { + if (tp) { + switch (output.chunkFormat) { + case "array-push": + if (tp.document) return "jsonp"; + if (tp.importScripts) return "import-scripts"; + break; + case "commonjs": + if (tp.require) return "require"; + if (tp.nodeBuiltins) return "async-node"; + break; + case "module": + if (tp.dynamicImport) return "import"; + break; + } + if ( + tp.require === null || + tp.nodeBuiltins === null || + tp.document === null || + tp.importScripts === null + ) { + return "universal"; + } + } + return false; + }); + F(output, "workerChunkLoading", () => { + if (tp) { + switch (output.chunkFormat) { + case "array-push": + if (tp.importScriptsInWorker) return "import-scripts"; + break; + case "commonjs": + if (tp.require) return "require"; + if (tp.nodeBuiltins) return "async-node"; + break; + case "module": + if (tp.dynamicImportInWorker) return "import"; + break; + } + if ( + tp.require === null || + tp.nodeBuiltins === null || + tp.importScriptsInWorker === null + ) { + return "universal"; + } + } + return false; + }); + F(output, "wasmLoading", () => { + if (tp) { + if (tp.fetchWasm) return "fetch"; + if (tp.nodeBuiltins) + return output.module ? "async-node-module" : "async-node"; + if (tp.nodeBuiltins === null || tp.fetchWasm === null) { + return "universal"; + } + } + return false; + }); + F(output, "workerWasmLoading", () => output.wasmLoading); + F(output, "devtoolNamespace", () => output.uniqueName); + if (output.library) { + F(output.library, "type", () => (output.module ? "module" : "var")); + } + F(output, "path", () => path.join(process.cwd(), "dist")); + F(output, "pathinfo", () => development); + D(output, "sourceMapFilename", "[file].map[query]"); + D( + output, + "hotUpdateChunkFilename", + `[id].[fullhash].hot-update.${output.module ? "mjs" : "js"}` + ); + D(output, "hotUpdateMainFilename", "[runtime].[fullhash].hot-update.json"); + D(output, "crossOriginLoading", false); + F(output, "scriptType", () => (output.module ? "module" : false)); + D( + output, + "publicPath", + (tp && (tp.document || tp.importScripts)) || output.scriptType === "module" + ? "auto" + : "" + ); + D(output, "workerPublicPath", ""); + D(output, "chunkLoadTimeout", 120000); + D(output, "hashFunction", futureDefaults ? "xxhash64" : "md4"); + D(output, "hashDigest", "hex"); + D(output, "hashDigestLength", futureDefaults ? 16 : 20); + D(output, "strictModuleExceptionHandling", false); + + const environment = /** @type {Environment} */ (output.environment); + /** + * @param {boolean | undefined} v value + * @returns {boolean} true, when v is truthy or undefined + */ + const optimistic = v => v || v === undefined; + /** + * @param {boolean | undefined} v value + * @param {boolean | undefined} c condition + * @returns {boolean | undefined} true, when v is truthy or undefined, or c is truthy + */ + const conditionallyOptimistic = (v, c) => (v === undefined && c) || v; + + F( + environment, + "globalThis", + () => /** @type {boolean | undefined} */ (tp && tp.globalThis) + ); + F( + environment, + "bigIntLiteral", + () => /** @type {boolean | undefined} */ (tp && tp.bigIntLiteral) + ); + F( + environment, + "const", + () => tp && optimistic(/** @type {boolean | undefined} */ (tp.const)) + ); + F( + environment, + "arrowFunction", + () => + tp && optimistic(/** @type {boolean | undefined} */ (tp.arrowFunction)) + ); + F( + environment, + "forOf", + () => tp && optimistic(/** @type {boolean | undefined} */ (tp.forOf)) + ); + F( + environment, + "destructuring", + () => + tp && optimistic(/** @type {boolean | undefined} */ (tp.destructuring)) + ); + F( + environment, + "optionalChaining", + () => + tp && optimistic(/** @type {boolean | undefined} */ (tp.optionalChaining)) + ); + F( + environment, + "templateLiteral", + () => + tp && optimistic(/** @type {boolean | undefined} */ (tp.templateLiteral)) + ); + F(environment, "dynamicImport", () => + conditionallyOptimistic( + /** @type {boolean | undefined} */ (tp && tp.dynamicImport), + output.module + ) + ); + F(environment, "dynamicImportInWorker", () => + conditionallyOptimistic( + /** @type {boolean | undefined} */ (tp && tp.dynamicImportInWorker), + output.module + ) + ); + F(environment, "module", () => + conditionallyOptimistic( + /** @type {boolean | undefined} */ (tp && tp.module), + output.module + ) + ); + + const { trustedTypes } = output; + if (trustedTypes) { + F( + trustedTypes, + "policyName", + () => + /** @type {NonNullable<Output["uniqueName"]>} */ + (output.uniqueName).replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack" + ); + D(trustedTypes, "onPolicyCreationFailure", "stop"); + } + + /** + * @param {function(EntryDescription): void} fn iterator + * @returns {void} + */ + const forEachEntry = fn => { + for (const name of Object.keys(entry)) { + fn(/** @type {{[k: string] : EntryDescription}} */ (entry)[name]); + } + }; + A(output, "enabledLibraryTypes", () => { + /** @type {LibraryType[]} */ + const enabledLibraryTypes = []; + if (output.library) { + enabledLibraryTypes.push(output.library.type); + } + forEachEntry(desc => { + if (desc.library) { + enabledLibraryTypes.push(desc.library.type); + } + }); + return enabledLibraryTypes; + }); + + A(output, "enabledChunkLoadingTypes", () => { + const enabledChunkLoadingTypes = new Set(); + if (output.chunkLoading) { + enabledChunkLoadingTypes.add(output.chunkLoading); + } + if (output.workerChunkLoading) { + enabledChunkLoadingTypes.add(output.workerChunkLoading); + } + forEachEntry(desc => { + if (desc.chunkLoading) { + enabledChunkLoadingTypes.add(desc.chunkLoading); + } + }); + return Array.from(enabledChunkLoadingTypes); + }); + + A(output, "enabledWasmLoadingTypes", () => { + const enabledWasmLoadingTypes = new Set(); + if (output.wasmLoading) { + enabledWasmLoadingTypes.add(output.wasmLoading); + } + if (output.workerWasmLoading) { + enabledWasmLoadingTypes.add(output.workerWasmLoading); + } + forEachEntry(desc => { + if (desc.wasmLoading) { + enabledWasmLoadingTypes.add(desc.wasmLoading); + } + }); + return Array.from(enabledWasmLoadingTypes); + }); +}; + +/** + * @param {ExternalsPresets} externalsPresets options + * @param {Object} options options + * @param {TargetProperties | false} options.targetProperties target properties + * @param {boolean} options.buildHttp buildHttp experiment enabled + * @returns {void} + */ +const applyExternalsPresetsDefaults = ( + externalsPresets, + { targetProperties, buildHttp } +) => { + D( + externalsPresets, + "web", + /** @type {boolean | undefined} */ + (!buildHttp && targetProperties && targetProperties.web) + ); + D( + externalsPresets, + "node", + /** @type {boolean | undefined} */ + (targetProperties && targetProperties.node) + ); + D( + externalsPresets, + "nwjs", + /** @type {boolean | undefined} */ + (targetProperties && targetProperties.nwjs) + ); + D( + externalsPresets, + "electron", + /** @type {boolean | undefined} */ + (targetProperties && targetProperties.electron) + ); + D( + externalsPresets, + "electronMain", + /** @type {boolean | undefined} */ + ( + targetProperties && + targetProperties.electron && + targetProperties.electronMain + ) + ); + D( + externalsPresets, + "electronPreload", + /** @type {boolean | undefined} */ + ( + targetProperties && + targetProperties.electron && + targetProperties.electronPreload + ) + ); + D( + externalsPresets, + "electronRenderer", + /** @type {boolean | undefined} */ + ( + targetProperties && + targetProperties.electron && + targetProperties.electronRenderer + ) + ); +}; + +/** + * @param {Loader} loader options + * @param {Object} options options + * @param {TargetProperties | false} options.targetProperties target properties + * @param {Environment} options.environment environment + * @returns {void} + */ +const applyLoaderDefaults = (loader, { targetProperties, environment }) => { + F(loader, "target", () => { + if (targetProperties) { + if (targetProperties.electron) { + if (targetProperties.electronMain) return "electron-main"; + if (targetProperties.electronPreload) return "electron-preload"; + if (targetProperties.electronRenderer) return "electron-renderer"; + return "electron"; + } + if (targetProperties.nwjs) return "nwjs"; + if (targetProperties.node) return "node"; + if (targetProperties.web) return "web"; + } + }); + D(loader, "environment", environment); +}; + +/** + * @param {WebpackNode} node options + * @param {Object} options options + * @param {TargetProperties | false} options.targetProperties target properties + * @param {boolean} options.futureDefaults is future defaults enabled + * @returns {void} + */ +const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => { + if (node === false) return; + + F(node, "global", () => { + if (targetProperties && targetProperties.global) return false; + // TODO webpack 6 should always default to false + return futureDefaults ? "warn" : true; + }); + F(node, "__filename", () => { + if (targetProperties && targetProperties.node) return "eval-only"; + // TODO webpack 6 should always default to false + return futureDefaults ? "warn-mock" : "mock"; + }); + F(node, "__dirname", () => { + if (targetProperties && targetProperties.node) return "eval-only"; + // TODO webpack 6 should always default to false + return futureDefaults ? "warn-mock" : "mock"; + }); +}; + +/** + * @param {Performance} performance options + * @param {Object} options options + * @param {boolean} options.production is production + * @returns {void} + */ +const applyPerformanceDefaults = (performance, { production }) => { + if (performance === false) return; + D(performance, "maxAssetSize", 250000); + D(performance, "maxEntrypointSize", 250000); + F(performance, "hints", () => (production ? "warning" : false)); +}; + +/** + * @param {Optimization} optimization options + * @param {Object} options options + * @param {boolean} options.production is production + * @param {boolean} options.development is development + * @param {CssExperimentOptions|false} options.css is css enabled + * @param {boolean} options.records using records + * @returns {void} + */ +const applyOptimizationDefaults = ( + optimization, + { production, development, css, records } +) => { + D(optimization, "removeAvailableModules", false); + D(optimization, "removeEmptyChunks", true); + D(optimization, "mergeDuplicateChunks", true); + D(optimization, "flagIncludedChunks", production); + F(optimization, "moduleIds", () => { + if (production) return "deterministic"; + if (development) return "named"; + return "natural"; + }); + F(optimization, "chunkIds", () => { + if (production) return "deterministic"; + if (development) return "named"; + return "natural"; + }); + F(optimization, "sideEffects", () => (production ? true : "flag")); + D(optimization, "providedExports", true); + D(optimization, "usedExports", production); + D(optimization, "innerGraph", production); + D(optimization, "mangleExports", production); + D(optimization, "concatenateModules", production); + D(optimization, "runtimeChunk", false); + D(optimization, "emitOnErrors", !production); + D(optimization, "checkWasmTypes", production); + D(optimization, "mangleWasmImports", false); + D(optimization, "portableRecords", records); + D(optimization, "realContentHash", production); + D(optimization, "minimize", production); + A(optimization, "minimizer", () => [ + { + apply: compiler => { + // Lazy load the Terser plugin + const TerserPlugin = require("terser-webpack-plugin"); + new TerserPlugin({ + terserOptions: { + compress: { + passes: 2 + } + } + }).apply(compiler); + } + } + ]); + F(optimization, "nodeEnv", () => { + if (production) return "production"; + if (development) return "development"; + return false; + }); + const { splitChunks } = optimization; + if (splitChunks) { + A(splitChunks, "defaultSizeTypes", () => + css ? ["javascript", "css", "unknown"] : ["javascript", "unknown"] + ); + D(splitChunks, "hidePathInfo", production); + D(splitChunks, "chunks", "async"); + D(splitChunks, "usedExports", optimization.usedExports === true); + D(splitChunks, "minChunks", 1); + F(splitChunks, "minSize", () => (production ? 20000 : 10000)); + F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined)); + F(splitChunks, "enforceSizeThreshold", () => (production ? 50000 : 30000)); + F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity)); + F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity)); + D(splitChunks, "automaticNameDelimiter", "-"); + const cacheGroups = + /** @type {NonNullable<OptimizationSplitChunksOptions["cacheGroups"]>} */ + (splitChunks.cacheGroups); + F(cacheGroups, "default", () => ({ + idHint: "", + reuseExistingChunk: true, + minChunks: 2, + priority: -20 + })); + F(cacheGroups, "defaultVendors", () => ({ + idHint: "vendors", + reuseExistingChunk: true, + test: NODE_MODULES_REGEXP, + priority: -10 + })); + } +}; + +/** + * @param {Object} options options + * @param {boolean} options.cache is cache enable + * @param {string} options.context build context + * @param {TargetProperties | false} options.targetProperties target properties + * @param {Mode} options.mode mode + * @param {CssExperimentOptions|false} options.css is css enabled + * @returns {ResolveOptions} resolve options + */ +const getResolveDefaults = ({ + cache, + context, + targetProperties, + mode, + css +}) => { + /** @type {string[]} */ + const conditions = ["webpack"]; + + conditions.push(mode === "development" ? "development" : "production"); + + if (targetProperties) { + if (targetProperties.webworker) conditions.push("worker"); + if (targetProperties.node) conditions.push("node"); + if (targetProperties.web) conditions.push("browser"); + if (targetProperties.electron) conditions.push("electron"); + if (targetProperties.nwjs) conditions.push("nwjs"); + } + + const jsExtensions = [".js", ".json", ".wasm"]; + + const tp = targetProperties; + const browserField = + tp && tp.web && (!tp.node || (tp.electron && tp.electronRenderer)); + + /** @type {function(): ResolveOptions} */ + const cjsDeps = () => ({ + aliasFields: browserField ? ["browser"] : [], + mainFields: browserField ? ["browser", "module", "..."] : ["module", "..."], + conditionNames: ["require", "module", "..."], + extensions: [...jsExtensions] + }); + /** @type {function(): ResolveOptions} */ + const esmDeps = () => ({ + aliasFields: browserField ? ["browser"] : [], + mainFields: browserField ? ["browser", "module", "..."] : ["module", "..."], + conditionNames: ["import", "module", "..."], + extensions: [...jsExtensions] + }); + + /** @type {ResolveOptions} */ + const resolveOptions = { + cache, + modules: ["node_modules"], + conditionNames: conditions, + mainFiles: ["index"], + extensions: [], + aliasFields: [], + exportsFields: ["exports"], + roots: [context], + mainFields: ["main"], + byDependency: { + wasm: esmDeps(), + esm: esmDeps(), + loaderImport: esmDeps(), + url: { + preferRelative: true + }, + worker: { + ...esmDeps(), + preferRelative: true + }, + commonjs: cjsDeps(), + amd: cjsDeps(), + // for backward-compat: loadModule + loader: cjsDeps(), + // for backward-compat: Custom Dependency + unknown: cjsDeps(), + // for backward-compat: getResolve without dependencyType + undefined: cjsDeps() + } + }; + + if (css) { + const styleConditions = []; + + styleConditions.push("webpack"); + styleConditions.push(mode === "development" ? "development" : "production"); + styleConditions.push("style"); + + resolveOptions.byDependency["css-import"] = { + // We avoid using any main files because we have to be consistent with CSS `@import` + // and CSS `@import` does not handle `main` files in directories, + // you should always specify the full URL for styles + mainFiles: [], + mainFields: ["style", "..."], + conditionNames: styleConditions, + extensions: [".css"] + }; + } + + return resolveOptions; +}; + +/** + * @param {Object} options options + * @param {boolean} options.cache is cache enable + * @returns {ResolveOptions} resolve options + */ +const getResolveLoaderDefaults = ({ cache }) => { + /** @type {ResolveOptions} */ + const resolveOptions = { + cache, + conditionNames: ["loader", "require", "node"], + exportsFields: ["exports"], + mainFields: ["loader", "main"], + extensions: [".js"], + mainFiles: ["index"] + }; + + return resolveOptions; +}; + +/** + * @param {InfrastructureLogging} infrastructureLogging options + * @returns {void} + */ +const applyInfrastructureLoggingDefaults = infrastructureLogging => { + F(infrastructureLogging, "stream", () => process.stderr); + const tty = + /** @type {any} */ (infrastructureLogging.stream).isTTY && + process.env.TERM !== "dumb"; + D(infrastructureLogging, "level", "info"); + D(infrastructureLogging, "debug", false); + D(infrastructureLogging, "colors", tty); + D(infrastructureLogging, "appendOnly", !tty); +}; + +exports.applyWebpackOptionsBaseDefaults = applyWebpackOptionsBaseDefaults; +exports.applyWebpackOptionsDefaults = applyWebpackOptionsDefaults; diff --git a/node_modules/webpack/lib/config/normalization.js b/node_modules/webpack/lib/config/normalization.js new file mode 100644 index 00000000..0c5acecc --- /dev/null +++ b/node_modules/webpack/lib/config/normalization.js @@ -0,0 +1,567 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const util = require("util"); + +/** @typedef {import("../../declarations/WebpackOptions").CacheOptionsNormalized} CacheOptions */ +/** @typedef {import("../../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescriptionNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").EntryStatic} EntryStatic */ +/** @typedef {import("../../declarations/WebpackOptions").EntryStaticNormalized} EntryStaticNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").Externals} Externals */ +/** @typedef {import("../../declarations/WebpackOptions").LibraryName} LibraryName */ +/** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */ +/** @typedef {import("../../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptionsNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunk} OptimizationRuntimeChunk */ +/** @typedef {import("../../declarations/WebpackOptions").OptimizationRuntimeChunkNormalized} OptimizationRuntimeChunkNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputNormalized */ +/** @typedef {import("../../declarations/WebpackOptions").Plugins} Plugins */ +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptions} WebpackOptions */ +/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */ +/** @typedef {import("../Entrypoint")} Entrypoint */ + +const handledDeprecatedNoEmitOnErrors = util.deprecate( + /** + * @param {boolean} noEmitOnErrors no emit on errors + * @param {boolean | undefined} emitOnErrors emit on errors + * @returns {boolean} emit on errors + */ + (noEmitOnErrors, emitOnErrors) => { + if (emitOnErrors !== undefined && !noEmitOnErrors === !emitOnErrors) { + throw new Error( + "Conflicting use of 'optimization.noEmitOnErrors' and 'optimization.emitOnErrors'. Remove deprecated 'optimization.noEmitOnErrors' from config." + ); + } + return !noEmitOnErrors; + }, + "optimization.noEmitOnErrors is deprecated in favor of optimization.emitOnErrors", + "DEP_WEBPACK_CONFIGURATION_OPTIMIZATION_NO_EMIT_ON_ERRORS" +); + +/** + * @template T + * @template R + * @param {T|undefined} value value or not + * @param {function(T): R} fn nested handler + * @returns {R} result value + */ +const nestedConfig = (value, fn) => + value === undefined ? fn(/** @type {T} */ ({})) : fn(value); + +/** + * @template T + * @param {T|undefined} value value or not + * @returns {T} result value + */ +const cloneObject = value => { + return /** @type {T} */ ({ ...value }); +}; + +/** + * @template T + * @template R + * @param {T|undefined} value value or not + * @param {function(T): R} fn nested handler + * @returns {R|undefined} result value + */ +const optionalNestedConfig = (value, fn) => + value === undefined ? undefined : fn(value); + +/** + * @template T + * @template R + * @param {T[]|undefined} value array or not + * @param {function(T[]): R[]} fn nested handler + * @returns {R[]|undefined} cloned value + */ +const nestedArray = (value, fn) => (Array.isArray(value) ? fn(value) : fn([])); + +/** + * @template T + * @template R + * @param {T[]|undefined} value array or not + * @param {function(T[]): R[]} fn nested handler + * @returns {R[]|undefined} cloned value + */ +const optionalNestedArray = (value, fn) => + Array.isArray(value) ? fn(value) : undefined; + +/** + * @template T + * @template R + * @param {Record<string, T>|undefined} value value or not + * @param {function(T): R} fn nested handler + * @param {Record<string, function(T): R>=} customKeys custom nested handler for some keys + * @returns {Record<string, R>} result value + */ +const keyedNestedConfig = (value, fn, customKeys) => { + const result = + value === undefined + ? {} + : Object.keys(value).reduce( + (obj, key) => ( + (obj[key] = ( + customKeys && key in customKeys ? customKeys[key] : fn + )(value[key])), + obj + ), + /** @type {Record<string, R>} */ ({}) + ); + if (customKeys) { + for (const key of Object.keys(customKeys)) { + if (!(key in result)) { + result[key] = customKeys[key](/** @type {T} */ ({})); + } + } + } + return result; +}; + +/** + * @param {WebpackOptions} config input config + * @returns {WebpackOptionsNormalized} normalized options + */ +const getNormalizedWebpackOptions = config => { + return { + amd: config.amd, + bail: config.bail, + cache: + /** @type {NonNullable<CacheOptions>} */ + ( + optionalNestedConfig(config.cache, cache => { + if (cache === false) return false; + if (cache === true) { + return { + type: "memory", + maxGenerations: undefined + }; + } + switch (cache.type) { + case "filesystem": + return { + type: "filesystem", + allowCollectingMemory: cache.allowCollectingMemory, + maxMemoryGenerations: cache.maxMemoryGenerations, + maxAge: cache.maxAge, + profile: cache.profile, + buildDependencies: cloneObject(cache.buildDependencies), + cacheDirectory: cache.cacheDirectory, + cacheLocation: cache.cacheLocation, + hashAlgorithm: cache.hashAlgorithm, + compression: cache.compression, + idleTimeout: cache.idleTimeout, + idleTimeoutForInitialStore: cache.idleTimeoutForInitialStore, + idleTimeoutAfterLargeChanges: + cache.idleTimeoutAfterLargeChanges, + name: cache.name, + store: cache.store, + version: cache.version, + readonly: cache.readonly + }; + case undefined: + case "memory": + return { + type: "memory", + maxGenerations: cache.maxGenerations + }; + default: + // @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339) + throw new Error(`Not implemented cache.type ${cache.type}`); + } + }) + ), + context: config.context, + dependencies: config.dependencies, + devServer: optionalNestedConfig(config.devServer, devServer => ({ + ...devServer + })), + devtool: config.devtool, + entry: + config.entry === undefined + ? { main: {} } + : typeof config.entry === "function" + ? ( + fn => () => + Promise.resolve().then(fn).then(getNormalizedEntryStatic) + )(config.entry) + : getNormalizedEntryStatic(config.entry), + experiments: nestedConfig(config.experiments, experiments => ({ + ...experiments, + buildHttp: optionalNestedConfig(experiments.buildHttp, options => + Array.isArray(options) ? { allowedUris: options } : options + ), + lazyCompilation: optionalNestedConfig( + experiments.lazyCompilation, + options => (options === true ? {} : options) + ), + css: optionalNestedConfig(experiments.css, options => + options === true ? {} : options + ) + })), + externals: /** @type {NonNullable<Externals>} */ (config.externals), + externalsPresets: cloneObject(config.externalsPresets), + externalsType: config.externalsType, + ignoreWarnings: config.ignoreWarnings + ? config.ignoreWarnings.map(ignore => { + if (typeof ignore === "function") return ignore; + const i = ignore instanceof RegExp ? { message: ignore } : ignore; + return (warning, { requestShortener }) => { + if (!i.message && !i.module && !i.file) return false; + if (i.message && !i.message.test(warning.message)) { + return false; + } + if ( + i.module && + (!warning.module || + !i.module.test( + warning.module.readableIdentifier(requestShortener) + )) + ) { + return false; + } + if (i.file && (!warning.file || !i.file.test(warning.file))) { + return false; + } + return true; + }; + }) + : undefined, + infrastructureLogging: cloneObject(config.infrastructureLogging), + loader: cloneObject(config.loader), + mode: config.mode, + module: + /** @type {ModuleOptionsNormalized} */ + ( + nestedConfig(config.module, module => ({ + noParse: module.noParse, + unsafeCache: module.unsafeCache, + parser: keyedNestedConfig(module.parser, cloneObject, { + javascript: parserOptions => ({ + unknownContextRequest: module.unknownContextRequest, + unknownContextRegExp: module.unknownContextRegExp, + unknownContextRecursive: module.unknownContextRecursive, + unknownContextCritical: module.unknownContextCritical, + exprContextRequest: module.exprContextRequest, + exprContextRegExp: module.exprContextRegExp, + exprContextRecursive: module.exprContextRecursive, + exprContextCritical: module.exprContextCritical, + wrappedContextRegExp: module.wrappedContextRegExp, + wrappedContextRecursive: module.wrappedContextRecursive, + wrappedContextCritical: module.wrappedContextCritical, + // TODO webpack 6 remove + strictExportPresence: module.strictExportPresence, + strictThisContextOnImports: module.strictThisContextOnImports, + ...parserOptions + }) + }), + generator: cloneObject(module.generator), + defaultRules: optionalNestedArray(module.defaultRules, r => [...r]), + rules: nestedArray(module.rules, r => [...r]) + })) + ), + name: config.name, + node: nestedConfig( + config.node, + node => + node && { + ...node + } + ), + optimization: nestedConfig(config.optimization, optimization => { + return { + ...optimization, + runtimeChunk: getNormalizedOptimizationRuntimeChunk( + optimization.runtimeChunk + ), + splitChunks: nestedConfig( + optimization.splitChunks, + splitChunks => + splitChunks && { + ...splitChunks, + defaultSizeTypes: splitChunks.defaultSizeTypes + ? [...splitChunks.defaultSizeTypes] + : ["..."], + cacheGroups: cloneObject(splitChunks.cacheGroups) + } + ), + emitOnErrors: + optimization.noEmitOnErrors !== undefined + ? handledDeprecatedNoEmitOnErrors( + optimization.noEmitOnErrors, + optimization.emitOnErrors + ) + : optimization.emitOnErrors + }; + }), + output: nestedConfig(config.output, output => { + const { library } = output; + const libraryAsName = /** @type {LibraryName} */ (library); + const libraryBase = + typeof library === "object" && + library && + !Array.isArray(library) && + "type" in library + ? library + : libraryAsName || output.libraryTarget + ? /** @type {LibraryOptions} */ ({ + name: libraryAsName + }) + : undefined; + /** @type {OutputNormalized} */ + const result = { + assetModuleFilename: output.assetModuleFilename, + asyncChunks: output.asyncChunks, + charset: output.charset, + chunkFilename: output.chunkFilename, + chunkFormat: output.chunkFormat, + chunkLoading: output.chunkLoading, + chunkLoadingGlobal: output.chunkLoadingGlobal, + chunkLoadTimeout: output.chunkLoadTimeout, + cssFilename: output.cssFilename, + cssChunkFilename: output.cssChunkFilename, + clean: output.clean, + compareBeforeEmit: output.compareBeforeEmit, + crossOriginLoading: output.crossOriginLoading, + devtoolFallbackModuleFilenameTemplate: + output.devtoolFallbackModuleFilenameTemplate, + devtoolModuleFilenameTemplate: output.devtoolModuleFilenameTemplate, + devtoolNamespace: output.devtoolNamespace, + environment: cloneObject(output.environment), + enabledChunkLoadingTypes: output.enabledChunkLoadingTypes + ? [...output.enabledChunkLoadingTypes] + : ["..."], + enabledLibraryTypes: output.enabledLibraryTypes + ? [...output.enabledLibraryTypes] + : ["..."], + enabledWasmLoadingTypes: output.enabledWasmLoadingTypes + ? [...output.enabledWasmLoadingTypes] + : ["..."], + filename: output.filename, + globalObject: output.globalObject, + hashDigest: output.hashDigest, + hashDigestLength: output.hashDigestLength, + hashFunction: output.hashFunction, + hashSalt: output.hashSalt, + hotUpdateChunkFilename: output.hotUpdateChunkFilename, + hotUpdateGlobal: output.hotUpdateGlobal, + hotUpdateMainFilename: output.hotUpdateMainFilename, + ignoreBrowserWarnings: output.ignoreBrowserWarnings, + iife: output.iife, + importFunctionName: output.importFunctionName, + importMetaName: output.importMetaName, + scriptType: output.scriptType, + library: libraryBase && { + type: + output.libraryTarget !== undefined + ? output.libraryTarget + : libraryBase.type, + auxiliaryComment: + output.auxiliaryComment !== undefined + ? output.auxiliaryComment + : libraryBase.auxiliaryComment, + amdContainer: + output.amdContainer !== undefined + ? output.amdContainer + : libraryBase.amdContainer, + export: + output.libraryExport !== undefined + ? output.libraryExport + : libraryBase.export, + name: libraryBase.name, + umdNamedDefine: + output.umdNamedDefine !== undefined + ? output.umdNamedDefine + : libraryBase.umdNamedDefine + }, + module: output.module, + path: output.path, + pathinfo: output.pathinfo, + publicPath: output.publicPath, + sourceMapFilename: output.sourceMapFilename, + sourcePrefix: output.sourcePrefix, + strictModuleExceptionHandling: output.strictModuleExceptionHandling, + trustedTypes: optionalNestedConfig( + output.trustedTypes, + trustedTypes => { + if (trustedTypes === true) return {}; + if (typeof trustedTypes === "string") + return { policyName: trustedTypes }; + return { ...trustedTypes }; + } + ), + uniqueName: output.uniqueName, + wasmLoading: output.wasmLoading, + webassemblyModuleFilename: output.webassemblyModuleFilename, + workerPublicPath: output.workerPublicPath, + workerChunkLoading: output.workerChunkLoading, + workerWasmLoading: output.workerWasmLoading + }; + return result; + }), + parallelism: config.parallelism, + performance: optionalNestedConfig(config.performance, performance => { + if (performance === false) return false; + return { + ...performance + }; + }), + plugins: /** @type {Plugins} */ (nestedArray(config.plugins, p => [...p])), + profile: config.profile, + recordsInputPath: + config.recordsInputPath !== undefined + ? config.recordsInputPath + : config.recordsPath, + recordsOutputPath: + config.recordsOutputPath !== undefined + ? config.recordsOutputPath + : config.recordsPath, + resolve: nestedConfig(config.resolve, resolve => ({ + ...resolve, + byDependency: keyedNestedConfig(resolve.byDependency, cloneObject) + })), + resolveLoader: cloneObject(config.resolveLoader), + snapshot: nestedConfig(config.snapshot, snapshot => ({ + resolveBuildDependencies: optionalNestedConfig( + snapshot.resolveBuildDependencies, + resolveBuildDependencies => ({ + timestamp: resolveBuildDependencies.timestamp, + hash: resolveBuildDependencies.hash + }) + ), + buildDependencies: optionalNestedConfig( + snapshot.buildDependencies, + buildDependencies => ({ + timestamp: buildDependencies.timestamp, + hash: buildDependencies.hash + }) + ), + resolve: optionalNestedConfig(snapshot.resolve, resolve => ({ + timestamp: resolve.timestamp, + hash: resolve.hash + })), + module: optionalNestedConfig(snapshot.module, module => ({ + timestamp: module.timestamp, + hash: module.hash + })), + immutablePaths: optionalNestedArray(snapshot.immutablePaths, p => [...p]), + managedPaths: optionalNestedArray(snapshot.managedPaths, p => [...p]) + })), + stats: nestedConfig(config.stats, stats => { + if (stats === false) { + return { + preset: "none" + }; + } + if (stats === true) { + return { + preset: "normal" + }; + } + if (typeof stats === "string") { + return { + preset: stats + }; + } + return { + ...stats + }; + }), + target: config.target, + watch: config.watch, + watchOptions: cloneObject(config.watchOptions) + }; +}; + +/** + * @param {EntryStatic} entry static entry options + * @returns {EntryStaticNormalized} normalized static entry options + */ +const getNormalizedEntryStatic = entry => { + if (typeof entry === "string") { + return { + main: { + import: [entry] + } + }; + } + if (Array.isArray(entry)) { + return { + main: { + import: entry + } + }; + } + /** @type {EntryStaticNormalized} */ + const result = {}; + for (const key of Object.keys(entry)) { + const value = entry[key]; + if (typeof value === "string") { + result[key] = { + import: [value] + }; + } else if (Array.isArray(value)) { + result[key] = { + import: value + }; + } else { + result[key] = { + import: + /** @type {EntryDescriptionNormalized["import"]} */ + ( + value.import && + (Array.isArray(value.import) ? value.import : [value.import]) + ), + filename: value.filename, + layer: value.layer, + runtime: value.runtime, + baseUri: value.baseUri, + publicPath: value.publicPath, + chunkLoading: value.chunkLoading, + asyncChunks: value.asyncChunks, + wasmLoading: value.wasmLoading, + dependOn: + /** @type {EntryDescriptionNormalized["dependOn"]} */ + ( + value.dependOn && + (Array.isArray(value.dependOn) + ? value.dependOn + : [value.dependOn]) + ), + library: value.library + }; + } + } + return result; +}; + +/** + * @param {OptimizationRuntimeChunk=} runtimeChunk runtimeChunk option + * @returns {OptimizationRuntimeChunkNormalized=} normalized runtimeChunk option + */ +const getNormalizedOptimizationRuntimeChunk = runtimeChunk => { + if (runtimeChunk === undefined) return undefined; + if (runtimeChunk === false) return false; + if (runtimeChunk === "single") { + return { + name: () => "runtime" + }; + } + if (runtimeChunk === true || runtimeChunk === "multiple") { + return { + /** + * @param {Entrypoint} entrypoint entrypoint + * @returns {string} runtime chunk name + */ + name: entrypoint => `runtime~${entrypoint.name}` + }; + } + const { name } = runtimeChunk; + return { + name: typeof name === "function" ? name : () => name + }; +}; + +exports.getNormalizedWebpackOptions = getNormalizedWebpackOptions; diff --git a/node_modules/webpack/lib/config/target.js b/node_modules/webpack/lib/config/target.js new file mode 100644 index 00000000..da026c32 --- /dev/null +++ b/node_modules/webpack/lib/config/target.js @@ -0,0 +1,375 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const memoize = require("../util/memoize"); + +const getBrowserslistTargetHandler = memoize(() => + require("./browserslistTargetHandler") +); + +/** + * @param {string} context the context directory + * @returns {string} default target + */ +const getDefaultTarget = context => { + const browsers = getBrowserslistTargetHandler().load(null, context); + return browsers ? "browserslist" : "web"; +}; + +/** + * @typedef {Object} PlatformTargetProperties + * @property {boolean | null} web web platform, importing of http(s) and std: is available + * @property {boolean | null} browser browser platform, running in a normal web browser + * @property {boolean | null} webworker (Web)Worker platform, running in a web/shared/service worker + * @property {boolean | null} node node platform, require of node built-in modules is available + * @property {boolean | null} nwjs nwjs platform, require of legacy nw.gui is available + * @property {boolean | null} electron electron platform, require of some electron built-in modules is available + */ + +/** + * @typedef {Object} ElectronContextTargetProperties + * @property {boolean | null} electronMain in main context + * @property {boolean | null} electronPreload in preload context + * @property {boolean | null} electronRenderer in renderer context with node integration + */ + +/** + * @typedef {Object} ApiTargetProperties + * @property {boolean | null} require has require function available + * @property {boolean | null} nodeBuiltins has node.js built-in modules available + * @property {boolean | null} document has document available (allows script tags) + * @property {boolean | null} importScripts has importScripts available + * @property {boolean | null} importScriptsInWorker has importScripts available when creating a worker + * @property {boolean | null} fetchWasm has fetch function available for WebAssembly + * @property {boolean | null} global has global variable available + */ + +/** + * @typedef {Object} EcmaTargetProperties + * @property {boolean | null} globalThis has globalThis variable available + * @property {boolean | null} bigIntLiteral big int literal syntax is available + * @property {boolean | null} const const and let variable declarations are available + * @property {boolean | null} arrowFunction arrow functions are available + * @property {boolean | null} forOf for of iteration is available + * @property {boolean | null} destructuring destructuring is available + * @property {boolean | null} dynamicImport async import() is available + * @property {boolean | null} dynamicImportInWorker async import() is available when creating a worker + * @property {boolean | null} module ESM syntax is available (when in module) + * @property {boolean | null} optionalChaining optional chaining is available + * @property {boolean | null} templateLiteral template literal is available + */ + +///** @typedef {PlatformTargetProperties | ApiTargetProperties | EcmaTargetProperties | PlatformTargetProperties & ApiTargetProperties | PlatformTargetProperties & EcmaTargetProperties | ApiTargetProperties & EcmaTargetProperties} TargetProperties */ + +/** + * @template T + * @typedef {{ [P in keyof T]?: never }} Never<T> + */ + +/** + * @template A + * @template B + * @typedef {(A & Never<B>) | (Never<A> & B) | (A & B)} Mix<A, B> + */ + +/** @typedef {Mix<Mix<PlatformTargetProperties, ElectronContextTargetProperties>, Mix<ApiTargetProperties, EcmaTargetProperties>>} TargetProperties */ + +/** + * @param {string} major major version + * @param {string | undefined} minor minor version + * @returns {(vMajor: number, vMinor?: number) => boolean | undefined} check if version is greater or equal + */ +const versionDependent = (major, minor) => { + if (!major) { + return () => /** @type {undefined} */ (undefined); + } + /** @type {number} */ + const nMajor = +major; + /** @type {number} */ + const nMinor = minor ? +minor : 0; + return (vMajor, vMinor = 0) => { + return nMajor > vMajor || (nMajor === vMajor && nMinor >= vMinor); + }; +}; + +/** @type {[string, string, RegExp, (...args: string[]) => Partial<TargetProperties>][]} */ +const TARGETS = [ + [ + "browserslist / browserslist:env / browserslist:query / browserslist:path-to-config / browserslist:path-to-config:env", + "Resolve features from browserslist. Will resolve browserslist config automatically. Only browser or node queries are supported (electron is not supported). Examples: 'browserslist:modern' to use 'modern' environment from browserslist config", + /^browserslist(?::(.+))?$/, + (rest, context) => { + const browserslistTargetHandler = getBrowserslistTargetHandler(); + const browsers = browserslistTargetHandler.load( + rest ? rest.trim() : null, + context + ); + if (!browsers) { + throw new Error(`No browserslist config found to handle the 'browserslist' target. +See https://github.com/browserslist/browserslist#queries for possible ways to provide a config. +The recommended way is to add a 'browserslist' key to your package.json and list supported browsers (resp. node.js versions). +You can also more options via the 'target' option: 'browserslist' / 'browserslist:env' / 'browserslist:query' / 'browserslist:path-to-config' / 'browserslist:path-to-config:env'`); + } + + return browserslistTargetHandler.resolve(browsers); + } + ], + [ + "web", + "Web browser.", + /^web$/, + () => { + return { + web: true, + browser: true, + webworker: null, + node: false, + electron: false, + nwjs: false, + + document: true, + importScriptsInWorker: true, + fetchWasm: true, + nodeBuiltins: false, + importScripts: false, + require: false, + global: false + }; + } + ], + [ + "webworker", + "Web Worker, SharedWorker or Service Worker.", + /^webworker$/, + () => { + return { + web: true, + browser: true, + webworker: true, + node: false, + electron: false, + nwjs: false, + + importScripts: true, + importScriptsInWorker: true, + fetchWasm: true, + nodeBuiltins: false, + require: false, + document: false, + global: false + }; + } + ], + [ + "[async-]node[X[.Y]]", + "Node.js in version X.Y. The 'async-' prefix will load chunks asynchronously via 'fs' and 'vm' instead of 'require()'. Examples: node14.5, async-node10.", + /^(async-)?node(\d+(?:\.(\d+))?)?$/, + (asyncFlag, major, minor) => { + const v = versionDependent(major, minor); + // see https://node.green/ + return { + node: true, + electron: false, + nwjs: false, + web: false, + webworker: false, + browser: false, + + require: !asyncFlag, + nodeBuiltins: true, + global: true, + document: false, + fetchWasm: false, + importScripts: false, + importScriptsInWorker: false, + + globalThis: v(12), + const: v(6), + templateLiteral: v(4), + optionalChaining: v(14), + arrowFunction: v(6), + forOf: v(5), + destructuring: v(6), + bigIntLiteral: v(10, 4), + dynamicImport: v(12, 17), + dynamicImportInWorker: major ? false : undefined, + module: v(12, 17) + }; + } + ], + [ + "electron[X[.Y]]-main/preload/renderer", + "Electron in version X.Y. Script is running in main, preload resp. renderer context.", + /^electron(\d+(?:\.(\d+))?)?-(main|preload|renderer)$/, + (major, minor, context) => { + const v = versionDependent(major, minor); + // see https://node.green/ + https://github.com/electron/releases + return { + node: true, + electron: true, + web: context !== "main", + webworker: false, + browser: false, + nwjs: false, + + electronMain: context === "main", + electronPreload: context === "preload", + electronRenderer: context === "renderer", + + global: true, + nodeBuiltins: true, + require: true, + document: context === "renderer", + fetchWasm: context === "renderer", + importScripts: false, + importScriptsInWorker: true, + + globalThis: v(5), + const: v(1, 1), + templateLiteral: v(1, 1), + optionalChaining: v(8), + arrowFunction: v(1, 1), + forOf: v(0, 36), + destructuring: v(1, 1), + bigIntLiteral: v(4), + dynamicImport: v(11), + dynamicImportInWorker: major ? false : undefined, + module: v(11) + }; + } + ], + [ + "nwjs[X[.Y]] / node-webkit[X[.Y]]", + "NW.js in version X.Y.", + /^(?:nwjs|node-webkit)(\d+(?:\.(\d+))?)?$/, + (major, minor) => { + const v = versionDependent(major, minor); + // see https://node.green/ + https://github.com/nwjs/nw.js/blob/nw48/CHANGELOG.md + return { + node: true, + web: true, + nwjs: true, + webworker: null, + browser: false, + electron: false, + + global: true, + nodeBuiltins: true, + document: false, + importScriptsInWorker: false, + fetchWasm: false, + importScripts: false, + require: false, + + globalThis: v(0, 43), + const: v(0, 15), + templateLiteral: v(0, 13), + optionalChaining: v(0, 44), + arrowFunction: v(0, 15), + forOf: v(0, 13), + destructuring: v(0, 15), + bigIntLiteral: v(0, 32), + dynamicImport: v(0, 43), + dynamicImportInWorker: major ? false : undefined, + module: v(0, 43) + }; + } + ], + [ + "esX", + "EcmaScript in this version. Examples: es2020, es5.", + /^es(\d+)$/, + version => { + let v = +version; + if (v < 1000) v = v + 2009; + return { + const: v >= 2015, + templateLiteral: v >= 2015, + optionalChaining: v >= 2020, + arrowFunction: v >= 2015, + forOf: v >= 2015, + destructuring: v >= 2015, + module: v >= 2015, + globalThis: v >= 2020, + bigIntLiteral: v >= 2020, + dynamicImport: v >= 2020, + dynamicImportInWorker: v >= 2020 + }; + } + ] +]; + +/** + * @param {string} target the target + * @param {string} context the context directory + * @returns {TargetProperties} target properties + */ +const getTargetProperties = (target, context) => { + for (const [, , regExp, handler] of TARGETS) { + const match = regExp.exec(target); + if (match) { + const [, ...args] = match; + const result = handler(...args, context); + if (result) return /** @type {TargetProperties} */ (result); + } + } + throw new Error( + `Unknown target '${target}'. The following targets are supported:\n${TARGETS.map( + ([name, description]) => `* ${name}: ${description}` + ).join("\n")}` + ); +}; + +/** + * @param {TargetProperties[]} targetProperties array of target properties + * @returns {TargetProperties} merged target properties + */ +const mergeTargetProperties = targetProperties => { + /** @type {Set<keyof TargetProperties>} */ + const keys = new Set(); + for (const tp of targetProperties) { + for (const key of Object.keys(tp)) { + keys.add(/** @type {keyof TargetProperties} */ (key)); + } + } + /** @type {Object} */ + const result = {}; + for (const key of keys) { + let hasTrue = false; + let hasFalse = false; + for (const tp of targetProperties) { + const value = tp[key]; + switch (value) { + case true: + hasTrue = true; + break; + case false: + hasFalse = true; + break; + } + } + if (hasTrue || hasFalse) + /** @type {TargetProperties} */ + (result)[key] = hasFalse && hasTrue ? null : hasTrue ? true : false; + } + return /** @type {TargetProperties} */ (result); +}; + +/** + * @param {string[]} targets the targets + * @param {string} context the context directory + * @returns {TargetProperties} target properties + */ +const getTargetsProperties = (targets, context) => { + return mergeTargetProperties( + targets.map(t => getTargetProperties(t, context)) + ); +}; + +exports.getDefaultTarget = getDefaultTarget; +exports.getTargetProperties = getTargetProperties; +exports.getTargetsProperties = getTargetsProperties; |
