diff options
author | 2020-11-16 00:10:28 +0100 | |
---|---|---|
committer | 2020-11-16 00:10:28 +0100 | |
commit | e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d (patch) | |
tree | 55713f725f77b44ebfec86e4eec3ce33e71458ca /node_modules/webpack/lib | |
download | website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.gz website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.bz2 website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.zip |
api, login, auth
Diffstat (limited to 'node_modules/webpack/lib')
306 files changed, 44255 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/APIPlugin.js b/node_modules/webpack/lib/APIPlugin.js new file mode 100644 index 0000000..bc084f0 --- /dev/null +++ b/node_modules/webpack/lib/APIPlugin.js @@ -0,0 +1,84 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ConstDependency = require("./dependencies/ConstDependency"); +const ParserHelpers = require("./ParserHelpers"); + +const NullFactory = require("./NullFactory"); + +/* eslint-disable camelcase */ +const REPLACEMENTS = { + __webpack_require__: "__webpack_require__", + __webpack_public_path__: "__webpack_require__.p", + __webpack_modules__: "__webpack_require__.m", + __webpack_chunk_load__: "__webpack_require__.e", + __non_webpack_require__: "require", + __webpack_nonce__: "__webpack_require__.nc", + "require.onError": "__webpack_require__.oe" +}; +const NO_WEBPACK_REQUIRE = { + __non_webpack_require__: true +}; +const REPLACEMENT_TYPES = { + __webpack_public_path__: "string", + __webpack_require__: "function", + __webpack_modules__: "object", + __webpack_chunk_load__: "function", + __webpack_nonce__: "string" +}; +/* eslint-enable camelcase */ + +class APIPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "APIPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + const handler = parser => { + Object.keys(REPLACEMENTS).forEach(key => { + parser.hooks.expression + .for(key) + .tap( + "APIPlugin", + NO_WEBPACK_REQUIRE[key] + ? ParserHelpers.toConstantDependency( + parser, + REPLACEMENTS[key] + ) + : ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + REPLACEMENTS[key] + ) + ); + const type = REPLACEMENT_TYPES[key]; + if (type) { + parser.hooks.evaluateTypeof + .for(key) + .tap("APIPlugin", ParserHelpers.evaluateToString(type)); + } + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("APIPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("APIPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("APIPlugin", handler); + } + ); + } +} + +module.exports = APIPlugin; diff --git a/node_modules/webpack/lib/AbstractMethodError.js b/node_modules/webpack/lib/AbstractMethodError.js new file mode 100644 index 0000000..c9eb9cf --- /dev/null +++ b/node_modules/webpack/lib/AbstractMethodError.js @@ -0,0 +1,43 @@ +"use strict"; + +const WebpackError = require("./WebpackError"); +const CURRENT_METHOD_REGEXP = /at ([a-zA-Z0-9_.]*)/; + +/** + * @param {string=} method method name + * @returns {string} message + */ +function createMessage(method) { + return `Abstract method${method ? " " + method : ""}. Must be overridden.`; +} + +/** + * @constructor + */ +function Message() { + this.stack = undefined; + Error.captureStackTrace(this); + /** @type {RegExpMatchArray} */ + const match = this.stack.split("\n")[3].match(CURRENT_METHOD_REGEXP); + + this.message = match && match[1] ? createMessage(match[1]) : createMessage(); +} + +/** + * Error for abstract method + * @example + * class FooClass { + * abstractMethod() { + * throw new AbstractMethodError(); // error message: Abstract method FooClass.abstractMethod. Must be overriden. + * } + * } + * + */ +class AbstractMethodError extends WebpackError { + constructor() { + super(new Message().message); + this.name = "AbstractMethodError"; + } +} + +module.exports = AbstractMethodError; diff --git a/node_modules/webpack/lib/AmdMainTemplatePlugin.js b/node_modules/webpack/lib/AmdMainTemplatePlugin.js new file mode 100644 index 0000000..705f88d --- /dev/null +++ b/node_modules/webpack/lib/AmdMainTemplatePlugin.js @@ -0,0 +1,106 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + +"use strict"; + +const { ConcatSource } = require("webpack-sources"); +const Template = require("./Template"); + +/** @typedef {import("./Compilation")} Compilation */ + +/** + * @typedef {Object} AmdMainTemplatePluginOptions + * @param {string=} name the library name + * @property {boolean=} requireAsWrapper + */ + +class AmdMainTemplatePlugin { + /** + * @param {AmdMainTemplatePluginOptions} options the plugin options + */ + constructor(options) { + if (!options || typeof options === "string") { + this.name = options; + this.requireAsWrapper = false; + } else { + this.name = options.name; + this.requireAsWrapper = options.requireAsWrapper; + } + } + + /** + * @param {Compilation} compilation the compilation instance + * @returns {void} + */ + apply(compilation) { + const { mainTemplate, chunkTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + const externals = chunk.getModules().filter(m => m.external); + const externalsDepsArray = JSON.stringify( + externals.map(m => + typeof m.request === "object" ? m.request.amd : m.request + ) + ); + const externalsArguments = externals + .map( + m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__` + ) + .join(", "); + + if (this.requireAsWrapper) { + return new ConcatSource( + `require(${externalsDepsArray}, function(${externalsArguments}) { return `, + source, + "});" + ); + } else if (this.name) { + const name = mainTemplate.getAssetPath(this.name, { + hash, + chunk + }); + + return new ConcatSource( + `define(${JSON.stringify( + name + )}, ${externalsDepsArray}, function(${externalsArguments}) { return `, + source, + "});" + ); + } else if (externalsArguments) { + return new ConcatSource( + `define(${externalsDepsArray}, function(${externalsArguments}) { return `, + source, + "});" + ); + } else { + return new ConcatSource("define(function() { return ", source, "});"); + } + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "AmdMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => { + if (this.name) { + paths.push(this.name); + } + return paths; + }); + + mainTemplate.hooks.hash.tap("AmdMainTemplatePlugin", hash => { + hash.update("exports amd"); + if (this.name) { + hash.update(this.name); + } + }); + } +} + +module.exports = AmdMainTemplatePlugin; diff --git a/node_modules/webpack/lib/AsyncDependenciesBlock.js b/node_modules/webpack/lib/AsyncDependenciesBlock.js new file mode 100644 index 0000000..a7e0291 --- /dev/null +++ b/node_modules/webpack/lib/AsyncDependenciesBlock.js @@ -0,0 +1,110 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependenciesBlock = require("./DependenciesBlock"); + +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ +/** @typedef {import("./util/createHash").Hash} Hash */ +/** @typedef {TODO} GroupOptions */ + +module.exports = class AsyncDependenciesBlock extends DependenciesBlock { + /** + * @param {GroupOptions} groupOptions options for the group + * @param {Module} module the Module object + * @param {DependencyLocation=} loc the line of code + * @param {TODO=} request the request + */ + constructor(groupOptions, module, loc, request) { + super(); + if (typeof groupOptions === "string") { + groupOptions = { name: groupOptions }; + } else if (!groupOptions) { + groupOptions = { name: undefined }; + } + this.groupOptions = groupOptions; + /** @type {ChunkGroup=} */ + this.chunkGroup = undefined; + this.module = module; + this.loc = loc; + this.request = request; + /** @type {DependenciesBlock} */ + this.parent = undefined; + } + + /** + * @returns {string} The name of the chunk + */ + get chunkName() { + return this.groupOptions.name; + } + + /** + * @param {string} value The new chunk name + * @returns {void} + */ + set chunkName(value) { + this.groupOptions.name = value; + } + + /** + * @returns {never} this throws and should never be called + */ + get chunks() { + throw new Error("Moved to AsyncDependenciesBlock.chunkGroup"); + } + + /** + * @param {never} value setter value + * @returns {never} this is going to throw therefore we should throw type + * assertions by returning never + */ + set chunks(value) { + throw new Error("Moved to AsyncDependenciesBlock.chunkGroup"); + } + + /** + * @param {Hash} hash the hash used to track block changes, from "crypto" module + * @returns {void} + */ + updateHash(hash) { + hash.update(JSON.stringify(this.groupOptions)); + hash.update( + (this.chunkGroup && + this.chunkGroup.chunks + .map(chunk => { + return chunk.id !== null ? chunk.id : ""; + }) + .join(",")) || + "" + ); + super.updateHash(hash); + } + + /** + * @returns {void} + */ + disconnect() { + this.chunkGroup = undefined; + super.disconnect(); + } + + /** + * @returns {void} + */ + unseal() { + this.chunkGroup = undefined; + super.unseal(); + } + + /** + * @returns {void} + */ + sortItems() { + super.sortItems(); + } +}; diff --git a/node_modules/webpack/lib/AsyncDependencyToInitialChunkError.js b/node_modules/webpack/lib/AsyncDependencyToInitialChunkError.js new file mode 100644 index 0000000..a0631aa --- /dev/null +++ b/node_modules/webpack/lib/AsyncDependencyToInitialChunkError.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ + +class AsyncDependencyToInitialChunkError extends WebpackError { + /** + * Creates an instance of AsyncDependencyToInitialChunkError. + * @param {string} chunkName Name of Chunk + * @param {Module} module module tied to dependency + * @param {TODO} loc location of dependency + */ + constructor(chunkName, module, loc) { + super( + `It's not allowed to load an initial chunk on demand. The chunk name "${chunkName}" is already used by an entrypoint.` + ); + + this.name = "AsyncDependencyToInitialChunkError"; + this.module = module; + this.loc = loc; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = AsyncDependencyToInitialChunkError; diff --git a/node_modules/webpack/lib/AutomaticPrefetchPlugin.js b/node_modules/webpack/lib/AutomaticPrefetchPlugin.js new file mode 100644 index 0000000..2d0db16 --- /dev/null +++ b/node_modules/webpack/lib/AutomaticPrefetchPlugin.js @@ -0,0 +1,57 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const asyncLib = require("neo-async"); +const PrefetchDependency = require("./dependencies/PrefetchDependency"); +const NormalModule = require("./NormalModule"); + +/** @typedef {import("./Compiler")} Compiler */ + +class AutomaticPrefetchPlugin { + /** + * Apply the plugin + * @param {Compiler} compiler Webpack Compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "AutomaticPrefetchPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + PrefetchDependency, + normalModuleFactory + ); + } + ); + let lastModules = null; + compiler.hooks.afterCompile.tap("AutomaticPrefetchPlugin", compilation => { + lastModules = compilation.modules + .filter(m => m instanceof NormalModule) + .map((/** @type {NormalModule} */ m) => ({ + context: m.context, + request: m.request + })); + }); + compiler.hooks.make.tapAsync( + "AutomaticPrefetchPlugin", + (compilation, callback) => { + if (!lastModules) return callback(); + asyncLib.forEach( + lastModules, + (m, callback) => { + compilation.prefetch( + m.context || compiler.context, + new PrefetchDependency(m.request), + callback + ); + }, + callback + ); + } + ); + } +} +module.exports = AutomaticPrefetchPlugin; diff --git a/node_modules/webpack/lib/BannerPlugin.js b/node_modules/webpack/lib/BannerPlugin.js new file mode 100644 index 0000000..322d854 --- /dev/null +++ b/node_modules/webpack/lib/BannerPlugin.js @@ -0,0 +1,122 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + +"use strict"; + +const { ConcatSource } = require("webpack-sources"); +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); +const Template = require("./Template"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/BannerPlugin.json"); + +/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */ +/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */ + +const wrapComment = str => { + if (!str.includes("\n")) { + return Template.toComment(str); + } + return `/*!\n * ${str + .replace(/\*\//g, "* /") + .split("\n") + .join("\n * ")}\n */`; +}; + +class BannerPlugin { + /** + * @param {BannerPluginArgument} options options object + */ + constructor(options) { + if (arguments.length > 1) { + throw new Error( + "BannerPlugin only takes one argument (pass an options object)" + ); + } + + validateOptions(schema, options, "Banner Plugin"); + + if (typeof options === "string" || typeof options === "function") { + options = { + banner: options + }; + } + + /** @type {BannerPluginOptions} */ + this.options = options; + + const bannerOption = options.banner; + if (typeof bannerOption === "function") { + const getBanner = bannerOption; + this.banner = this.options.raw + ? getBanner + : data => wrapComment(getBanner(data)); + } else { + const banner = this.options.raw + ? bannerOption + : wrapComment(bannerOption); + this.banner = () => banner; + } + } + + apply(compiler) { + const options = this.options; + const banner = this.banner; + const matchObject = ModuleFilenameHelpers.matchObject.bind( + undefined, + options + ); + + compiler.hooks.compilation.tap("BannerPlugin", compilation => { + compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => { + for (const chunk of chunks) { + if (options.entryOnly && !chunk.canBeInitial()) { + continue; + } + + for (const file of chunk.files) { + if (!matchObject(file)) { + continue; + } + + let query = ""; + let filename = file; + const hash = compilation.hash; + const querySplit = filename.indexOf("?"); + + if (querySplit >= 0) { + query = filename.substr(querySplit); + filename = filename.substr(0, querySplit); + } + + const lastSlashIndex = filename.lastIndexOf("/"); + + const basename = + lastSlashIndex === -1 + ? filename + : filename.substr(lastSlashIndex + 1); + + const data = { + hash, + chunk, + filename, + basename, + query + }; + + const comment = compilation.getPath(banner(data), data); + + compilation.updateAsset( + file, + old => new ConcatSource(comment, "\n", old) + ); + } + } + }); + }); + } +} + +module.exports = BannerPlugin; diff --git a/node_modules/webpack/lib/BasicEvaluatedExpression.js b/node_modules/webpack/lib/BasicEvaluatedExpression.js new file mode 100644 index 0000000..a0f7bd4 --- /dev/null +++ b/node_modules/webpack/lib/BasicEvaluatedExpression.js @@ -0,0 +1,248 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const TypeUnknown = 0; +const TypeNull = 1; +const TypeString = 2; +const TypeNumber = 3; +const TypeBoolean = 4; +const TypeRegExp = 5; +const TypeConditional = 6; +const TypeArray = 7; +const TypeConstArray = 8; +const TypeIdentifier = 9; +const TypeWrapped = 10; +const TypeTemplateString = 11; + +class BasicEvaluatedExpression { + constructor() { + this.type = TypeUnknown; + this.range = null; + this.falsy = false; + this.truthy = false; + this.bool = null; + this.number = null; + this.regExp = null; + this.string = null; + this.quasis = null; + this.parts = null; + this.array = null; + this.items = null; + this.options = null; + this.prefix = null; + this.postfix = null; + this.wrappedInnerExpressions = null; + this.expression = null; + } + + isNull() { + return this.type === TypeNull; + } + + isString() { + return this.type === TypeString; + } + + isNumber() { + return this.type === TypeNumber; + } + + 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; + } + + isTruthy() { + return this.truthy; + } + + isFalsy() { + return this.falsy; + } + + asBool() { + if (this.truthy) return true; + if (this.falsy) return false; + if (this.isBoolean()) return this.bool; + if (this.isNull()) return false; + if (this.isString()) return this.string !== ""; + if (this.isNumber()) return this.number !== 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; + } + + asString() { + if (this.isBoolean()) return `${this.bool}`; + if (this.isNull()) return "null"; + if (this.isString()) return this.string; + if (this.isNumber()) return `${this.number}`; + if (this.isRegExp()) return `${this.regExp}`; + if (this.isArray()) { + let array = []; + for (const item of 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 this.parts) { + const partStr = part.asString(); + if (partStr === undefined) return undefined; + str += partStr; + } + return str; + } + return undefined; + } + + setString(string) { + this.type = TypeString; + this.string = string; + return this; + } + + setNull() { + this.type = TypeNull; + return this; + } + + setNumber(number) { + this.type = TypeNumber; + this.number = number; + return this; + } + + setBoolean(bool) { + this.type = TypeBoolean; + this.bool = bool; + return this; + } + + setRegExp(regExp) { + this.type = TypeRegExp; + this.regExp = regExp; + return this; + } + + setIdentifier(identifier) { + this.type = TypeIdentifier; + this.identifier = identifier; + return this; + } + + setWrapped(prefix, postfix, innerExpressions) { + this.type = TypeWrapped; + this.prefix = prefix; + this.postfix = postfix; + this.wrappedInnerExpressions = innerExpressions; + return this; + } + + setOptions(options) { + this.type = TypeConditional; + this.options = options; + return this; + } + + addOptions(options) { + if (!this.options) { + this.type = TypeConditional; + this.options = []; + } + for (const item of options) { + this.options.push(item); + } + return this; + } + + setItems(items) { + this.type = TypeArray; + this.items = items; + return this; + } + + setArray(array) { + this.type = TypeConstArray; + this.array = array; + return this; + } + + setTemplateString(quasis, parts, kind) { + this.type = TypeTemplateString; + this.quasis = quasis; + this.parts = parts; + this.templateStringKind = kind; + return this; + } + + setTruthy() { + this.falsy = false; + this.truthy = true; + return this; + } + + setFalsy() { + this.falsy = true; + this.truthy = false; + return this; + } + + setRange(range) { + this.range = range; + return this; + } + + setExpression(expression) { + this.expression = expression; + return this; + } +} + +module.exports = BasicEvaluatedExpression; diff --git a/node_modules/webpack/lib/CachePlugin.js b/node_modules/webpack/lib/CachePlugin.js new file mode 100644 index 0000000..68da003 --- /dev/null +++ b/node_modules/webpack/lib/CachePlugin.js @@ -0,0 +1,100 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const asyncLib = require("neo-async"); + +class CachePlugin { + constructor(cache) { + this.cache = cache || {}; + this.FS_ACCURACY = 2000; + } + + apply(compiler) { + if (Array.isArray(compiler.compilers)) { + compiler.compilers.forEach((c, idx) => { + new CachePlugin((this.cache[idx] = this.cache[idx] || {})).apply(c); + }); + } else { + const registerCacheToCompiler = (compiler, cache) => { + compiler.hooks.thisCompilation.tap("CachePlugin", compilation => { + compilation.cache = cache; + compilation.hooks.childCompiler.tap( + "CachePlugin", + (childCompiler, compilerName, compilerIndex) => { + let childCache; + if (!cache.children) { + cache.children = {}; + } + if (!cache.children[compilerName]) { + cache.children[compilerName] = []; + } + if (cache.children[compilerName][compilerIndex]) { + childCache = cache.children[compilerName][compilerIndex]; + } else { + cache.children[compilerName].push((childCache = {})); + } + registerCacheToCompiler(childCompiler, childCache); + } + ); + }); + }; + registerCacheToCompiler(compiler, this.cache); + compiler.hooks.watchRun.tap("CachePlugin", () => { + this.watching = true; + }); + compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => { + if (!compiler._lastCompilationFileDependencies) { + return callback(); + } + const fs = compiler.inputFileSystem; + const fileTs = (compiler.fileTimestamps = new Map()); + asyncLib.forEach( + compiler._lastCompilationFileDependencies, + (file, callback) => { + fs.stat(file, (err, stat) => { + if (err) { + if (err.code === "ENOENT") return callback(); + return callback(err); + } + + if (stat.mtime) this.applyMtime(+stat.mtime); + + fileTs.set(file, +stat.mtime || Infinity); + + callback(); + }); + }, + err => { + if (err) return callback(err); + + for (const [file, ts] of fileTs) { + fileTs.set(file, ts + this.FS_ACCURACY); + } + + callback(); + } + ); + }); + compiler.hooks.afterCompile.tap("CachePlugin", compilation => { + compilation.compiler._lastCompilationFileDependencies = + compilation.fileDependencies; + compilation.compiler._lastCompilationContextDependencies = + compilation.contextDependencies; + }); + } + } + + /* istanbul ignore next */ + applyMtime(mtime) { + if (this.FS_ACCURACY > 1 && mtime % 2 !== 0) this.FS_ACCURACY = 1; + else if (this.FS_ACCURACY > 10 && mtime % 20 !== 0) this.FS_ACCURACY = 10; + else if (this.FS_ACCURACY > 100 && mtime % 200 !== 0) + this.FS_ACCURACY = 100; + else if (this.FS_ACCURACY > 1000 && mtime % 2000 !== 0) + this.FS_ACCURACY = 1000; + } +} +module.exports = CachePlugin; diff --git a/node_modules/webpack/lib/CaseSensitiveModulesWarning.js b/node_modules/webpack/lib/CaseSensitiveModulesWarning.js new file mode 100644 index 0000000..6bfeeca --- /dev/null +++ b/node_modules/webpack/lib/CaseSensitiveModulesWarning.js @@ -0,0 +1,67 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ + +/** + * @param {Module[]} modules the modules to be sorted + * @returns {Module[]} sorted version of original modules + */ +const sortModules = modules => { + return modules.slice().sort((a, b) => { + const aIdent = a.identifier(); + const bIdent = b.identifier(); + /* istanbul ignore next */ + if (aIdent < bIdent) return -1; + /* istanbul ignore next */ + if (aIdent > bIdent) return 1; + /* istanbul ignore next */ + return 0; + }); +}; + +/** + * @param {Module[]} modules each module from throw + * @returns {string} each message from provided moduels + */ +const createModulesListMessage = modules => { + return modules + .map(m => { + let message = `* ${m.identifier()}`; + const validReasons = m.reasons.filter(reason => reason.module); + + if (validReasons.length > 0) { + message += `\n Used by ${validReasons.length} module(s), i. e.`; + message += `\n ${validReasons[0].module.identifier()}`; + } + return message; + }) + .join("\n"); +}; + +class CaseSensitiveModulesWarning extends WebpackError { + /** + * Creates an instance of CaseSensitiveModulesWarning. + * @param {Module[]} modules modules that were detected + */ + constructor(modules) { + const sortedModules = sortModules(modules); + const modulesList = createModulesListMessage(sortedModules); + super(`There are multiple modules with names that only differ in casing. +This can lead to unexpected behavior when compiling on a filesystem with other case-semantic. +Use equal casing. Compare these module identifiers: +${modulesList}`); + + this.name = "CaseSensitiveModulesWarning"; + this.origin = this.module = sortedModules[0]; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = CaseSensitiveModulesWarning; diff --git a/node_modules/webpack/lib/Chunk.js b/node_modules/webpack/lib/Chunk.js new file mode 100644 index 0000000..db644ee --- /dev/null +++ b/node_modules/webpack/lib/Chunk.js @@ -0,0 +1,875 @@ +/* +MIT License http://www.opensource.org/licenses/mit-license.php +Author Tobias Koppers @sokra +*/ +"use strict"; + +const util = require("util"); +const SortableSet = require("./util/SortableSet"); +const intersect = require("./util/SetHelpers").intersect; +const GraphHelpers = require("./GraphHelpers"); +const Entrypoint = require("./Entrypoint"); +let debugId = 1000; +const ERR_CHUNK_ENTRY = "Chunk.entry was removed. Use hasRuntime()"; +const ERR_CHUNK_INITIAL = + "Chunk.initial was removed. Use canBeInitial/isOnlyInitial()"; + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./ModuleReason")} ModuleReason */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./util/createHash").Hash} Hash */ + +/** + * @typedef {Object} WithId an object who has an id property * + * @property {string | number} id the id of the object + */ + +/** + * Compare two Modules based on their ids for sorting + * @param {Module} a module + * @param {Module} b module + * @returns {-1|0|1} sort value + */ + +// TODO use @callback +/** @typedef {(a: Module, b: Module) => -1|0|1} ModuleSortPredicate */ +/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */ +/** @typedef {(c: Chunk) => boolean} ChunkFilterPredicate */ + +const sortModuleById = (a, b) => { + if (a.id < b.id) return -1; + if (b.id < a.id) return 1; + return 0; +}; + +/** + * Compare two ChunkGroups based on their ids for sorting + * @param {ChunkGroup} a chunk group + * @param {ChunkGroup} b chunk group + * @returns {-1|0|1} sort value + */ +const sortChunkGroupById = (a, b) => { + if (a.id < b.id) return -1; + if (b.id < a.id) return 1; + return 0; +}; + +/** + * Compare two Identifiables , based on their ids for sorting + * @param {Module} a first object with ident fn + * @param {Module} b second object with ident fn + * @returns {-1|0|1} The order number of the sort + */ +const sortByIdentifier = (a, b) => { + if (a.identifier() > b.identifier()) return 1; + if (a.identifier() < b.identifier()) return -1; + return 0; +}; + +/** + * @returns {string} a concatenation of module identifiers sorted + * @param {SortableSet} set to pull module identifiers from + */ +const getModulesIdent = set => { + set.sort(); + let str = ""; + for (const m of set) { + str += m.identifier() + "#"; + } + return str; +}; + +/** + * @template T + * @param {SortableSet<T>} set the sortable set to convert to array + * @returns {Array<T>} the array returned from Array.from(set) + */ +const getArray = set => Array.from(set); + +/** + * @param {SortableSet<Module>} set the sortable Set to get the count/size of + * @returns {number} the size of the modules + */ +const getModulesSize = set => { + let size = 0; + for (const module of set) { + size += module.size(); + } + return size; +}; + +/** + * A Chunk is a unit of encapsulation for Modules. + * Chunks are "rendered" into bundles that get emitted when the build completes. + */ +class Chunk { + /** + * @param {string=} name of chunk being created, is optional (for subclasses) + */ + constructor(name) { + /** @type {number | null} */ + this.id = null; + /** @type {number[] | null} */ + this.ids = null; + /** @type {number} */ + this.debugId = debugId++; + /** @type {string} */ + this.name = name; + /** @type {boolean} */ + this.preventIntegration = false; + /** @type {Module=} */ + this.entryModule = undefined; + /** @private @type {SortableSet<Module>} */ + this._modules = new SortableSet(undefined, sortByIdentifier); + /** @type {string?} */ + this.filenameTemplate = undefined; + /** @private @type {SortableSet<ChunkGroup>} */ + this._groups = new SortableSet(undefined, sortChunkGroupById); + /** @type {string[]} */ + this.files = []; + /** @type {boolean} */ + this.rendered = false; + /** @type {string=} */ + this.hash = undefined; + /** @type {Object} */ + this.contentHash = Object.create(null); + /** @type {string=} */ + this.renderedHash = undefined; + /** @type {string=} */ + this.chunkReason = undefined; + /** @type {boolean} */ + this.extraAsync = false; + this.removedModules = undefined; + } + + /** + * @deprecated Chunk.entry has been deprecated. Please use .hasRuntime() instead + * @returns {never} Throws an error trying to access this property + */ + get entry() { + throw new Error(ERR_CHUNK_ENTRY); + } + + /** + * @deprecated .entry has been deprecated. Please use .hasRuntime() instead + * @param {never} data The data that was attempting to be set + * @returns {never} Throws an error trying to access this property + */ + set entry(data) { + throw new Error(ERR_CHUNK_ENTRY); + } + + /** + * @deprecated Chunk.initial was removed. Use canBeInitial/isOnlyInitial() + * @returns {never} Throws an error trying to access this property + */ + get initial() { + throw new Error(ERR_CHUNK_INITIAL); + } + + /** + * @deprecated Chunk.initial was removed. Use canBeInitial/isOnlyInitial() + * @param {never} data The data attempting to be set + * @returns {never} Throws an error trying to access this property + */ + set initial(data) { + throw new Error(ERR_CHUNK_INITIAL); + } + + /** + * @returns {boolean} whether or not the Chunk will have a runtime + */ + hasRuntime() { + for (const chunkGroup of this._groups) { + if ( + chunkGroup.isInitial() && + chunkGroup instanceof Entrypoint && + chunkGroup.getRuntimeChunk() === this + ) { + return true; + } + } + return false; + } + + /** + * @returns {boolean} whether or not this chunk can be an initial chunk + */ + canBeInitial() { + for (const chunkGroup of this._groups) { + if (chunkGroup.isInitial()) return true; + } + return false; + } + + /** + * @returns {boolean} whether this chunk can only be an initial chunk + */ + isOnlyInitial() { + if (this._groups.size <= 0) return false; + for (const chunkGroup of this._groups) { + if (!chunkGroup.isInitial()) return false; + } + return true; + } + + /** + * @returns {boolean} if this chunk contains the entry module + */ + hasEntryModule() { + return !!this.entryModule; + } + + /** + * @param {Module} module the module that will be added to this chunk. + * @returns {boolean} returns true if the chunk doesn't have the module and it was added + */ + addModule(module) { + if (!this._modules.has(module)) { + this._modules.add(module); + return true; + } + return false; + } + + /** + * @param {Module} module the module that will be removed from this chunk + * @returns {boolean} returns true if chunk exists and is successfully deleted + */ + removeModule(module) { + if (this._modules.delete(module)) { + module.removeChunk(this); + return true; + } + return false; + } + + /** + * @param {Module[]} modules the new modules to be set + * @returns {void} set new modules to this chunk and return nothing + */ + setModules(modules) { + this._modules = new SortableSet(modules, sortByIdentifier); + } + + /** + * @returns {number} the amount of modules in chunk + */ + getNumberOfModules() { + return this._modules.size; + } + + /** + * @returns {SortableSet} return the modules SortableSet for this chunk + */ + get modulesIterable() { + return this._modules; + } + + /** + * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being added + * @returns {boolean} returns true if chunk is not apart of chunkGroup and is added successfully + */ + addGroup(chunkGroup) { + if (this._groups.has(chunkGroup)) return false; + this._groups.add(chunkGroup); + return true; + } + + /** + * @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being removed from + * @returns {boolean} returns true if chunk does exist in chunkGroup and is removed + */ + removeGroup(chunkGroup) { + if (!this._groups.has(chunkGroup)) return false; + this._groups.delete(chunkGroup); + return true; + } + + /** + * @param {ChunkGroup} chunkGroup the chunkGroup to check + * @returns {boolean} returns true if chunk has chunkGroup reference and exists in chunkGroup + */ + isInGroup(chunkGroup) { + return this._groups.has(chunkGroup); + } + + /** + * @returns {number} the amount of groups said chunk is in + */ + getNumberOfGroups() { + return this._groups.size; + } + + /** + * @returns {SortableSet<ChunkGroup>} the chunkGroups that said chunk is referenced in + */ + get groupsIterable() { + return this._groups; + } + + /** + * @param {Chunk} otherChunk the chunk to compare itself with + * @returns {-1|0|1} this is a comparitor function like sort and returns -1, 0, or 1 based on sort order + */ + compareTo(otherChunk) { + if (this.name && !otherChunk.name) return -1; + if (!this.name && otherChunk.name) return 1; + if (this.name < otherChunk.name) return -1; + if (this.name > otherChunk.name) return 1; + if (this._modules.size > otherChunk._modules.size) return -1; + if (this._modules.size < otherChunk._modules.size) return 1; + this._modules.sort(); + otherChunk._modules.sort(); + const a = this._modules[Symbol.iterator](); + const b = otherChunk._modules[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = a.next(); + if (aItem.done) return 0; + const bItem = b.next(); + const aModuleIdentifier = aItem.value.identifier(); + const bModuleIdentifier = bItem.value.identifier(); + if (aModuleIdentifier < bModuleIdentifier) return -1; + if (aModuleIdentifier > bModuleIdentifier) return 1; + } + } + + /** + * @param {Module} module Module to check + * @returns {boolean} returns true if module does exist in this chunk + */ + containsModule(module) { + return this._modules.has(module); + } + + /** + * @returns {Module[]} an array of modules (do not modify) + */ + getModules() { + return this._modules.getFromCache(getArray); + } + + getModulesIdent() { + return this._modules.getFromUnorderedCache(getModulesIdent); + } + + /** + * @param {string=} reason reason why chunk is removed + * @returns {void} + */ + remove(reason) { + // cleanup modules + // Array.from is used here to create a clone, because removeChunk modifies this._modules + for (const module of Array.from(this._modules)) { + module.removeChunk(this); + } + for (const chunkGroup of this._groups) { + chunkGroup.removeChunk(this); + } + } + + /** + * + * @param {Module} module module to move + * @param {Chunk} otherChunk other chunk to move it to + * @returns {void} + */ + moveModule(module, otherChunk) { + GraphHelpers.disconnectChunkAndModule(this, module); + GraphHelpers.connectChunkAndModule(otherChunk, module); + module.rewriteChunkInReasons(this, [otherChunk]); + } + + /** + * + * @param {Chunk} otherChunk the chunk to integrate with + * @param {string} reason reason why the module is being integrated + * @returns {boolean} returns true or false if integration succeeds or fails + */ + integrate(otherChunk, reason) { + if (!this.canBeIntegrated(otherChunk)) { + return false; + } + + // Pick a new name for the integrated chunk + if (this.name && otherChunk.name) { + if (this.hasEntryModule() === otherChunk.hasEntryModule()) { + // When both chunks have entry modules or none have one, use + // shortest name + if (this.name.length !== otherChunk.name.length) { + this.name = + this.name.length < otherChunk.name.length + ? this.name + : otherChunk.name; + } else { + this.name = this.name < otherChunk.name ? this.name : otherChunk.name; + } + } else if (otherChunk.hasEntryModule()) { + // Pick the name of the chunk with the entry module + this.name = otherChunk.name; + } + } else if (otherChunk.name) { + this.name = otherChunk.name; + } + + // Array.from is used here to create a clone, because moveModule modifies otherChunk._modules + for (const module of Array.from(otherChunk._modules)) { + otherChunk.moveModule(module, this); + } + otherChunk._modules.clear(); + + if (otherChunk.entryModule) { + this.entryModule = otherChunk.entryModule; + } + + for (const chunkGroup of otherChunk._groups) { + chunkGroup.replaceChunk(otherChunk, this); + this.addGroup(chunkGroup); + } + otherChunk._groups.clear(); + + return true; + } + + /** + * @param {Chunk} newChunk the new chunk that will be split out of the current chunk + * @returns {void} + */ + split(newChunk) { + for (const chunkGroup of this._groups) { + chunkGroup.insertChunk(newChunk, this); + newChunk.addGroup(chunkGroup); + } + } + + isEmpty() { + return this._modules.size === 0; + } + + updateHash(hash) { + hash.update(`${this.id} `); + hash.update(this.ids ? this.ids.join(",") : ""); + hash.update(`${this.name || ""} `); + for (const m of this._modules) { + hash.update(m.hash); + } + } + + canBeIntegrated(otherChunk) { + if (this.preventIntegration || otherChunk.preventIntegration) { + return false; + } + + /** + * @param {Chunk} a chunk + * @param {Chunk} b chunk + * @returns {boolean} true, if a is always available when b is reached + */ + const isAvailable = (a, b) => { + const queue = new Set(b.groupsIterable); + for (const chunkGroup of queue) { + if (a.isInGroup(chunkGroup)) continue; + if (chunkGroup.isInitial()) return false; + for (const parent of chunkGroup.parentsIterable) { + queue.add(parent); + } + } + return true; + }; + + const selfHasRuntime = this.hasRuntime(); + const otherChunkHasRuntime = otherChunk.hasRuntime(); + + if (selfHasRuntime !== otherChunkHasRuntime) { + if (selfHasRuntime) { + return isAvailable(this, otherChunk); + } else if (otherChunkHasRuntime) { + return isAvailable(otherChunk, this); + } else { + return false; + } + } + + if (this.hasEntryModule() || otherChunk.hasEntryModule()) { + return false; + } + + return true; + } + + /** + * + * @param {number} size the size + * @param {Object} options the options passed in + * @returns {number} the multiplier returned + */ + addMultiplierAndOverhead(size, options) { + const overhead = + typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000; + const multiplicator = this.canBeInitial() + ? options.entryChunkMultiplicator || 10 + : 1; + + return size * multiplicator + overhead; + } + + /** + * @returns {number} the size of all modules + */ + modulesSize() { + return this._modules.getFromUnorderedCache(getModulesSize); + } + + /** + * @param {Object} options the size display options + * @returns {number} the chunk size + */ + size(options = {}) { + return this.addMultiplierAndOverhead(this.modulesSize(), options); + } + + /** + * @param {Chunk} otherChunk the other chunk + * @param {TODO} options the options for this function + * @returns {number | false} the size, or false if it can't be integrated + */ + integratedSize(otherChunk, options) { + // Chunk if it's possible to integrate this chunk + if (!this.canBeIntegrated(otherChunk)) { + return false; + } + + let integratedModulesSize = this.modulesSize(); + // only count modules that do not exist in this chunk! + for (const otherModule of otherChunk._modules) { + if (!this._modules.has(otherModule)) { + integratedModulesSize += otherModule.size(); + } + } + + return this.addMultiplierAndOverhead(integratedModulesSize, options); + } + + /** + * @param {function(Module, Module): -1|0|1=} sortByFn a predicate function used to sort modules + * @returns {void} + */ + sortModules(sortByFn) { + this._modules.sortWith(sortByFn || sortModuleById); + } + + sortItems() { + this.sortModules(); + } + + /** + * @returns {Set<Chunk>} a set of all the async chunks + */ + getAllAsyncChunks() { + const queue = new Set(); + const chunks = new Set(); + + const initialChunks = intersect( + Array.from(this.groupsIterable, g => new Set(g.chunks)) + ); + + for (const chunkGroup of this.groupsIterable) { + for (const child of chunkGroup.childrenIterable) { + queue.add(child); + } + } + + for (const chunkGroup of queue) { + for (const chunk of chunkGroup.chunks) { + if (!initialChunks.has(chunk)) { + chunks.add(chunk); + } + } + for (const child of chunkGroup.childrenIterable) { + queue.add(child); + } + } + + return chunks; + } + + /** + * @typedef {Object} ChunkMaps + * @property {Record<string|number, string>} hash + * @property {Record<string|number, Record<string, string>>} contentHash + * @property {Record<string|number, string>} name + */ + + /** + * @param {boolean} realHash should the full hash or the rendered hash be used + * @returns {ChunkMaps} the chunk map information + */ + getChunkMaps(realHash) { + /** @type {Record<string|number, string>} */ + const chunkHashMap = Object.create(null); + /** @type {Record<string|number, Record<string, string>>} */ + const chunkContentHashMap = Object.create(null); + /** @type {Record<string|number, string>} */ + const chunkNameMap = Object.create(null); + + for (const chunk of this.getAllAsyncChunks()) { + chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash; + for (const key of Object.keys(chunk.contentHash)) { + if (!chunkContentHashMap[key]) { + chunkContentHashMap[key] = Object.create(null); + } + chunkContentHashMap[key][chunk.id] = chunk.contentHash[key]; + } + if (chunk.name) { + chunkNameMap[chunk.id] = chunk.name; + } + } + + return { + hash: chunkHashMap, + contentHash: chunkContentHashMap, + name: chunkNameMap + }; + } + + /** + * @returns {Record<string, Set<TODO>[]>} a record object of names to lists of child ids(?) + */ + getChildIdsByOrders() { + const lists = new Map(); + for (const group of this.groupsIterable) { + if (group.chunks[group.chunks.length - 1] === this) { + for (const childGroup of group.childrenIterable) { + // TODO webpack 5 remove this check for options + if (typeof childGroup.options === "object") { + for (const key of Object.keys(childGroup.options)) { + if (key.endsWith("Order")) { + const name = key.substr(0, key.length - "Order".length); + let list = lists.get(name); + if (list === undefined) lists.set(name, (list = [])); + list.push({ + order: childGroup.options[key], + group: childGroup + }); + } + } + } + } + } + } + const result = Object.create(null); + for (const [name, list] of lists) { + list.sort((a, b) => { + const cmp = b.order - a.order; + if (cmp !== 0) return cmp; + // TODO webpack 5 remove this check of compareTo + if (a.group.compareTo) { + return a.group.compareTo(b.group); + } + return 0; + }); + result[name] = Array.from( + list.reduce((set, item) => { + for (const chunk of item.group.chunks) { + set.add(chunk.id); + } + return set; + }, new Set()) + ); + } + return result; + } + + getChildIdsByOrdersMap(includeDirectChildren) { + const chunkMaps = Object.create(null); + + const addChildIdsByOrdersToMap = chunk => { + const data = chunk.getChildIdsByOrders(); + for (const key of Object.keys(data)) { + let chunkMap = chunkMaps[key]; + if (chunkMap === undefined) { + chunkMaps[key] = chunkMap = Object.create(null); + } + chunkMap[chunk.id] = data[key]; + } + }; + + if (includeDirectChildren) { + const chunks = new Set(); + for (const chunkGroup of this.groupsIterable) { + for (const chunk of chunkGroup.chunks) { + chunks.add(chunk); + } + } + for (const chunk of chunks) { + addChildIdsByOrdersToMap(chunk); + } + } + + for (const chunk of this.getAllAsyncChunks()) { + addChildIdsByOrdersToMap(chunk); + } + + return chunkMaps; + } + + /** + * @typedef {Object} ChunkModuleMaps + * @property {Record<string|number, (string|number)[]>} id + * @property {Record<string|number, string>} hash + */ + + /** + * @param {ModuleFilterPredicate} filterFn function used to filter modules + * @returns {ChunkModuleMaps} module map information + */ + getChunkModuleMaps(filterFn) { + /** @type {Record<string|number, (string|number)[]>} */ + const chunkModuleIdMap = Object.create(null); + /** @type {Record<string|number, string>} */ + const chunkModuleHashMap = Object.create(null); + + for (const chunk of this.getAllAsyncChunks()) { + /** @type {(string|number)[]} */ + let array; + for (const module of chunk.modulesIterable) { + if (filterFn(module)) { + if (array === undefined) { + array = []; + chunkModuleIdMap[chunk.id] = array; + } + array.push(module.id); + chunkModuleHashMap[module.id] = module.renderedHash; + } + } + if (array !== undefined) { + array.sort(); + } + } + + return { + id: chunkModuleIdMap, + hash: chunkModuleHashMap + }; + } + + /** + * + * @param {function(Module): boolean} filterFn predicate function used to filter modules + * @param {function(Chunk): boolean} filterChunkFn predicate function used to filter chunks + * @returns {boolean} return true if module exists in graph + */ + hasModuleInGraph(filterFn, filterChunkFn) { + const queue = new Set(this.groupsIterable); + const chunksProcessed = new Set(); + + for (const chunkGroup of queue) { + for (const chunk of chunkGroup.chunks) { + if (!chunksProcessed.has(chunk)) { + chunksProcessed.add(chunk); + if (!filterChunkFn || filterChunkFn(chunk)) { + for (const module of chunk.modulesIterable) { + if (filterFn(module)) { + return true; + } + } + } + } + } + for (const child of chunkGroup.childrenIterable) { + queue.add(child); + } + } + return false; + } + + toString() { + return `Chunk[${Array.from(this._modules).join()}]`; + } +} + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "forEachModule", { + configurable: false, + value: util.deprecate( + /** + * @deprecated + * @this {Chunk} + * @typedef {function(any, any, Set<any>): void} ForEachModuleCallback + * @param {ForEachModuleCallback} fn Callback function + * @returns {void} + */ + function(fn) { + this._modules.forEach(fn); + }, + "Chunk.forEachModule: Use for(const module of chunk.modulesIterable) instead" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "mapModules", { + configurable: false, + value: util.deprecate( + /** + * @deprecated + * @this {Chunk} + * @typedef {function(any, number): any} MapModulesCallback + * @param {MapModulesCallback} fn Callback function + * @returns {TODO[]} result of mapped modules + */ + function(fn) { + return Array.from(this._modules, fn); + }, + "Chunk.mapModules: Use Array.from(chunk.modulesIterable, fn) instead" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "chunks", { + configurable: false, + get() { + throw new Error("Chunk.chunks: Use ChunkGroup.getChildren() instead"); + }, + set() { + throw new Error("Chunk.chunks: Use ChunkGroup.add/removeChild() instead"); + } +}); + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "parents", { + configurable: false, + get() { + throw new Error("Chunk.parents: Use ChunkGroup.getParents() instead"); + }, + set() { + throw new Error("Chunk.parents: Use ChunkGroup.add/removeParent() instead"); + } +}); + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "blocks", { + configurable: false, + get() { + throw new Error("Chunk.blocks: Use ChunkGroup.getBlocks() instead"); + }, + set() { + throw new Error("Chunk.blocks: Use ChunkGroup.add/removeBlock() instead"); + } +}); + +// TODO remove in webpack 5 +Object.defineProperty(Chunk.prototype, "entrypoints", { + configurable: false, + get() { + throw new Error( + "Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead" + ); + }, + set() { + throw new Error("Chunk.entrypoints: Use Chunks.addGroup instead"); + } +}); + +module.exports = Chunk; diff --git a/node_modules/webpack/lib/ChunkGroup.js b/node_modules/webpack/lib/ChunkGroup.js new file mode 100644 index 0000000..6f0ad97 --- /dev/null +++ b/node_modules/webpack/lib/ChunkGroup.js @@ -0,0 +1,513 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const SortableSet = require("./util/SortableSet"); +const compareLocations = require("./compareLocations"); + +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./ModuleReason")} ModuleReason */ + +/** @typedef {{module: Module, loc: TODO, request: string}} OriginRecord */ +/** @typedef {string|{name: string}} ChunkGroupOptions */ + +let debugId = 5000; + +/** + * @template T + * @param {SortableSet<T>} set set to convert to array. + * @returns {T[]} the array format of existing set + */ +const getArray = set => Array.from(set); + +/** + * A convenience method used to sort chunks based on their id's + * @param {ChunkGroup} a first sorting comparator + * @param {ChunkGroup} b second sorting comparator + * @returns {1|0|-1} a sorting index to determine order + */ +const sortById = (a, b) => { + if (a.id < b.id) return -1; + if (b.id < a.id) return 1; + return 0; +}; + +/** + * @param {OriginRecord} a the first comparator in sort + * @param {OriginRecord} b the second comparator in sort + * @returns {1|-1|0} returns sorting order as index + */ +const sortOrigin = (a, b) => { + const aIdent = a.module ? a.module.identifier() : ""; + const bIdent = b.module ? b.module.identifier() : ""; + if (aIdent < bIdent) return -1; + if (aIdent > bIdent) return 1; + return compareLocations(a.loc, b.loc); +}; + +class ChunkGroup { + /** + * Creates an instance of ChunkGroup. + * @param {ChunkGroupOptions=} options chunk group options passed to chunkGroup + */ + constructor(options) { + if (typeof options === "string") { + options = { name: options }; + } else if (!options) { + options = { name: undefined }; + } + /** @type {number} */ + this.groupDebugId = debugId++; + this.options = options; + /** @type {SortableSet<ChunkGroup>} */ + this._children = new SortableSet(undefined, sortById); + this._parents = new SortableSet(undefined, sortById); + this._blocks = new SortableSet(); + /** @type {Chunk[]} */ + this.chunks = []; + /** @type {OriginRecord[]} */ + this.origins = []; + /** Indices in top-down order */ + /** @private @type {Map<Module, number>} */ + this._moduleIndices = new Map(); + /** Indices in bottom-up order */ + /** @private @type {Map<Module, number>} */ + this._moduleIndices2 = new Map(); + } + + /** + * when a new chunk is added to a chunkGroup, addingOptions will occur. + * @param {ChunkGroupOptions} options the chunkGroup options passed to addOptions + * @returns {void} + */ + addOptions(options) { + for (const key of Object.keys(options)) { + if (this.options[key] === undefined) { + this.options[key] = options[key]; + } else if (this.options[key] !== options[key]) { + if (key.endsWith("Order")) { + this.options[key] = Math.max(this.options[key], options[key]); + } else { + throw new Error( + `ChunkGroup.addOptions: No option merge strategy for ${key}` + ); + } + } + } + } + + /** + * returns the name of current ChunkGroup + * @returns {string|undefined} returns the ChunkGroup name + */ + get name() { + return this.options.name; + } + + /** + * sets a new name for current ChunkGroup + * @param {string} value the new name for ChunkGroup + * @returns {void} + */ + set name(value) { + this.options.name = value; + } + + /** + * get a uniqueId for ChunkGroup, made up of its member Chunk debugId's + * @returns {string} a unique concatenation of chunk debugId's + */ + get debugId() { + return Array.from(this.chunks, x => x.debugId).join("+"); + } + + /** + * get a unique id for ChunkGroup, made up of its member Chunk id's + * @returns {string} a unique concatenation of chunk ids + */ + get id() { + return Array.from(this.chunks, x => x.id).join("+"); + } + + /** + * Performs an unshift of a specific chunk + * @param {Chunk} chunk chunk being unshifted + * @returns {boolean} returns true if attempted chunk shift is accepted + */ + unshiftChunk(chunk) { + const oldIdx = this.chunks.indexOf(chunk); + if (oldIdx > 0) { + this.chunks.splice(oldIdx, 1); + this.chunks.unshift(chunk); + } else if (oldIdx < 0) { + this.chunks.unshift(chunk); + return true; + } + return false; + } + + /** + * inserts a chunk before another existing chunk in group + * @param {Chunk} chunk Chunk being inserted + * @param {Chunk} before Placeholder/target chunk marking new chunk insertion point + * @returns {boolean} return true if insertion was successful + */ + insertChunk(chunk, before) { + const oldIdx = this.chunks.indexOf(chunk); + const idx = this.chunks.indexOf(before); + if (idx < 0) { + throw new Error("before chunk not found"); + } + if (oldIdx >= 0 && oldIdx > idx) { + this.chunks.splice(oldIdx, 1); + this.chunks.splice(idx, 0, chunk); + } else if (oldIdx < 0) { + this.chunks.splice(idx, 0, chunk); + return true; + } + return false; + } + + /** + * add a chunk into ChunkGroup. Is pushed on or prepended + * @param {Chunk} chunk chunk being pushed into ChunkGroupS + * @returns {boolean} returns true if chunk addition was successful. + */ + pushChunk(chunk) { + const oldIdx = this.chunks.indexOf(chunk); + if (oldIdx >= 0) { + return false; + } + this.chunks.push(chunk); + return true; + } + + /** + * @param {Chunk} oldChunk chunk to be replaced + * @param {Chunk} newChunk New chunk that will be replaced with + * @returns {boolean} returns true if the replacement was successful + */ + replaceChunk(oldChunk, newChunk) { + const oldIdx = this.chunks.indexOf(oldChunk); + if (oldIdx < 0) return false; + const newIdx = this.chunks.indexOf(newChunk); + if (newIdx < 0) { + this.chunks[oldIdx] = newChunk; + return true; + } + if (newIdx < oldIdx) { + this.chunks.splice(oldIdx, 1); + return true; + } else if (newIdx !== oldIdx) { + this.chunks[oldIdx] = newChunk; + this.chunks.splice(newIdx, 1); + return true; + } + } + + removeChunk(chunk) { + const idx = this.chunks.indexOf(chunk); + if (idx >= 0) { + this.chunks.splice(idx, 1); + return true; + } + return false; + } + + isInitial() { + return false; + } + + addChild(chunk) { + if (this._children.has(chunk)) { + return false; + } + this._children.add(chunk); + return true; + } + + getChildren() { + return this._children.getFromCache(getArray); + } + + getNumberOfChildren() { + return this._children.size; + } + + get childrenIterable() { + return this._children; + } + + removeChild(chunk) { + if (!this._children.has(chunk)) { + return false; + } + + this._children.delete(chunk); + chunk.removeParent(this); + return true; + } + + addParent(parentChunk) { + if (!this._parents.has(parentChunk)) { + this._parents.add(parentChunk); + return true; + } + return false; + } + + getParents() { + return this._parents.getFromCache(getArray); + } + + setParents(newParents) { + this._parents.clear(); + for (const p of newParents) { + this._parents.add(p); + } + } + + getNumberOfParents() { + return this._parents.size; + } + + hasParent(parent) { + return this._parents.has(parent); + } + + get parentsIterable() { + return this._parents; + } + + removeParent(chunk) { + if (this._parents.delete(chunk)) { + chunk.removeChunk(this); + return true; + } + return false; + } + + /** + * @returns {Array} - an array containing the blocks + */ + getBlocks() { + return this._blocks.getFromCache(getArray); + } + + getNumberOfBlocks() { + return this._blocks.size; + } + + hasBlock(block) { + return this._blocks.has(block); + } + + get blocksIterable() { + return this._blocks; + } + + addBlock(block) { + if (!this._blocks.has(block)) { + this._blocks.add(block); + return true; + } + return false; + } + + addOrigin(module, loc, request) { + this.origins.push({ + module, + loc, + request + }); + } + + containsModule(module) { + for (const chunk of this.chunks) { + if (chunk.containsModule(module)) return true; + } + return false; + } + + getFiles() { + const files = new Set(); + + for (const chunk of this.chunks) { + for (const file of chunk.files) { + files.add(file); + } + } + + return Array.from(files); + } + + /** + * @param {string=} reason reason for removing ChunkGroup + * @returns {void} + */ + remove(reason) { + // cleanup parents + for (const parentChunkGroup of this._parents) { + // remove this chunk from its parents + parentChunkGroup._children.delete(this); + + // cleanup "sub chunks" + for (const chunkGroup of this._children) { + /** + * remove this chunk as "intermediary" and connect + * it "sub chunks" and parents directly + */ + // add parent to each "sub chunk" + chunkGroup.addParent(parentChunkGroup); + // add "sub chunk" to parent + parentChunkGroup.addChild(chunkGroup); + } + } + + /** + * we need to iterate again over the children + * to remove this from the child's parents. + * This can not be done in the above loop + * as it is not guaranteed that `this._parents` contains anything. + */ + for (const chunkGroup of this._children) { + // remove this as parent of every "sub chunk" + chunkGroup._parents.delete(this); + } + + // cleanup blocks + for (const block of this._blocks) { + block.chunkGroup = null; + } + + // remove chunks + for (const chunk of this.chunks) { + chunk.removeGroup(this); + } + } + + sortItems() { + this.origins.sort(sortOrigin); + this._parents.sort(); + this._children.sort(); + } + + /** + * Sorting predicate which allows current ChunkGroup to be compared against another. + * Sorting values are based off of number of chunks in ChunkGroup. + * + * @param {ChunkGroup} otherGroup the chunkGroup to compare this against + * @returns {-1|0|1} sort position for comparison + */ + compareTo(otherGroup) { + if (this.chunks.length > otherGroup.chunks.length) return -1; + if (this.chunks.length < otherGroup.chunks.length) return 1; + const a = this.chunks[Symbol.iterator](); + const b = otherGroup.chunks[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = a.next(); + const bItem = b.next(); + if (aItem.done) return 0; + const cmp = aItem.value.compareTo(bItem.value); + if (cmp !== 0) return cmp; + } + } + + getChildrenByOrders() { + const lists = new Map(); + for (const childGroup of this._children) { + // TODO webpack 5 remove this check for options + if (typeof childGroup.options === "object") { + for (const key of Object.keys(childGroup.options)) { + if (key.endsWith("Order")) { + const name = key.substr(0, key.length - "Order".length); + let list = lists.get(name); + if (list === undefined) { + lists.set(name, (list = [])); + } + list.push({ + order: childGroup.options[key], + group: childGroup + }); + } + } + } + } + const result = Object.create(null); + for (const [name, list] of lists) { + list.sort((a, b) => { + const cmp = b.order - a.order; + if (cmp !== 0) return cmp; + // TODO webpack 5 remove this check of compareTo + if (a.group.compareTo) { + return a.group.compareTo(b.group); + } + return 0; + }); + result[name] = list.map(i => i.group); + } + return result; + } + + /** + * Sets the top-down index of a module in this ChunkGroup + * @param {Module} module module for which the index should be set + * @param {number} index the index of the module + * @returns {void} + */ + setModuleIndex(module, index) { + this._moduleIndices.set(module, index); + } + + /** + * Gets the top-down index of a module in this ChunkGroup + * @param {Module} module the module + * @returns {number} index + */ + getModuleIndex(module) { + return this._moduleIndices.get(module); + } + + /** + * Sets the bottom-up index of a module in this ChunkGroup + * @param {Module} module module for which the index should be set + * @param {number} index the index of the module + * @returns {void} + */ + setModuleIndex2(module, index) { + this._moduleIndices2.set(module, index); + } + + /** + * Gets the bottom-up index of a module in this ChunkGroup + * @param {Module} module the module + * @returns {number} index + */ + getModuleIndex2(module) { + return this._moduleIndices2.get(module); + } + + checkConstraints() { + const chunk = this; + for (const child of chunk._children) { + if (!child._parents.has(chunk)) { + throw new Error( + `checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}` + ); + } + } + for (const parentChunk of chunk._parents) { + if (!parentChunk._children.has(chunk)) { + throw new Error( + `checkConstraints: parent missing child ${parentChunk.debugId} <- ${chunk.debugId}` + ); + } + } + } +} + +module.exports = ChunkGroup; diff --git a/node_modules/webpack/lib/ChunkRenderError.js b/node_modules/webpack/lib/ChunkRenderError.js new file mode 100644 index 0000000..0d0eb2c --- /dev/null +++ b/node_modules/webpack/lib/ChunkRenderError.js @@ -0,0 +1,32 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Chunk")} Chunk */ + +class ChunkRenderError extends WebpackError { + /** + * Create a new ChunkRenderError + * @param {Chunk} chunk A chunk + * @param {string} file Related file + * @param {Error} error Original error + */ + constructor(chunk, file, error) { + super(); + + this.name = "ChunkRenderError"; + this.error = error; + this.message = error.message; + this.details = error.stack; + this.file = file; + this.chunk = chunk; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ChunkRenderError; diff --git a/node_modules/webpack/lib/ChunkTemplate.js b/node_modules/webpack/lib/ChunkTemplate.js new file mode 100644 index 0000000..65861af --- /dev/null +++ b/node_modules/webpack/lib/ChunkTemplate.js @@ -0,0 +1,87 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable"); + +/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./Module")} Module} */ +/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate} */ +/** @typedef {import("./util/createHash").Hash} Hash} */ + +/** + * @typedef {Object} RenderManifestOptions + * @property {Chunk} chunk the chunk used to render + * @property {string} hash + * @property {string} fullHash + * @property {TODO} outputOptions + * @property {{javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates + * @property {Map<TODO, TODO>} dependencyTemplates + */ + +module.exports = class ChunkTemplate extends Tapable { + constructor(outputOptions) { + super(); + this.outputOptions = outputOptions || {}; + this.hooks = { + /** @type {SyncWaterfallHook<TODO[], RenderManifestOptions>} */ + renderManifest: new SyncWaterfallHook(["result", "options"]), + modules: new SyncWaterfallHook([ + "source", + "chunk", + "moduleTemplate", + "dependencyTemplates" + ]), + render: new SyncWaterfallHook([ + "source", + "chunk", + "moduleTemplate", + "dependencyTemplates" + ]), + renderWithEntry: new SyncWaterfallHook(["source", "chunk"]), + hash: new SyncHook(["hash"]), + hashForChunk: new SyncHook(["hash", "chunk"]) + }; + } + + /** + * + * @param {RenderManifestOptions} options render manifest options + * @returns {TODO[]} returns render manifest + */ + getRenderManifest(options) { + const result = []; + + this.hooks.renderManifest.call(result, options); + + return result; + } + + /** + * Updates hash with information from this template + * @param {Hash} hash the hash to update + * @returns {void} + */ + updateHash(hash) { + hash.update("ChunkTemplate"); + hash.update("2"); + this.hooks.hash.call(hash); + } + + /** + * TODO webpack 5: remove moduleTemplate and dependencyTemplates + * Updates hash with chunk-specific information from this template + * @param {Hash} hash the hash to update + * @param {Chunk} chunk the chunk + * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render + * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates + * @returns {void} + */ + updateHashForChunk(hash, chunk, moduleTemplate, dependencyTemplates) { + this.updateHash(hash); + this.hooks.hashForChunk.call(hash, chunk); + } +}; diff --git a/node_modules/webpack/lib/CommentCompilationWarning.js b/node_modules/webpack/lib/CommentCompilationWarning.js new file mode 100644 index 0000000..79f0a2a --- /dev/null +++ b/node_modules/webpack/lib/CommentCompilationWarning.js @@ -0,0 +1,32 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ + +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ + +class CommentCompilationWarning extends WebpackError { + /** + * + * @param {string} message warning message + * @param {Module} module affected module + * @param {DependencyLocation} loc affected lines of code + */ + constructor(message, module, loc) { + super(message); + + this.name = "CommentCompilationWarning"; + + this.module = module; + this.loc = loc; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = CommentCompilationWarning; diff --git a/node_modules/webpack/lib/CommonJsStuffPlugin.js b/node_modules/webpack/lib/CommonJsStuffPlugin.js new file mode 100644 index 0000000..80fee87 --- /dev/null +++ b/node_modules/webpack/lib/CommonJsStuffPlugin.js @@ -0,0 +1,116 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const ParserHelpers = require("./ParserHelpers"); + +class CommonJsStuffPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "CommonJsStuffPlugin", + (compilation, { normalModuleFactory }) => { + const handler = (parser, parserOptions) => { + parser.hooks.expression + .for("require.main.require") + .tap( + "CommonJsStuffPlugin", + ParserHelpers.expressionIsUnsupported( + parser, + "require.main.require is not supported by webpack." + ) + ); + parser.hooks.expression + .for("module.parent.require") + .tap( + "CommonJsStuffPlugin", + ParserHelpers.expressionIsUnsupported( + parser, + "module.parent.require is not supported by webpack." + ) + ); + parser.hooks.expression + .for("require.main") + .tap( + "CommonJsStuffPlugin", + ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + "__webpack_require__.c[__webpack_require__.s]" + ) + ); + parser.hooks.expression + .for("module.loaded") + .tap("CommonJsStuffPlugin", expr => { + parser.state.module.buildMeta.moduleConcatenationBailout = + "module.loaded"; + return ParserHelpers.toConstantDependency( + parser, + "module.l" + )(expr); + }); + parser.hooks.expression + .for("module.id") + .tap("CommonJsStuffPlugin", expr => { + parser.state.module.buildMeta.moduleConcatenationBailout = + "module.id"; + return ParserHelpers.toConstantDependency( + parser, + "module.i" + )(expr); + }); + parser.hooks.expression + .for("module.exports") + .tap("CommonJsStuffPlugin", () => { + const module = parser.state.module; + const isHarmony = + module.buildMeta && module.buildMeta.exportsType; + if (!isHarmony) return true; + }); + parser.hooks.evaluateIdentifier + .for("module.hot") + .tap( + "CommonJsStuffPlugin", + ParserHelpers.evaluateToIdentifier("module.hot", false) + ); + parser.hooks.expression + .for("module") + .tap("CommonJsStuffPlugin", () => { + const module = parser.state.module; + const isHarmony = + module.buildMeta && module.buildMeta.exportsType; + let moduleJsPath = path.join( + __dirname, + "..", + "buildin", + isHarmony ? "harmony-module.js" : "module.js" + ); + if (module.context) { + moduleJsPath = path.relative( + parser.state.module.context, + moduleJsPath + ); + if (!/^[A-Z]:/i.test(moduleJsPath)) { + moduleJsPath = `./${moduleJsPath.replace(/\\/g, "/")}`; + } + } + return ParserHelpers.addParsedVariableToModule( + parser, + "module", + `require(${JSON.stringify(moduleJsPath)})(module)` + ); + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("CommonJsStuffPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("CommonJsStuffPlugin", handler); + } + ); + } +} +module.exports = CommonJsStuffPlugin; diff --git a/node_modules/webpack/lib/CompatibilityPlugin.js b/node_modules/webpack/lib/CompatibilityPlugin.js new file mode 100644 index 0000000..1544d6c --- /dev/null +++ b/node_modules/webpack/lib/CompatibilityPlugin.js @@ -0,0 +1,70 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ConstDependency = require("./dependencies/ConstDependency"); + +const NullFactory = require("./NullFactory"); + +/** @typedef {import("./Compiler")} Compiler */ + +class CompatibilityPlugin { + /** + * Apply the plugin + * @param {Compiler} compiler Webpack Compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "CompatibilityPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("CompatibilityPlugin", (parser, parserOptions) => { + if ( + parserOptions.browserify !== undefined && + !parserOptions.browserify + ) + return; + + parser.hooks.call + .for("require") + .tap("CompatibilityPlugin", expr => { + // support for browserify style require delegator: "require(o, !0)" + if (expr.arguments.length !== 2) return; + const second = parser.evaluateExpression(expr.arguments[1]); + if (!second.isBoolean()) return; + if (second.asBool() !== true) return; + const dep = new ConstDependency("require", expr.callee.range); + dep.loc = expr.loc; + if (parser.state.current.dependencies.length > 1) { + const last = + parser.state.current.dependencies[ + parser.state.current.dependencies.length - 1 + ]; + if ( + last.critical && + last.options && + last.options.request === "." && + last.userRequest === "." && + last.options.recursive + ) + parser.state.current.dependencies.pop(); + } + parser.state.current.addDependency(dep); + return true; + }); + }); + } + ); + } +} +module.exports = CompatibilityPlugin; diff --git a/node_modules/webpack/lib/Compilation.js b/node_modules/webpack/lib/Compilation.js new file mode 100644 index 0000000..6329174 --- /dev/null +++ b/node_modules/webpack/lib/Compilation.js @@ -0,0 +1,2327 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const asyncLib = require("neo-async"); +const util = require("util"); +const { CachedSource } = require("webpack-sources"); +const { + Tapable, + SyncHook, + SyncBailHook, + SyncWaterfallHook, + AsyncSeriesHook +} = require("tapable"); +const EntryModuleNotFoundError = require("./EntryModuleNotFoundError"); +const ModuleNotFoundError = require("./ModuleNotFoundError"); +const ModuleDependencyWarning = require("./ModuleDependencyWarning"); +const ModuleDependencyError = require("./ModuleDependencyError"); +const ChunkGroup = require("./ChunkGroup"); +const Chunk = require("./Chunk"); +const Entrypoint = require("./Entrypoint"); +const MainTemplate = require("./MainTemplate"); +const ChunkTemplate = require("./ChunkTemplate"); +const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate"); +const ModuleTemplate = require("./ModuleTemplate"); +const RuntimeTemplate = require("./RuntimeTemplate"); +const ChunkRenderError = require("./ChunkRenderError"); +const Stats = require("./Stats"); +const Semaphore = require("./util/Semaphore"); +const createHash = require("./util/createHash"); +const SortableSet = require("./util/SortableSet"); +const GraphHelpers = require("./GraphHelpers"); +const ModuleDependency = require("./dependencies/ModuleDependency"); +const compareLocations = require("./compareLocations"); +const { Logger, LogType } = require("./logging/Logger"); +const ErrorHelpers = require("./ErrorHelpers"); +const buildChunkGraph = require("./buildChunkGraph"); +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */ +/** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */ +/** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */ +/** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */ +/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */ +/** @typedef {import("./DependenciesBlock")} DependenciesBlock */ +/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ +/** @typedef {import("./Dependency")} Dependency */ +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ +/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */ +/** @typedef {import("./util/createHash").Hash} Hash */ + +// TODO use @callback +/** @typedef {{[assetName: string]: Source}} CompilationAssets */ +/** @typedef {(err: Error|null, result?: Module) => void } ModuleCallback */ +/** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */ +/** @typedef {(module: Module) => void} OnModuleCallback */ +/** @typedef {(err?: Error|null) => void} Callback */ +/** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */ +/** @typedef {new (...args: any[]) => Dependency} DepConstructor */ +/** @typedef {{apply: () => void}} Plugin */ + +/** + * @typedef {Object} ModuleFactoryCreateDataContextInfo + * @property {string} issuer + * @property {string} compiler + */ + +/** + * @typedef {Object} ModuleFactoryCreateData + * @property {ModuleFactoryCreateDataContextInfo} contextInfo + * @property {any=} resolveOptions + * @property {string} context + * @property {Dependency[]} dependencies + */ + +/** + * @typedef {Object} ModuleFactory + * @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create + */ + +/** + * @typedef {Object} SortedDependency + * @property {ModuleFactory} factory + * @property {Dependency[]} dependencies + */ + +/** + * @typedef {Object} DependenciesBlockLike + * @property {Dependency[]} dependencies + * @property {AsyncDependenciesBlock[]} blocks + * @property {DependenciesBlockVariable[]} variables + */ + +/** + * @typedef {Object} LogEntry + * @property {string} type + * @property {any[]} args + * @property {number} time + * @property {string[]=} trace + */ + +/** + * @typedef {Object} AssetInfo + * @property {boolean=} immutable true, if the asset can be long term cached forever (contains a hash) + * @property {number=} size size in bytes, only set after asset has been emitted + * @property {boolean=} development true, when asset is only used for development and doesn't count towards user-facing assets + * @property {boolean=} hotModuleReplacement true, when asset ships data for updating an existing application (HMR) + */ + +/** + * @typedef {Object} Asset + * @property {string} name the filename of the asset + * @property {Source} source source of the asset + * @property {AssetInfo} info info about the asset + */ + +/** + * @param {Chunk} a first chunk to sort by id + * @param {Chunk} b second chunk to sort by id + * @returns {-1|0|1} sort value + */ +const byId = (a, b) => { + if (typeof a.id !== typeof b.id) { + return typeof a.id < typeof b.id ? -1 : 1; + } + if (a.id < b.id) return -1; + if (a.id > b.id) return 1; + return 0; +}; + +/** + * @param {Module} a first module to sort by + * @param {Module} b second module to sort by + * @returns {-1|0|1} sort value + */ +const byIdOrIdentifier = (a, b) => { + if (typeof a.id !== typeof b.id) { + return typeof a.id < typeof b.id ? -1 : 1; + } + if (a.id < b.id) return -1; + if (a.id > b.id) return 1; + const identA = a.identifier(); + const identB = b.identifier(); + if (identA < identB) return -1; + if (identA > identB) return 1; + return 0; +}; + +/** + * @param {Module} a first module to sort by + * @param {Module} b second module to sort by + * @returns {-1|0|1} sort value + */ +const byIndexOrIdentifier = (a, b) => { + if (a.index < b.index) return -1; + if (a.index > b.index) return 1; + const identA = a.identifier(); + const identB = b.identifier(); + if (identA < identB) return -1; + if (identA > identB) return 1; + return 0; +}; + +/** + * @param {Compilation} a first compilation to sort by + * @param {Compilation} b second compilation to sort by + * @returns {-1|0|1} sort value + */ +const byNameOrHash = (a, b) => { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + if (a.fullHash < b.fullHash) return -1; + if (a.fullHash > b.fullHash) return 1; + return 0; +}; + +/** + * @param {DependenciesBlockVariable[]} variables DepBlock Variables to iterate over + * @param {DepBlockVarDependenciesCallback} fn callback to apply on iterated elements + * @returns {void} + */ +const iterationBlockVariable = (variables, fn) => { + for ( + let indexVariable = 0; + indexVariable < variables.length; + indexVariable++ + ) { + const varDep = variables[indexVariable].dependencies; + for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) { + fn(varDep[indexVDep]); + } + } +}; + +/** + * @template T + * @param {T[]} arr array of elements to iterate over + * @param {function(T): void} fn callback applied to each element + * @returns {void} + */ +const iterationOfArrayCallback = (arr, fn) => { + for (let index = 0; index < arr.length; index++) { + fn(arr[index]); + } +}; + +/** + * @template T + * @param {Set<T>} set set to add items to + * @param {Set<T>} otherSet set to add items from + * @returns {void} + */ +const addAllToSet = (set, otherSet) => { + for (const item of otherSet) { + set.add(item); + } +}; + +/** + * @param {Source} a a source + * @param {Source} b another source + * @returns {boolean} true, when both sources are equal + */ +const isSourceEqual = (a, b) => { + if (a === b) return true; + // TODO webpack 5: check .buffer() instead, it's called anyway during emit + /** @type {Buffer|string} */ + let aSource = a.source(); + /** @type {Buffer|string} */ + let bSource = b.source(); + if (aSource === bSource) return true; + if (typeof aSource === "string" && typeof bSource === "string") return false; + if (!Buffer.isBuffer(aSource)) aSource = Buffer.from(aSource, "utf-8"); + if (!Buffer.isBuffer(bSource)) bSource = Buffer.from(bSource, "utf-8"); + return aSource.equals(bSource); +}; + +class Compilation extends Tapable { + /** + * Creates an instance of Compilation. + * @param {Compiler} compiler the compiler which created the compilation + */ + constructor(compiler) { + super(); + this.hooks = { + /** @type {SyncHook<Module>} */ + buildModule: new SyncHook(["module"]), + /** @type {SyncHook<Module>} */ + rebuildModule: new SyncHook(["module"]), + /** @type {SyncHook<Module, Error>} */ + failedModule: new SyncHook(["module", "error"]), + /** @type {SyncHook<Module>} */ + succeedModule: new SyncHook(["module"]), + + /** @type {SyncHook<Dependency, string>} */ + addEntry: new SyncHook(["entry", "name"]), + /** @type {SyncHook<Dependency, string, Error>} */ + failedEntry: new SyncHook(["entry", "name", "error"]), + /** @type {SyncHook<Dependency, string, Module>} */ + succeedEntry: new SyncHook(["entry", "name", "module"]), + + /** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */ + dependencyReference: new SyncWaterfallHook([ + "dependencyReference", + "dependency", + "module" + ]), + + /** @type {AsyncSeriesHook<Module[]>} */ + finishModules: new AsyncSeriesHook(["modules"]), + /** @type {SyncHook<Module>} */ + finishRebuildingModule: new SyncHook(["module"]), + /** @type {SyncHook} */ + unseal: new SyncHook([]), + /** @type {SyncHook} */ + seal: new SyncHook([]), + + /** @type {SyncHook} */ + beforeChunks: new SyncHook([]), + /** @type {SyncHook<Chunk[]>} */ + afterChunks: new SyncHook(["chunks"]), + + /** @type {SyncBailHook<Module[]>} */ + optimizeDependenciesBasic: new SyncBailHook(["modules"]), + /** @type {SyncBailHook<Module[]>} */ + optimizeDependencies: new SyncBailHook(["modules"]), + /** @type {SyncBailHook<Module[]>} */ + optimizeDependenciesAdvanced: new SyncBailHook(["modules"]), + /** @type {SyncBailHook<Module[]>} */ + afterOptimizeDependencies: new SyncHook(["modules"]), + + /** @type {SyncHook} */ + optimize: new SyncHook([]), + /** @type {SyncBailHook<Module[]>} */ + optimizeModulesBasic: new SyncBailHook(["modules"]), + /** @type {SyncBailHook<Module[]>} */ + optimizeModules: new SyncBailHook(["modules"]), + /** @type {SyncBailHook<Module[]>} */ + optimizeModulesAdvanced: new SyncBailHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + afterOptimizeModules: new SyncHook(["modules"]), + + /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */ + optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]), + /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */ + optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]), + /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */ + optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]), + /** @type {SyncHook<Chunk[], ChunkGroup[]>} */ + afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]), + + /** @type {AsyncSeriesHook<Chunk[], Module[]>} */ + optimizeTree: new AsyncSeriesHook(["chunks", "modules"]), + /** @type {SyncHook<Chunk[], Module[]>} */ + afterOptimizeTree: new SyncHook(["chunks", "modules"]), + + /** @type {SyncBailHook<Chunk[], Module[]>} */ + optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]), + /** @type {SyncBailHook<Chunk[], Module[]>} */ + optimizeChunkModules: new SyncBailHook(["chunks", "modules"]), + /** @type {SyncBailHook<Chunk[], Module[]>} */ + optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]), + /** @type {SyncHook<Chunk[], Module[]>} */ + afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]), + /** @type {SyncBailHook} */ + shouldRecord: new SyncBailHook([]), + + /** @type {SyncHook<Module[], any>} */ + reviveModules: new SyncHook(["modules", "records"]), + /** @type {SyncHook<Module[]>} */ + optimizeModuleOrder: new SyncHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + advancedOptimizeModuleOrder: new SyncHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + beforeModuleIds: new SyncHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + moduleIds: new SyncHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + optimizeModuleIds: new SyncHook(["modules"]), + /** @type {SyncHook<Module[]>} */ + afterOptimizeModuleIds: new SyncHook(["modules"]), + + /** @type {SyncHook<Chunk[], any>} */ + reviveChunks: new SyncHook(["chunks", "records"]), + /** @type {SyncHook<Chunk[]>} */ + optimizeChunkOrder: new SyncHook(["chunks"]), + /** @type {SyncHook<Chunk[]>} */ + beforeChunkIds: new SyncHook(["chunks"]), + /** @type {SyncHook<Chunk[]>} */ + optimizeChunkIds: new SyncHook(["chunks"]), + /** @type {SyncHook<Chunk[]>} */ + afterOptimizeChunkIds: new SyncHook(["chunks"]), + + /** @type {SyncHook<Module[], any>} */ + recordModules: new SyncHook(["modules", "records"]), + /** @type {SyncHook<Chunk[], any>} */ + recordChunks: new SyncHook(["chunks", "records"]), + + /** @type {SyncHook} */ + beforeHash: new SyncHook([]), + /** @type {SyncHook<Chunk>} */ + contentHash: new SyncHook(["chunk"]), + /** @type {SyncHook} */ + afterHash: new SyncHook([]), + /** @type {SyncHook<any>} */ + recordHash: new SyncHook(["records"]), + /** @type {SyncHook<Compilation, any>} */ + record: new SyncHook(["compilation", "records"]), + + /** @type {SyncHook} */ + beforeModuleAssets: new SyncHook([]), + /** @type {SyncBailHook} */ + shouldGenerateChunkAssets: new SyncBailHook([]), + /** @type {SyncHook} */ + beforeChunkAssets: new SyncHook([]), + /** @type {SyncHook<Chunk[]>} */ + additionalChunkAssets: new SyncHook(["chunks"]), + + /** @type {AsyncSeriesHook} */ + additionalAssets: new AsyncSeriesHook([]), + /** @type {AsyncSeriesHook<Chunk[]>} */ + optimizeChunkAssets: new AsyncSeriesHook(["chunks"]), + /** @type {SyncHook<Chunk[]>} */ + afterOptimizeChunkAssets: new SyncHook(["chunks"]), + /** @type {AsyncSeriesHook<CompilationAssets>} */ + optimizeAssets: new AsyncSeriesHook(["assets"]), + /** @type {SyncHook<CompilationAssets>} */ + afterOptimizeAssets: new SyncHook(["assets"]), + + /** @type {SyncBailHook} */ + needAdditionalSeal: new SyncBailHook([]), + /** @type {AsyncSeriesHook} */ + afterSeal: new AsyncSeriesHook([]), + + /** @type {SyncHook<Chunk, Hash>} */ + chunkHash: new SyncHook(["chunk", "chunkHash"]), + /** @type {SyncHook<Module, string>} */ + moduleAsset: new SyncHook(["module", "filename"]), + /** @type {SyncHook<Chunk, string>} */ + chunkAsset: new SyncHook(["chunk", "filename"]), + + /** @type {SyncWaterfallHook<string, TODO>} */ + assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate + + /** @type {SyncBailHook} */ + needAdditionalPass: new SyncBailHook([]), + + /** @type {SyncHook<Compiler, string, number>} */ + childCompiler: new SyncHook([ + "childCompiler", + "compilerName", + "compilerIndex" + ]), + + /** @type {SyncBailHook<string, LogEntry>} */ + log: new SyncBailHook(["origin", "logEntry"]), + + // TODO the following hooks are weirdly located here + // TODO move them for webpack 5 + /** @type {SyncHook<object, Module>} */ + normalModuleLoader: new SyncHook(["loaderContext", "module"]), + + /** @type {SyncBailHook<Chunk[]>} */ + optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]), + /** @type {SyncBailHook<Chunk[]>} */ + optimizeExtractedChunks: new SyncBailHook(["chunks"]), + /** @type {SyncBailHook<Chunk[]>} */ + optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]), + /** @type {SyncHook<Chunk[]>} */ + afterOptimizeExtractedChunks: new SyncHook(["chunks"]) + }; + this._pluginCompat.tap("Compilation", options => { + switch (options.name) { + case "optimize-tree": + case "additional-assets": + case "optimize-chunk-assets": + case "optimize-assets": + case "after-seal": + options.async = true; + break; + } + }); + /** @type {string=} */ + this.name = undefined; + /** @type {Compiler} */ + this.compiler = compiler; + this.resolverFactory = compiler.resolverFactory; + this.inputFileSystem = compiler.inputFileSystem; + this.requestShortener = compiler.requestShortener; + + const options = compiler.options; + this.options = options; + this.outputOptions = options && options.output; + /** @type {boolean=} */ + this.bail = options && options.bail; + this.profile = options && options.profile; + this.performance = options && options.performance; + + this.mainTemplate = new MainTemplate(this.outputOptions); + this.chunkTemplate = new ChunkTemplate(this.outputOptions); + this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate( + this.outputOptions + ); + this.runtimeTemplate = new RuntimeTemplate( + this.outputOptions, + this.requestShortener + ); + this.moduleTemplates = { + javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"), + webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly") + }; + + this.semaphore = new Semaphore(options.parallelism || 100); + + this.entries = []; + /** @private @type {{name: string, request: string, module: Module}[]} */ + this._preparedEntrypoints = []; + /** @type {Map<string, Entrypoint>} */ + this.entrypoints = new Map(); + /** @type {Chunk[]} */ + this.chunks = []; + /** @type {ChunkGroup[]} */ + this.chunkGroups = []; + /** @type {Map<string, ChunkGroup>} */ + this.namedChunkGroups = new Map(); + /** @type {Map<string, Chunk>} */ + this.namedChunks = new Map(); + /** @type {Module[]} */ + this.modules = []; + /** @private @type {Map<string, Module>} */ + this._modules = new Map(); + this.cache = null; + this.records = null; + /** @type {string[]} */ + this.additionalChunkAssets = []; + /** @type {CompilationAssets} */ + this.assets = {}; + /** @type {Map<string, AssetInfo>} */ + this.assetsInfo = new Map(); + /** @type {WebpackError[]} */ + this.errors = []; + /** @type {WebpackError[]} */ + this.warnings = []; + /** @type {Compilation[]} */ + this.children = []; + /** @type {Map<string, LogEntry[]>} */ + this.logging = new Map(); + /** @type {Map<DepConstructor, ModuleFactory>} */ + this.dependencyFactories = new Map(); + /** @type {Map<DepConstructor, DependencyTemplate>} */ + this.dependencyTemplates = new Map(); + // TODO refactor this in webpack 5 to a custom DependencyTemplates class with a hash property + // @ts-ignore + this.dependencyTemplates.set("hash", ""); + this.childrenCounters = {}; + /** @type {Set<number|string>} */ + this.usedChunkIds = null; + /** @type {Set<number>} */ + this.usedModuleIds = null; + /** @type {Map<string, number>=} */ + this.fileTimestamps = undefined; + /** @type {Map<string, number>=} */ + this.contextTimestamps = undefined; + /** @type {Set<string>=} */ + this.compilationDependencies = undefined; + /** @private @type {Map<Module, Callback[]>} */ + this._buildingModules = new Map(); + /** @private @type {Map<Module, Callback[]>} */ + this._rebuildingModules = new Map(); + /** @type {Set<string>} */ + this.emittedAssets = new Set(); + } + + getStats() { + return new Stats(this); + } + + /** + * @param {string | (function(): string)} name name of the logger, or function called once to get the logger name + * @returns {Logger} a logger with that name + */ + getLogger(name) { + if (!name) { + throw new TypeError("Compilation.getLogger(name) called without a name"); + } + /** @type {LogEntry[] | undefined} */ + let logEntries; + return new Logger((type, args) => { + if (typeof name === "function") { + name = name(); + if (!name) { + throw new TypeError( + "Compilation.getLogger(name) called with a function not returning a name" + ); + } + } + let trace; + switch (type) { + case LogType.warn: + case LogType.error: + case LogType.trace: + trace = ErrorHelpers.cutOffLoaderExecution(new Error("Trace").stack) + .split("\n") + .slice(3); + break; + } + /** @type {LogEntry} */ + const logEntry = { + time: Date.now(), + type, + args, + trace + }; + if (this.hooks.log.call(name, logEntry) === undefined) { + if (logEntry.type === LogType.profileEnd) { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.profileEnd === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.profileEnd(`[${name}] ${logEntry.args[0]}`); + } + } + if (logEntries === undefined) { + logEntries = this.logging.get(name); + if (logEntries === undefined) { + logEntries = []; + this.logging.set(name, logEntries); + } + } + logEntries.push(logEntry); + if (logEntry.type === LogType.profile) { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.profile === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.profile(`[${name}] ${logEntry.args[0]}`); + } + } + } + }); + } + + /** + * @typedef {Object} AddModuleResult + * @property {Module} module the added or existing module + * @property {boolean} issuer was this the first request for this module + * @property {boolean} build should the module be build + * @property {boolean} dependencies should dependencies be walked + */ + + /** + * @param {Module} module module to be added that was created + * @param {any=} cacheGroup cacheGroup it is apart of + * @returns {AddModuleResult} returns meta about whether or not the module had built + * had an issuer, or any dependnecies + */ + addModule(module, cacheGroup) { + const identifier = module.identifier(); + const alreadyAddedModule = this._modules.get(identifier); + if (alreadyAddedModule) { + return { + module: alreadyAddedModule, + issuer: false, + build: false, + dependencies: false + }; + } + const cacheName = (cacheGroup || "m") + identifier; + if (this.cache && this.cache[cacheName]) { + const cacheModule = this.cache[cacheName]; + + if (typeof cacheModule.updateCacheModule === "function") { + cacheModule.updateCacheModule(module); + } + + let rebuild = true; + if (this.fileTimestamps && this.contextTimestamps) { + rebuild = cacheModule.needRebuild( + this.fileTimestamps, + this.contextTimestamps + ); + } + + if (!rebuild) { + cacheModule.disconnect(); + this._modules.set(identifier, cacheModule); + this.modules.push(cacheModule); + for (const err of cacheModule.errors) { + this.errors.push(err); + } + for (const err of cacheModule.warnings) { + this.warnings.push(err); + } + return { + module: cacheModule, + issuer: true, + build: false, + dependencies: true + }; + } + cacheModule.unbuild(); + module = cacheModule; + } + this._modules.set(identifier, module); + if (this.cache) { + this.cache[cacheName] = module; + } + this.modules.push(module); + return { + module: module, + issuer: true, + build: true, + dependencies: true + }; + } + + /** + * Fetches a module from a compilation by its identifier + * @param {Module} module the module provided + * @returns {Module} the module requested + */ + getModule(module) { + const identifier = module.identifier(); + return this._modules.get(identifier); + } + + /** + * Attempts to search for a module by its identifier + * @param {string} identifier identifier (usually path) for module + * @returns {Module|undefined} attempt to search for module and return it, else undefined + */ + findModule(identifier) { + return this._modules.get(identifier); + } + + /** + * @param {Module} module module with its callback list + * @param {Callback} callback the callback function + * @returns {void} + */ + waitForBuildingFinished(module, callback) { + let callbackList = this._buildingModules.get(module); + if (callbackList) { + callbackList.push(() => callback()); + } else { + process.nextTick(callback); + } + } + + /** + * Builds the module object + * + * @param {Module} module module to be built + * @param {boolean} optional optional flag + * @param {Module=} origin origin module this module build was requested from + * @param {Dependency[]=} dependencies optional dependencies from the module to be built + * @param {TODO} thisCallback the callback + * @returns {TODO} returns the callback function with results + */ + buildModule(module, optional, origin, dependencies, thisCallback) { + let callbackList = this._buildingModules.get(module); + if (callbackList) { + callbackList.push(thisCallback); + return; + } + this._buildingModules.set(module, (callbackList = [thisCallback])); + + const callback = err => { + this._buildingModules.delete(module); + for (const cb of callbackList) { + cb(err); + } + }; + + this.hooks.buildModule.call(module); + module.build( + this.options, + this, + this.resolverFactory.get("normal", module.resolveOptions), + this.inputFileSystem, + error => { + const errors = module.errors; + for (let indexError = 0; indexError < errors.length; indexError++) { + const err = errors[indexError]; + err.origin = origin; + err.dependencies = dependencies; + if (optional) { + this.warnings.push(err); + } else { + this.errors.push(err); + } + } + + const warnings = module.warnings; + for ( + let indexWarning = 0; + indexWarning < warnings.length; + indexWarning++ + ) { + const war = warnings[indexWarning]; + war.origin = origin; + war.dependencies = dependencies; + this.warnings.push(war); + } + const originalMap = module.dependencies.reduce((map, v, i) => { + map.set(v, i); + return map; + }, new Map()); + module.dependencies.sort((a, b) => { + const cmp = compareLocations(a.loc, b.loc); + if (cmp) return cmp; + return originalMap.get(a) - originalMap.get(b); + }); + if (error) { + this.hooks.failedModule.call(module, error); + return callback(error); + } + this.hooks.succeedModule.call(module); + return callback(); + } + ); + } + + /** + * @param {Module} module to be processed for deps + * @param {ModuleCallback} callback callback to be triggered + * @returns {void} + */ + processModuleDependencies(module, callback) { + const dependencies = new Map(); + + const addDependency = dep => { + const resourceIdent = dep.getResourceIdentifier(); + if (resourceIdent) { + const factory = this.dependencyFactories.get(dep.constructor); + if (factory === undefined) { + throw new Error( + `No module factory available for dependency type: ${dep.constructor.name}` + ); + } + let innerMap = dependencies.get(factory); + if (innerMap === undefined) { + dependencies.set(factory, (innerMap = new Map())); + } + let list = innerMap.get(resourceIdent); + if (list === undefined) innerMap.set(resourceIdent, (list = [])); + list.push(dep); + } + }; + + const addDependenciesBlock = block => { + if (block.dependencies) { + iterationOfArrayCallback(block.dependencies, addDependency); + } + if (block.blocks) { + iterationOfArrayCallback(block.blocks, addDependenciesBlock); + } + if (block.variables) { + iterationBlockVariable(block.variables, addDependency); + } + }; + + try { + addDependenciesBlock(module); + } catch (e) { + callback(e); + } + + const sortedDependencies = []; + + for (const pair1 of dependencies) { + for (const pair2 of pair1[1]) { + sortedDependencies.push({ + factory: pair1[0], + dependencies: pair2[1] + }); + } + } + + this.addModuleDependencies( + module, + sortedDependencies, + this.bail, + null, + true, + callback + ); + } + + /** + * @param {Module} module module to add deps to + * @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through + * @param {(boolean|null)=} bail whether to bail or not + * @param {TODO} cacheGroup optional cacheGroup + * @param {boolean} recursive whether it is recursive traversal + * @param {function} callback callback for when dependencies are finished being added + * @returns {void} + */ + addModuleDependencies( + module, + dependencies, + bail, + cacheGroup, + recursive, + callback + ) { + const start = this.profile && Date.now(); + const currentProfile = this.profile && {}; + + asyncLib.forEach( + dependencies, + (item, callback) => { + const dependencies = item.dependencies; + + const errorAndCallback = err => { + err.origin = module; + err.dependencies = dependencies; + this.errors.push(err); + if (bail) { + callback(err); + } else { + callback(); + } + }; + const warningAndCallback = err => { + err.origin = module; + this.warnings.push(err); + callback(); + }; + + const semaphore = this.semaphore; + semaphore.acquire(() => { + const factory = item.factory; + factory.create( + { + contextInfo: { + issuer: module.nameForCondition && module.nameForCondition(), + compiler: this.compiler.name + }, + resolveOptions: module.resolveOptions, + context: module.context, + dependencies: dependencies + }, + (err, dependentModule) => { + let afterFactory; + + const isOptional = () => { + return dependencies.every(d => d.optional); + }; + + const errorOrWarningAndCallback = err => { + if (isOptional()) { + return warningAndCallback(err); + } else { + return errorAndCallback(err); + } + }; + + if (err) { + semaphore.release(); + return errorOrWarningAndCallback( + new ModuleNotFoundError(module, err) + ); + } + if (!dependentModule) { + semaphore.release(); + return process.nextTick(callback); + } + if (currentProfile) { + afterFactory = Date.now(); + currentProfile.factory = afterFactory - start; + } + + const iterationDependencies = depend => { + for (let index = 0; index < depend.length; index++) { + const dep = depend[index]; + dep.module = dependentModule; + dependentModule.addReason(module, dep); + } + }; + + const addModuleResult = this.addModule( + dependentModule, + cacheGroup + ); + dependentModule = addModuleResult.module; + iterationDependencies(dependencies); + + const afterBuild = () => { + if (recursive && addModuleResult.dependencies) { + this.processModuleDependencies(dependentModule, callback); + } else { + return callback(); + } + }; + + if (addModuleResult.issuer) { + if (currentProfile) { + dependentModule.profile = currentProfile; + } + + dependentModule.issuer = module; + } else { + if (this.profile) { + if (module.profile) { + const time = Date.now() - start; + if ( + !module.profile.dependencies || + time > module.profile.dependencies + ) { + module.profile.dependencies = time; + } + } + } + } + + if (addModuleResult.build) { + this.buildModule( + dependentModule, + isOptional(), + module, + dependencies, + err => { + if (err) { + semaphore.release(); + return errorOrWarningAndCallback(err); + } + + if (currentProfile) { + const afterBuilding = Date.now(); + currentProfile.building = afterBuilding - afterFactory; + } + + semaphore.release(); + afterBuild(); + } + ); + } else { + semaphore.release(); + this.waitForBuildingFinished(dependentModule, afterBuild); + } + } + ); + }); + }, + err => { + // In V8, the Error objects keep a reference to the functions on the stack. These warnings & + // errors are created inside closures that keep a reference to the Compilation, so errors are + // leaking the Compilation object. + + if (err) { + // eslint-disable-next-line no-self-assign + err.stack = err.stack; + return callback(err); + } + + return process.nextTick(callback); + } + ); + } + + /** + * + * @param {string} context context string path + * @param {Dependency} dependency dependency used to create Module chain + * @param {OnModuleCallback} onModule function invoked on modules creation + * @param {ModuleChainCallback} callback callback for when module chain is complete + * @returns {void} will throw if dependency instance is not a valid Dependency + */ + _addModuleChain(context, dependency, onModule, callback) { + const start = this.profile && Date.now(); + const currentProfile = this.profile && {}; + + const errorAndCallback = this.bail + ? err => { + callback(err); + } + : err => { + err.dependencies = [dependency]; + this.errors.push(err); + callback(); + }; + + if ( + typeof dependency !== "object" || + dependency === null || + !dependency.constructor + ) { + throw new Error("Parameter 'dependency' must be a Dependency"); + } + const Dep = /** @type {DepConstructor} */ (dependency.constructor); + const moduleFactory = this.dependencyFactories.get(Dep); + if (!moduleFactory) { + throw new Error( + `No dependency factory available for this dependency type: ${dependency.constructor.name}` + ); + } + + this.semaphore.acquire(() => { + moduleFactory.create( + { + contextInfo: { + issuer: "", + compiler: this.compiler.name + }, + context: context, + dependencies: [dependency] + }, + (err, module) => { + if (err) { + this.semaphore.release(); + return errorAndCallback(new EntryModuleNotFoundError(err)); + } + + let afterFactory; + + if (currentProfile) { + afterFactory = Date.now(); + currentProfile.factory = afterFactory - start; + } + + const addModuleResult = this.addModule(module); + module = addModuleResult.module; + + onModule(module); + + dependency.module = module; + module.addReason(null, dependency); + + const afterBuild = () => { + if (addModuleResult.dependencies) { + this.processModuleDependencies(module, err => { + if (err) return callback(err); + callback(null, module); + }); + } else { + return callback(null, module); + } + }; + + if (addModuleResult.issuer) { + if (currentProfile) { + module.profile = currentProfile; + } + } + + if (addModuleResult.build) { + this.buildModule(module, false, null, null, err => { + if (err) { + this.semaphore.release(); + return errorAndCallback(err); + } + + if (currentProfile) { + const afterBuilding = Date.now(); + currentProfile.building = afterBuilding - afterFactory; + } + + this.semaphore.release(); + afterBuild(); + }); + } else { + this.semaphore.release(); + this.waitForBuildingFinished(module, afterBuild); + } + } + ); + }); + } + + /** + * + * @param {string} context context path for entry + * @param {Dependency} entry entry dependency being created + * @param {string} name name of entry + * @param {ModuleCallback} callback callback function + * @returns {void} returns + */ + addEntry(context, entry, name, callback) { + this.hooks.addEntry.call(entry, name); + + const slot = { + name: name, + // TODO webpack 5 remove `request` + request: null, + module: null + }; + + if (entry instanceof ModuleDependency) { + slot.request = entry.request; + } + + // TODO webpack 5: merge modules instead when multiple entry modules are supported + const idx = this._preparedEntrypoints.findIndex(slot => slot.name === name); + if (idx >= 0) { + // Overwrite existing entrypoint + this._preparedEntrypoints[idx] = slot; + } else { + this._preparedEntrypoints.push(slot); + } + this._addModuleChain( + context, + entry, + module => { + this.entries.push(module); + }, + (err, module) => { + if (err) { + this.hooks.failedEntry.call(entry, name, err); + return callback(err); + } + + if (module) { + slot.module = module; + } else { + const idx = this._preparedEntrypoints.indexOf(slot); + if (idx >= 0) { + this._preparedEntrypoints.splice(idx, 1); + } + } + this.hooks.succeedEntry.call(entry, name, module); + return callback(null, module); + } + ); + } + + /** + * @param {string} context context path string + * @param {Dependency} dependency dep used to create module + * @param {ModuleCallback} callback module callback sending module up a level + * @returns {void} + */ + prefetch(context, dependency, callback) { + this._addModuleChain( + context, + dependency, + module => { + module.prefetched = true; + }, + callback + ); + } + + /** + * @param {Module} module module to be rebuilt + * @param {Callback} thisCallback callback when module finishes rebuilding + * @returns {void} + */ + rebuildModule(module, thisCallback) { + let callbackList = this._rebuildingModules.get(module); + if (callbackList) { + callbackList.push(thisCallback); + return; + } + this._rebuildingModules.set(module, (callbackList = [thisCallback])); + + const callback = err => { + this._rebuildingModules.delete(module); + for (const cb of callbackList) { + cb(err); + } + }; + + this.hooks.rebuildModule.call(module); + const oldDependencies = module.dependencies.slice(); + const oldVariables = module.variables.slice(); + const oldBlocks = module.blocks.slice(); + module.unbuild(); + this.buildModule(module, false, module, null, err => { + if (err) { + this.hooks.finishRebuildingModule.call(module); + return callback(err); + } + + this.processModuleDependencies(module, err => { + if (err) return callback(err); + this.removeReasonsOfDependencyBlock(module, { + dependencies: oldDependencies, + variables: oldVariables, + blocks: oldBlocks + }); + this.hooks.finishRebuildingModule.call(module); + callback(); + }); + }); + } + + finish(callback) { + const modules = this.modules; + this.hooks.finishModules.callAsync(modules, err => { + if (err) return callback(err); + + for (let index = 0; index < modules.length; index++) { + const module = modules[index]; + this.reportDependencyErrorsAndWarnings(module, [module]); + } + + callback(); + }); + } + + unseal() { + this.hooks.unseal.call(); + this.chunks.length = 0; + this.chunkGroups.length = 0; + this.namedChunks.clear(); + this.namedChunkGroups.clear(); + this.additionalChunkAssets.length = 0; + this.assets = {}; + this.assetsInfo.clear(); + for (const module of this.modules) { + module.unseal(); + } + } + + /** + * @param {Callback} callback signals when the seal method is finishes + * @returns {void} + */ + seal(callback) { + this.hooks.seal.call(); + + while ( + this.hooks.optimizeDependenciesBasic.call(this.modules) || + this.hooks.optimizeDependencies.call(this.modules) || + this.hooks.optimizeDependenciesAdvanced.call(this.modules) + ) { + /* empty */ + } + this.hooks.afterOptimizeDependencies.call(this.modules); + + this.hooks.beforeChunks.call(); + for (const preparedEntrypoint of this._preparedEntrypoints) { + const module = preparedEntrypoint.module; + const name = preparedEntrypoint.name; + const chunk = this.addChunk(name); + const entrypoint = new Entrypoint(name); + entrypoint.setRuntimeChunk(chunk); + entrypoint.addOrigin(null, name, preparedEntrypoint.request); + this.namedChunkGroups.set(name, entrypoint); + this.entrypoints.set(name, entrypoint); + this.chunkGroups.push(entrypoint); + + GraphHelpers.connectChunkGroupAndChunk(entrypoint, chunk); + GraphHelpers.connectChunkAndModule(chunk, module); + + chunk.entryModule = module; + chunk.name = name; + + this.assignDepth(module); + } + buildChunkGraph( + this, + /** @type {Entrypoint[]} */ (this.chunkGroups.slice()) + ); + this.sortModules(this.modules); + this.hooks.afterChunks.call(this.chunks); + + this.hooks.optimize.call(); + + while ( + this.hooks.optimizeModulesBasic.call(this.modules) || + this.hooks.optimizeModules.call(this.modules) || + this.hooks.optimizeModulesAdvanced.call(this.modules) + ) { + /* empty */ + } + this.hooks.afterOptimizeModules.call(this.modules); + + while ( + this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) || + this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) || + this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups) + ) { + /* empty */ + } + this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups); + + this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => { + if (err) { + return callback(err); + } + + this.hooks.afterOptimizeTree.call(this.chunks, this.modules); + + while ( + this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) || + this.hooks.optimizeChunkModules.call(this.chunks, this.modules) || + this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules) + ) { + /* empty */ + } + this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules); + + const shouldRecord = this.hooks.shouldRecord.call() !== false; + + this.hooks.reviveModules.call(this.modules, this.records); + this.hooks.optimizeModuleOrder.call(this.modules); + this.hooks.advancedOptimizeModuleOrder.call(this.modules); + this.hooks.beforeModuleIds.call(this.modules); + this.hooks.moduleIds.call(this.modules); + this.applyModuleIds(); + this.hooks.optimizeModuleIds.call(this.modules); + this.hooks.afterOptimizeModuleIds.call(this.modules); + + this.sortItemsWithModuleIds(); + + this.hooks.reviveChunks.call(this.chunks, this.records); + this.hooks.optimizeChunkOrder.call(this.chunks); + this.hooks.beforeChunkIds.call(this.chunks); + this.applyChunkIds(); + this.hooks.optimizeChunkIds.call(this.chunks); + this.hooks.afterOptimizeChunkIds.call(this.chunks); + + this.sortItemsWithChunkIds(); + + if (shouldRecord) { + this.hooks.recordModules.call(this.modules, this.records); + this.hooks.recordChunks.call(this.chunks, this.records); + } + + this.hooks.beforeHash.call(); + this.createHash(); + this.hooks.afterHash.call(); + + if (shouldRecord) { + this.hooks.recordHash.call(this.records); + } + + this.hooks.beforeModuleAssets.call(); + this.createModuleAssets(); + if (this.hooks.shouldGenerateChunkAssets.call() !== false) { + this.hooks.beforeChunkAssets.call(); + this.createChunkAssets(); + } + this.hooks.additionalChunkAssets.call(this.chunks); + this.summarizeDependencies(); + if (shouldRecord) { + this.hooks.record.call(this, this.records); + } + + this.hooks.additionalAssets.callAsync(err => { + if (err) { + return callback(err); + } + this.hooks.optimizeChunkAssets.callAsync(this.chunks, err => { + if (err) { + return callback(err); + } + this.hooks.afterOptimizeChunkAssets.call(this.chunks); + this.hooks.optimizeAssets.callAsync(this.assets, err => { + if (err) { + return callback(err); + } + this.hooks.afterOptimizeAssets.call(this.assets); + if (this.hooks.needAdditionalSeal.call()) { + this.unseal(); + return this.seal(callback); + } + return this.hooks.afterSeal.callAsync(callback); + }); + }); + }); + }); + } + + /** + * @param {Module[]} modules the modules array on compilation to perform the sort for + * @returns {void} + */ + sortModules(modules) { + // TODO webpack 5: this should only be enabled when `moduleIds: "natural"` + // TODO move it into a plugin (NaturalModuleIdsPlugin) and use this in WebpackOptionsApply + // TODO remove this method + modules.sort(byIndexOrIdentifier); + } + + /** + * @param {Module} module moulde to report from + * @param {DependenciesBlock[]} blocks blocks to report from + * @returns {void} + */ + reportDependencyErrorsAndWarnings(module, blocks) { + for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) { + const block = blocks[indexBlock]; + const dependencies = block.dependencies; + + for (let indexDep = 0; indexDep < dependencies.length; indexDep++) { + const d = dependencies[indexDep]; + + const warnings = d.getWarnings(); + if (warnings) { + for (let indexWar = 0; indexWar < warnings.length; indexWar++) { + const w = warnings[indexWar]; + + const warning = new ModuleDependencyWarning(module, w, d.loc); + this.warnings.push(warning); + } + } + const errors = d.getErrors(); + if (errors) { + for (let indexErr = 0; indexErr < errors.length; indexErr++) { + const e = errors[indexErr]; + + const error = new ModuleDependencyError(module, e, d.loc); + this.errors.push(error); + } + } + } + + this.reportDependencyErrorsAndWarnings(module, block.blocks); + } + } + + /** + * @param {TODO} groupOptions options for the chunk group + * @param {Module} module the module the references the chunk group + * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module) + * @param {string} request the request from which the the chunk group is referenced + * @returns {ChunkGroup} the new or existing chunk group + */ + addChunkInGroup(groupOptions, module, loc, request) { + if (typeof groupOptions === "string") { + groupOptions = { name: groupOptions }; + } + const name = groupOptions.name; + if (name) { + const chunkGroup = this.namedChunkGroups.get(name); + if (chunkGroup !== undefined) { + chunkGroup.addOptions(groupOptions); + if (module) { + chunkGroup.addOrigin(module, loc, request); + } + return chunkGroup; + } + } + const chunkGroup = new ChunkGroup(groupOptions); + if (module) chunkGroup.addOrigin(module, loc, request); + const chunk = this.addChunk(name); + + GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk); + + this.chunkGroups.push(chunkGroup); + if (name) { + this.namedChunkGroups.set(name, chunkGroup); + } + return chunkGroup; + } + + /** + * This method first looks to see if a name is provided for a new chunk, + * and first looks to see if any named chunks already exist and reuse that chunk instead. + * + * @param {string=} name optional chunk name to be provided + * @returns {Chunk} create a chunk (invoked during seal event) + */ + addChunk(name) { + if (name) { + const chunk = this.namedChunks.get(name); + if (chunk !== undefined) { + return chunk; + } + } + const chunk = new Chunk(name); + this.chunks.push(chunk); + if (name) { + this.namedChunks.set(name, chunk); + } + return chunk; + } + + /** + * @param {Module} module module to assign depth + * @returns {void} + */ + assignDepth(module) { + const queue = new Set([module]); + let depth; + + module.depth = 0; + + /** + * @param {Module} module module for processeing + * @returns {void} + */ + const enqueueJob = module => { + const d = module.depth; + if (typeof d === "number" && d <= depth) return; + queue.add(module); + module.depth = depth; + }; + + /** + * @param {Dependency} dependency dependency to assign depth to + * @returns {void} + */ + const assignDepthToDependency = dependency => { + if (dependency.module) { + enqueueJob(dependency.module); + } + }; + + /** + * @param {DependenciesBlock} block block to assign depth to + * @returns {void} + */ + const assignDepthToDependencyBlock = block => { + if (block.variables) { + iterationBlockVariable(block.variables, assignDepthToDependency); + } + + if (block.dependencies) { + iterationOfArrayCallback(block.dependencies, assignDepthToDependency); + } + + if (block.blocks) { + iterationOfArrayCallback(block.blocks, assignDepthToDependencyBlock); + } + }; + + for (module of queue) { + queue.delete(module); + depth = module.depth; + + depth++; + assignDepthToDependencyBlock(module); + } + } + + /** + * @param {Module} module the module containing the dependency + * @param {Dependency} dependency the dependency + * @returns {DependencyReference} a reference for the dependency + */ + getDependencyReference(module, dependency) { + // TODO remove dep.getReference existence check in webpack 5 + if (typeof dependency.getReference !== "function") return null; + const ref = dependency.getReference(); + if (!ref) return null; + return this.hooks.dependencyReference.call(ref, dependency, module); + } + + /** + * + * @param {Module} module module relationship for removal + * @param {DependenciesBlockLike} block //TODO: good description + * @returns {void} + */ + removeReasonsOfDependencyBlock(module, block) { + const iteratorDependency = d => { + if (!d.module) { + return; + } + if (d.module.removeReason(module, d)) { + for (const chunk of d.module.chunksIterable) { + this.patchChunksAfterReasonRemoval(d.module, chunk); + } + } + }; + + if (block.blocks) { + iterationOfArrayCallback(block.blocks, block => + this.removeReasonsOfDependencyBlock(module, block) + ); + } + + if (block.dependencies) { + iterationOfArrayCallback(block.dependencies, iteratorDependency); + } + + if (block.variables) { + iterationBlockVariable(block.variables, iteratorDependency); + } + } + + /** + * @param {Module} module module to patch tie + * @param {Chunk} chunk chunk to patch tie + * @returns {void} + */ + patchChunksAfterReasonRemoval(module, chunk) { + if (!module.hasReasons()) { + this.removeReasonsOfDependencyBlock(module, module); + } + if (!module.hasReasonForChunk(chunk)) { + if (module.removeChunk(chunk)) { + this.removeChunkFromDependencies(module, chunk); + } + } + } + + /** + * + * @param {DependenciesBlock} block block tie for Chunk + * @param {Chunk} chunk chunk to remove from dep + * @returns {void} + */ + removeChunkFromDependencies(block, chunk) { + const iteratorDependency = d => { + if (!d.module) { + return; + } + this.patchChunksAfterReasonRemoval(d.module, chunk); + }; + + const blocks = block.blocks; + for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) { + const asyncBlock = blocks[indexBlock]; + // Grab all chunks from the first Block's AsyncDepBlock + const chunks = asyncBlock.chunkGroup.chunks; + // For each chunk in chunkGroup + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + const iteratedChunk = chunks[indexChunk]; + asyncBlock.chunkGroup.removeChunk(iteratedChunk); + asyncBlock.chunkGroup.removeParent(iteratedChunk); + // Recurse + this.removeChunkFromDependencies(block, iteratedChunk); + } + } + + if (block.dependencies) { + iterationOfArrayCallback(block.dependencies, iteratorDependency); + } + + if (block.variables) { + iterationBlockVariable(block.variables, iteratorDependency); + } + } + + applyModuleIds() { + const unusedIds = []; + let nextFreeModuleId = 0; + const usedIds = new Set(); + if (this.usedModuleIds) { + for (const id of this.usedModuleIds) { + usedIds.add(id); + } + } + + const modules1 = this.modules; + for (let indexModule1 = 0; indexModule1 < modules1.length; indexModule1++) { + const module1 = modules1[indexModule1]; + if (module1.id !== null) { + usedIds.add(module1.id); + } + } + + if (usedIds.size > 0) { + let usedIdMax = -1; + for (const usedIdKey of usedIds) { + if (typeof usedIdKey !== "number") { + continue; + } + + usedIdMax = Math.max(usedIdMax, usedIdKey); + } + + let lengthFreeModules = (nextFreeModuleId = usedIdMax + 1); + + while (lengthFreeModules--) { + if (!usedIds.has(lengthFreeModules)) { + unusedIds.push(lengthFreeModules); + } + } + } + + const modules2 = this.modules; + for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) { + const module2 = modules2[indexModule2]; + if (module2.id === null) { + if (unusedIds.length > 0) { + module2.id = unusedIds.pop(); + } else { + module2.id = nextFreeModuleId++; + } + } + } + } + + applyChunkIds() { + /** @type {Set<number>} */ + const usedIds = new Set(); + + // Get used ids from usedChunkIds property (i. e. from records) + if (this.usedChunkIds) { + for (const id of this.usedChunkIds) { + if (typeof id !== "number") { + continue; + } + + usedIds.add(id); + } + } + + // Get used ids from existing chunks + const chunks = this.chunks; + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + const chunk = chunks[indexChunk]; + const usedIdValue = chunk.id; + + if (typeof usedIdValue !== "number") { + continue; + } + + usedIds.add(usedIdValue); + } + + // Calculate maximum assigned chunk id + let nextFreeChunkId = -1; + for (const id of usedIds) { + nextFreeChunkId = Math.max(nextFreeChunkId, id); + } + nextFreeChunkId++; + + // Determine free chunk ids from 0 to maximum + /** @type {number[]} */ + const unusedIds = []; + if (nextFreeChunkId > 0) { + let index = nextFreeChunkId; + while (index--) { + if (!usedIds.has(index)) { + unusedIds.push(index); + } + } + } + + // Assign ids to chunk which has no id + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + const chunk = chunks[indexChunk]; + if (chunk.id === null) { + if (unusedIds.length > 0) { + chunk.id = unusedIds.pop(); + } else { + chunk.id = nextFreeChunkId++; + } + } + if (!chunk.ids) { + chunk.ids = [chunk.id]; + } + } + } + + sortItemsWithModuleIds() { + this.modules.sort(byIdOrIdentifier); + + const modules = this.modules; + for (let indexModule = 0; indexModule < modules.length; indexModule++) { + modules[indexModule].sortItems(false); + } + + const chunks = this.chunks; + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + chunks[indexChunk].sortItems(); + } + + chunks.sort((a, b) => a.compareTo(b)); + } + + sortItemsWithChunkIds() { + for (const chunkGroup of this.chunkGroups) { + chunkGroup.sortItems(); + } + + this.chunks.sort(byId); + + for ( + let indexModule = 0; + indexModule < this.modules.length; + indexModule++ + ) { + this.modules[indexModule].sortItems(true); + } + + const chunks = this.chunks; + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + chunks[indexChunk].sortItems(); + } + + /** + * Used to sort errors and warnings in compilation. this.warnings, and + * this.errors contribute to the compilation hash and therefore should be + * updated whenever other references (having a chunk id) are sorted. This preserves the hash + * integrity + * + * @param {WebpackError} a first WebpackError instance (including subclasses) + * @param {WebpackError} b second WebpackError instance (including subclasses) + * @returns {-1|0|1} sort order index + */ + const byMessage = (a, b) => { + const ma = `${a.message}`; + const mb = `${b.message}`; + if (ma < mb) return -1; + if (mb < ma) return 1; + return 0; + }; + + this.errors.sort(byMessage); + this.warnings.sort(byMessage); + this.children.sort(byNameOrHash); + } + + summarizeDependencies() { + this.fileDependencies = new SortableSet(this.compilationDependencies); + this.contextDependencies = new SortableSet(); + this.missingDependencies = new SortableSet(); + + for ( + let indexChildren = 0; + indexChildren < this.children.length; + indexChildren++ + ) { + const child = this.children[indexChildren]; + + addAllToSet(this.fileDependencies, child.fileDependencies); + addAllToSet(this.contextDependencies, child.contextDependencies); + addAllToSet(this.missingDependencies, child.missingDependencies); + } + + for ( + let indexModule = 0; + indexModule < this.modules.length; + indexModule++ + ) { + const module = this.modules[indexModule]; + + if (module.buildInfo.fileDependencies) { + addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies); + } + if (module.buildInfo.contextDependencies) { + addAllToSet( + this.contextDependencies, + module.buildInfo.contextDependencies + ); + } + } + for (const error of this.errors) { + if ( + typeof error.missing === "object" && + error.missing && + error.missing[Symbol.iterator] + ) { + addAllToSet(this.missingDependencies, error.missing); + } + } + this.fileDependencies.sort(); + this.contextDependencies.sort(); + this.missingDependencies.sort(); + } + + createHash() { + const outputOptions = this.outputOptions; + const hashFunction = outputOptions.hashFunction; + const hashDigest = outputOptions.hashDigest; + const hashDigestLength = outputOptions.hashDigestLength; + const hash = createHash(hashFunction); + if (outputOptions.hashSalt) { + hash.update(outputOptions.hashSalt); + } + this.mainTemplate.updateHash(hash); + this.chunkTemplate.updateHash(hash); + for (const key of Object.keys(this.moduleTemplates).sort()) { + this.moduleTemplates[key].updateHash(hash); + } + for (const child of this.children) { + hash.update(child.hash); + } + for (const warning of this.warnings) { + hash.update(`${warning.message}`); + } + for (const error of this.errors) { + hash.update(`${error.message}`); + } + const modules = this.modules; + for (let i = 0; i < modules.length; i++) { + const module = modules[i]; + const moduleHash = createHash(hashFunction); + module.updateHash(moduleHash); + module.hash = /** @type {string} */ (moduleHash.digest(hashDigest)); + module.renderedHash = module.hash.substr(0, hashDigestLength); + } + // clone needed as sort below is inplace mutation + const chunks = this.chunks.slice(); + /** + * sort here will bring all "falsy" values to the beginning + * this is needed as the "hasRuntime()" chunks are dependent on the + * hashes of the non-runtime chunks. + */ + chunks.sort((a, b) => { + const aEntry = a.hasRuntime(); + const bEntry = b.hasRuntime(); + if (aEntry && !bEntry) return 1; + if (!aEntry && bEntry) return -1; + return byId(a, b); + }); + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + const chunkHash = createHash(hashFunction); + try { + if (outputOptions.hashSalt) { + chunkHash.update(outputOptions.hashSalt); + } + chunk.updateHash(chunkHash); + const template = chunk.hasRuntime() + ? this.mainTemplate + : this.chunkTemplate; + template.updateHashForChunk( + chunkHash, + chunk, + this.moduleTemplates.javascript, + this.dependencyTemplates + ); + this.hooks.chunkHash.call(chunk, chunkHash); + chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest)); + hash.update(chunk.hash); + chunk.renderedHash = chunk.hash.substr(0, hashDigestLength); + this.hooks.contentHash.call(chunk); + } catch (err) { + this.errors.push(new ChunkRenderError(chunk, "", err)); + } + } + this.fullHash = /** @type {string} */ (hash.digest(hashDigest)); + this.hash = this.fullHash.substr(0, hashDigestLength); + } + + /** + * @param {string} update extra information + * @returns {void} + */ + modifyHash(update) { + const outputOptions = this.outputOptions; + const hashFunction = outputOptions.hashFunction; + const hashDigest = outputOptions.hashDigest; + const hashDigestLength = outputOptions.hashDigestLength; + const hash = createHash(hashFunction); + hash.update(this.fullHash); + hash.update(update); + this.fullHash = /** @type {string} */ (hash.digest(hashDigest)); + this.hash = this.fullHash.substr(0, hashDigestLength); + } + + /** + * @param {string} file file name + * @param {Source} source asset source + * @param {AssetInfo} assetInfo extra asset information + * @returns {void} + */ + emitAsset(file, source, assetInfo = {}) { + if (this.assets[file]) { + if (!isSourceEqual(this.assets[file], source)) { + // TODO webpack 5: make this an error instead + this.warnings.push( + new WebpackError( + `Conflict: Multiple assets emit different content to the same filename ${file}` + ) + ); + this.assets[file] = source; + this.assetsInfo.set(file, assetInfo); + return; + } + const oldInfo = this.assetsInfo.get(file); + this.assetsInfo.set(file, Object.assign({}, oldInfo, assetInfo)); + return; + } + this.assets[file] = source; + this.assetsInfo.set(file, assetInfo); + } + + /** + * @param {string} file file name + * @param {Source | function(Source): Source} newSourceOrFunction new asset source or function converting old to new + * @param {AssetInfo | function(AssetInfo | undefined): AssetInfo} assetInfoUpdateOrFunction new asset info or function converting old to new + */ + updateAsset( + file, + newSourceOrFunction, + assetInfoUpdateOrFunction = undefined + ) { + if (!this.assets[file]) { + throw new Error( + `Called Compilation.updateAsset for not existing filename ${file}` + ); + } + if (typeof newSourceOrFunction === "function") { + this.assets[file] = newSourceOrFunction(this.assets[file]); + } else { + this.assets[file] = newSourceOrFunction; + } + if (assetInfoUpdateOrFunction !== undefined) { + const oldInfo = this.assetsInfo.get(file); + if (typeof assetInfoUpdateOrFunction === "function") { + this.assetsInfo.set(file, assetInfoUpdateOrFunction(oldInfo || {})); + } else { + this.assetsInfo.set( + file, + Object.assign({}, oldInfo, assetInfoUpdateOrFunction) + ); + } + } + } + + getAssets() { + /** @type {Asset[]} */ + const array = []; + for (const assetName of Object.keys(this.assets)) { + if (Object.prototype.hasOwnProperty.call(this.assets, assetName)) { + array.push({ + name: assetName, + source: this.assets[assetName], + info: this.assetsInfo.get(assetName) || {} + }); + } + } + return array; + } + + /** + * @param {string} name the name of the asset + * @returns {Asset | undefined} the asset or undefined when not found + */ + getAsset(name) { + if (!Object.prototype.hasOwnProperty.call(this.assets, name)) + return undefined; + return { + name, + source: this.assets[name], + info: this.assetsInfo.get(name) || {} + }; + } + + createModuleAssets() { + for (let i = 0; i < this.modules.length; i++) { + const module = this.modules[i]; + if (module.buildInfo.assets) { + const assetsInfo = module.buildInfo.assetsInfo; + for (const assetName of Object.keys(module.buildInfo.assets)) { + const fileName = this.getPath(assetName); + this.emitAsset( + fileName, + module.buildInfo.assets[assetName], + assetsInfo ? assetsInfo.get(assetName) : undefined + ); + this.hooks.moduleAsset.call(module, fileName); + } + } + } + } + + createChunkAssets() { + const outputOptions = this.outputOptions; + const cachedSourceMap = new Map(); + /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */ + const alreadyWrittenFiles = new Map(); + for (let i = 0; i < this.chunks.length; i++) { + const chunk = this.chunks[i]; + chunk.files = []; + let source; + let file; + let filenameTemplate; + try { + const template = chunk.hasRuntime() + ? this.mainTemplate + : this.chunkTemplate; + const manifest = template.getRenderManifest({ + chunk, + hash: this.hash, + fullHash: this.fullHash, + outputOptions, + moduleTemplates: this.moduleTemplates, + dependencyTemplates: this.dependencyTemplates + }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }] + for (const fileManifest of manifest) { + const cacheName = fileManifest.identifier; + const usedHash = fileManifest.hash; + filenameTemplate = fileManifest.filenameTemplate; + const pathAndInfo = this.getPathWithInfo( + filenameTemplate, + fileManifest.pathOptions + ); + file = pathAndInfo.path; + const assetInfo = pathAndInfo.info; + + // check if the same filename was already written by another chunk + const alreadyWritten = alreadyWrittenFiles.get(file); + if (alreadyWritten !== undefined) { + if (alreadyWritten.hash === usedHash) { + if (this.cache) { + this.cache[cacheName] = { + hash: usedHash, + source: alreadyWritten.source + }; + } + chunk.files.push(file); + this.hooks.chunkAsset.call(chunk, file); + continue; + } else { + throw new Error( + `Conflict: Multiple chunks emit assets to the same filename ${file}` + + ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})` + ); + } + } + if ( + this.cache && + this.cache[cacheName] && + this.cache[cacheName].hash === usedHash + ) { + source = this.cache[cacheName].source; + } else { + source = fileManifest.render(); + // Ensure that source is a cached source to avoid additional cost because of repeated access + if (!(source instanceof CachedSource)) { + const cacheEntry = cachedSourceMap.get(source); + if (cacheEntry) { + source = cacheEntry; + } else { + const cachedSource = new CachedSource(source); + cachedSourceMap.set(source, cachedSource); + source = cachedSource; + } + } + if (this.cache) { + this.cache[cacheName] = { + hash: usedHash, + source + }; + } + } + this.emitAsset(file, source, assetInfo); + chunk.files.push(file); + this.hooks.chunkAsset.call(chunk, file); + alreadyWrittenFiles.set(file, { + hash: usedHash, + source, + chunk + }); + } + } catch (err) { + this.errors.push( + new ChunkRenderError(chunk, file || filenameTemplate, err) + ); + } + } + } + + /** + * @param {string} filename used to get asset path with hash + * @param {TODO=} data // TODO: figure out this param type + * @returns {string} interpolated path + */ + getPath(filename, data) { + data = data || {}; + data.hash = data.hash || this.hash; + return this.mainTemplate.getAssetPath(filename, data); + } + + /** + * @param {string} filename used to get asset path with hash + * @param {TODO=} data // TODO: figure out this param type + * @returns {{ path: string, info: AssetInfo }} interpolated path and asset info + */ + getPathWithInfo(filename, data) { + data = data || {}; + data.hash = data.hash || this.hash; + return this.mainTemplate.getAssetPathWithInfo(filename, data); + } + + /** + * This function allows you to run another instance of webpack inside of webpack however as + * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins + * from parent (or top level compiler) and creates a child Compilation + * + * @param {string} name name of the child compiler + * @param {TODO} outputOptions // Need to convert config schema to types for this + * @param {Plugin[]} plugins webpack plugins that will be applied + * @returns {Compiler} creates a child Compiler instance + */ + createChildCompiler(name, outputOptions, plugins) { + const idx = this.childrenCounters[name] || 0; + this.childrenCounters[name] = idx + 1; + return this.compiler.createChildCompiler( + this, + name, + idx, + outputOptions, + plugins + ); + } + + checkConstraints() { + /** @type {Set<number|string>} */ + const usedIds = new Set(); + + const modules = this.modules; + for (let indexModule = 0; indexModule < modules.length; indexModule++) { + const moduleId = modules[indexModule].id; + if (moduleId === null) continue; + if (usedIds.has(moduleId)) { + throw new Error(`checkConstraints: duplicate module id ${moduleId}`); + } + usedIds.add(moduleId); + } + + const chunks = this.chunks; + for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) { + const chunk = chunks[indexChunk]; + if (chunks.indexOf(chunk) !== indexChunk) { + throw new Error( + `checkConstraints: duplicate chunk in compilation ${chunk.debugId}` + ); + } + } + + for (const chunkGroup of this.chunkGroups) { + chunkGroup.checkConstraints(); + } + } +} + +// TODO remove in webpack 5 +Compilation.prototype.applyPlugins = util.deprecate( + /** + * @deprecated + * @param {string} name Name + * @param {any[]} args Other arguments + * @returns {void} + * @this {Compilation} + */ + function(name, ...args) { + this.hooks[ + name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase()) + ].call(...args); + }, + "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead" +); + +// TODO remove in webpack 5 +Object.defineProperty(Compilation.prototype, "moduleTemplate", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {Compilation} + * @returns {TODO} module template + */ + function() { + return this.moduleTemplates.javascript; + }, + "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead" + ), + set: util.deprecate( + /** + * @deprecated + * @param {ModuleTemplate} value Template value + * @this {Compilation} + * @returns {void} + */ + function(value) { + this.moduleTemplates.javascript = value; + }, + "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead." + ) +}); + +module.exports = Compilation; diff --git a/node_modules/webpack/lib/Compiler.js b/node_modules/webpack/lib/Compiler.js new file mode 100644 index 0000000..376aa28 --- /dev/null +++ b/node_modules/webpack/lib/Compiler.js @@ -0,0 +1,735 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const parseJson = require("json-parse-better-errors"); +const asyncLib = require("neo-async"); +const path = require("path"); +const { Source } = require("webpack-sources"); +const util = require("util"); +const { + Tapable, + SyncHook, + SyncBailHook, + AsyncParallelHook, + AsyncSeriesHook +} = require("tapable"); + +const Compilation = require("./Compilation"); +const Stats = require("./Stats"); +const Watching = require("./Watching"); +const NormalModuleFactory = require("./NormalModuleFactory"); +const ContextModuleFactory = require("./ContextModuleFactory"); +const ResolverFactory = require("./ResolverFactory"); + +const RequestShortener = require("./RequestShortener"); +const { makePathsRelative } = require("./util/identifier"); +const ConcurrentCompilationError = require("./ConcurrentCompilationError"); +const { Logger } = require("./logging/Logger"); + +/** @typedef {import("../declarations/WebpackOptions").Entry} Entry */ +/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */ + +/** + * @typedef {Object} CompilationParams + * @property {NormalModuleFactory} normalModuleFactory + * @property {ContextModuleFactory} contextModuleFactory + * @property {Set<string>} compilationDependencies + */ + +class Compiler extends Tapable { + constructor(context) { + super(); + this.hooks = { + /** @type {SyncBailHook<Compilation>} */ + shouldEmit: new SyncBailHook(["compilation"]), + /** @type {AsyncSeriesHook<Stats>} */ + done: new AsyncSeriesHook(["stats"]), + /** @type {AsyncSeriesHook<>} */ + additionalPass: new AsyncSeriesHook([]), + /** @type {AsyncSeriesHook<Compiler>} */ + beforeRun: new AsyncSeriesHook(["compiler"]), + /** @type {AsyncSeriesHook<Compiler>} */ + run: new AsyncSeriesHook(["compiler"]), + /** @type {AsyncSeriesHook<Compilation>} */ + emit: new AsyncSeriesHook(["compilation"]), + /** @type {AsyncSeriesHook<string, Buffer>} */ + assetEmitted: new AsyncSeriesHook(["file", "content"]), + /** @type {AsyncSeriesHook<Compilation>} */ + afterEmit: new AsyncSeriesHook(["compilation"]), + + /** @type {SyncHook<Compilation, CompilationParams>} */ + thisCompilation: new SyncHook(["compilation", "params"]), + /** @type {SyncHook<Compilation, CompilationParams>} */ + compilation: new SyncHook(["compilation", "params"]), + /** @type {SyncHook<NormalModuleFactory>} */ + normalModuleFactory: new SyncHook(["normalModuleFactory"]), + /** @type {SyncHook<ContextModuleFactory>} */ + contextModuleFactory: new SyncHook(["contextModulefactory"]), + + /** @type {AsyncSeriesHook<CompilationParams>} */ + beforeCompile: new AsyncSeriesHook(["params"]), + /** @type {SyncHook<CompilationParams>} */ + compile: new SyncHook(["params"]), + /** @type {AsyncParallelHook<Compilation>} */ + make: new AsyncParallelHook(["compilation"]), + /** @type {AsyncSeriesHook<Compilation>} */ + afterCompile: new AsyncSeriesHook(["compilation"]), + + /** @type {AsyncSeriesHook<Compiler>} */ + watchRun: new AsyncSeriesHook(["compiler"]), + /** @type {SyncHook<Error>} */ + failed: new SyncHook(["error"]), + /** @type {SyncHook<string, string>} */ + invalid: new SyncHook(["filename", "changeTime"]), + /** @type {SyncHook} */ + watchClose: new SyncHook([]), + + /** @type {SyncBailHook<string, string, any[]>} */ + infrastructureLog: new SyncBailHook(["origin", "type", "args"]), + + // TODO the following hooks are weirdly located here + // TODO move them for webpack 5 + /** @type {SyncHook} */ + environment: new SyncHook([]), + /** @type {SyncHook} */ + afterEnvironment: new SyncHook([]), + /** @type {SyncHook<Compiler>} */ + afterPlugins: new SyncHook(["compiler"]), + /** @type {SyncHook<Compiler>} */ + afterResolvers: new SyncHook(["compiler"]), + /** @type {SyncBailHook<string, Entry>} */ + entryOption: new SyncBailHook(["context", "entry"]) + }; + // TODO webpack 5 remove this + this.hooks.infrastructurelog = this.hooks.infrastructureLog; + + this._pluginCompat.tap("Compiler", options => { + switch (options.name) { + case "additional-pass": + case "before-run": + case "run": + case "emit": + case "after-emit": + case "before-compile": + case "make": + case "after-compile": + case "watch-run": + options.async = true; + break; + } + }); + + /** @type {string=} */ + this.name = undefined; + /** @type {Compilation=} */ + this.parentCompilation = undefined; + /** @type {string} */ + this.outputPath = ""; + + this.outputFileSystem = null; + this.inputFileSystem = null; + + /** @type {string|null} */ + this.recordsInputPath = null; + /** @type {string|null} */ + this.recordsOutputPath = null; + this.records = {}; + this.removedFiles = new Set(); + /** @type {Map<string, number>} */ + this.fileTimestamps = new Map(); + /** @type {Map<string, number>} */ + this.contextTimestamps = new Map(); + /** @type {ResolverFactory} */ + this.resolverFactory = new ResolverFactory(); + + this.infrastructureLogger = undefined; + + // TODO remove in webpack 5 + this.resolvers = { + normal: { + plugins: util.deprecate((hook, fn) => { + this.resolverFactory.plugin("resolver normal", resolver => { + resolver.plugin(hook, fn); + }); + }, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.plugin(/* … */);\n}); instead.'), + apply: util.deprecate((...args) => { + this.resolverFactory.plugin("resolver normal", resolver => { + resolver.apply(...args); + }); + }, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.apply(/* … */);\n}); instead.') + }, + loader: { + plugins: util.deprecate((hook, fn) => { + this.resolverFactory.plugin("resolver loader", resolver => { + resolver.plugin(hook, fn); + }); + }, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.plugin(/* … */);\n}); instead.'), + apply: util.deprecate((...args) => { + this.resolverFactory.plugin("resolver loader", resolver => { + resolver.apply(...args); + }); + }, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.apply(/* … */);\n}); instead.') + }, + context: { + plugins: util.deprecate((hook, fn) => { + this.resolverFactory.plugin("resolver context", resolver => { + resolver.plugin(hook, fn); + }); + }, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.plugin(/* … */);\n}); instead.'), + apply: util.deprecate((...args) => { + this.resolverFactory.plugin("resolver context", resolver => { + resolver.apply(...args); + }); + }, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.apply(/* … */);\n}); instead.') + } + }; + + /** @type {WebpackOptions} */ + this.options = /** @type {WebpackOptions} */ ({}); + + this.context = context; + + this.requestShortener = new RequestShortener(context); + + /** @type {boolean} */ + this.running = false; + + /** @type {boolean} */ + this.watchMode = false; + + /** @private @type {WeakMap<Source, { sizeOnlySource: SizeOnlySource, writtenTo: Map<string, number> }>} */ + this._assetEmittingSourceCache = new WeakMap(); + /** @private @type {Map<string, number>} */ + this._assetEmittingWrittenFiles = new Map(); + } + + /** + * @param {string | (function(): string)} name name of the logger, or function called once to get the logger name + * @returns {Logger} a logger with that name + */ + getInfrastructureLogger(name) { + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called without a name" + ); + } + return new Logger((type, args) => { + if (typeof name === "function") { + name = name(); + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called with a function not returning a name" + ); + } + } + if (this.hooks.infrastructureLog.call(name, type, args) === undefined) { + if (this.infrastructureLogger !== undefined) { + this.infrastructureLogger(name, type, args); + } + } + }); + } + + watch(watchOptions, handler) { + if (this.running) return handler(new ConcurrentCompilationError()); + + this.running = true; + this.watchMode = true; + this.fileTimestamps = new Map(); + this.contextTimestamps = new Map(); + this.removedFiles = new Set(); + return new Watching(this, watchOptions, handler); + } + + run(callback) { + if (this.running) return callback(new ConcurrentCompilationError()); + + const finalCallback = (err, stats) => { + this.running = false; + + if (err) { + this.hooks.failed.call(err); + } + + if (callback !== undefined) return callback(err, stats); + }; + + const startTime = Date.now(); + + this.running = true; + + const onCompiled = (err, compilation) => { + if (err) return finalCallback(err); + + if (this.hooks.shouldEmit.call(compilation) === false) { + const stats = new Stats(compilation); + stats.startTime = startTime; + stats.endTime = Date.now(); + this.hooks.done.callAsync(stats, err => { + if (err) return finalCallback(err); + return finalCallback(null, stats); + }); + return; + } + + this.emitAssets(compilation, err => { + if (err) return finalCallback(err); + + if (compilation.hooks.needAdditionalPass.call()) { + compilation.needAdditionalPass = true; + + const stats = new Stats(compilation); + stats.startTime = startTime; + stats.endTime = Date.now(); + this.hooks.done.callAsync(stats, err => { + if (err) return finalCallback(err); + + this.hooks.additionalPass.callAsync(err => { + if (err) return finalCallback(err); + this.compile(onCompiled); + }); + }); + return; + } + + this.emitRecords(err => { + if (err) return finalCallback(err); + + const stats = new Stats(compilation); + stats.startTime = startTime; + stats.endTime = Date.now(); + this.hooks.done.callAsync(stats, err => { + if (err) return finalCallback(err); + return finalCallback(null, stats); + }); + }); + }); + }; + + this.hooks.beforeRun.callAsync(this, err => { + if (err) return finalCallback(err); + + this.hooks.run.callAsync(this, err => { + if (err) return finalCallback(err); + + this.readRecords(err => { + if (err) return finalCallback(err); + + this.compile(onCompiled); + }); + }); + }); + } + + runAsChild(callback) { + this.compile((err, compilation) => { + if (err) return callback(err); + + this.parentCompilation.children.push(compilation); + for (const { name, source, info } of compilation.getAssets()) { + this.parentCompilation.emitAsset(name, source, info); + } + + const entries = Array.from( + compilation.entrypoints.values(), + ep => ep.chunks + ).reduce((array, chunks) => { + return array.concat(chunks); + }, []); + + return callback(null, entries, compilation); + }); + } + + purgeInputFileSystem() { + if (this.inputFileSystem && this.inputFileSystem.purge) { + this.inputFileSystem.purge(); + } + } + + emitAssets(compilation, callback) { + let outputPath; + const emitFiles = err => { + if (err) return callback(err); + + asyncLib.forEachLimit( + compilation.getAssets(), + 15, + ({ name: file, source }, callback) => { + let targetFile = file; + const queryStringIdx = targetFile.indexOf("?"); + if (queryStringIdx >= 0) { + targetFile = targetFile.substr(0, queryStringIdx); + } + + const writeOut = err => { + if (err) return callback(err); + const targetPath = this.outputFileSystem.join( + outputPath, + targetFile + ); + // TODO webpack 5 remove futureEmitAssets option and make it on by default + if (this.options.output.futureEmitAssets) { + // check if the target file has already been written by this Compiler + const targetFileGeneration = this._assetEmittingWrittenFiles.get( + targetPath + ); + + // create an cache entry for this Source if not already existing + let cacheEntry = this._assetEmittingSourceCache.get(source); + if (cacheEntry === undefined) { + cacheEntry = { + sizeOnlySource: undefined, + writtenTo: new Map() + }; + this._assetEmittingSourceCache.set(source, cacheEntry); + } + + // if the target file has already been written + if (targetFileGeneration !== undefined) { + // check if the Source has been written to this target file + const writtenGeneration = cacheEntry.writtenTo.get(targetPath); + if (writtenGeneration === targetFileGeneration) { + // if yes, we skip writing the file + // as it's already there + // (we assume one doesn't remove files while the Compiler is running) + + compilation.updateAsset(file, cacheEntry.sizeOnlySource, { + size: cacheEntry.sizeOnlySource.size() + }); + + return callback(); + } + } + + // TODO webpack 5: if info.immutable check if file already exists in output + // skip emitting if it's already there + + // get the binary (Buffer) content from the Source + /** @type {Buffer} */ + let content; + if (typeof source.buffer === "function") { + content = source.buffer(); + } else { + const bufferOrString = source.source(); + if (Buffer.isBuffer(bufferOrString)) { + content = bufferOrString; + } else { + content = Buffer.from(bufferOrString, "utf8"); + } + } + + // Create a replacement resource which only allows to ask for size + // This allows to GC all memory allocated by the Source + // (expect when the Source is stored in any other cache) + cacheEntry.sizeOnlySource = new SizeOnlySource(content.length); + compilation.updateAsset(file, cacheEntry.sizeOnlySource, { + size: content.length + }); + + // Write the file to output file system + this.outputFileSystem.writeFile(targetPath, content, err => { + if (err) return callback(err); + + // information marker that the asset has been emitted + compilation.emittedAssets.add(file); + + // cache the information that the Source has been written to that location + const newGeneration = + targetFileGeneration === undefined + ? 1 + : targetFileGeneration + 1; + cacheEntry.writtenTo.set(targetPath, newGeneration); + this._assetEmittingWrittenFiles.set(targetPath, newGeneration); + this.hooks.assetEmitted.callAsync(file, content, callback); + }); + } else { + if (source.existsAt === targetPath) { + source.emitted = false; + return callback(); + } + let content = source.source(); + + if (!Buffer.isBuffer(content)) { + content = Buffer.from(content, "utf8"); + } + + source.existsAt = targetPath; + source.emitted = true; + this.outputFileSystem.writeFile(targetPath, content, err => { + if (err) return callback(err); + this.hooks.assetEmitted.callAsync(file, content, callback); + }); + } + }; + + if (targetFile.match(/\/|\\/)) { + const dir = path.dirname(targetFile); + this.outputFileSystem.mkdirp( + this.outputFileSystem.join(outputPath, dir), + writeOut + ); + } else { + writeOut(); + } + }, + err => { + if (err) return callback(err); + + this.hooks.afterEmit.callAsync(compilation, err => { + if (err) return callback(err); + + return callback(); + }); + } + ); + }; + + this.hooks.emit.callAsync(compilation, err => { + if (err) return callback(err); + outputPath = compilation.getPath(this.outputPath); + this.outputFileSystem.mkdirp(outputPath, emitFiles); + }); + } + + emitRecords(callback) { + if (!this.recordsOutputPath) return callback(); + const idx1 = this.recordsOutputPath.lastIndexOf("/"); + const idx2 = this.recordsOutputPath.lastIndexOf("\\"); + let recordsOutputPathDirectory = null; + if (idx1 > idx2) { + recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1); + } else if (idx1 < idx2) { + recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2); + } + + const writeFile = () => { + this.outputFileSystem.writeFile( + this.recordsOutputPath, + JSON.stringify(this.records, undefined, 2), + callback + ); + }; + + if (!recordsOutputPathDirectory) { + return writeFile(); + } + this.outputFileSystem.mkdirp(recordsOutputPathDirectory, err => { + if (err) return callback(err); + writeFile(); + }); + } + + readRecords(callback) { + if (!this.recordsInputPath) { + this.records = {}; + return callback(); + } + this.inputFileSystem.stat(this.recordsInputPath, err => { + // It doesn't exist + // We can ignore this. + if (err) return callback(); + + this.inputFileSystem.readFile(this.recordsInputPath, (err, content) => { + if (err) return callback(err); + + try { + this.records = parseJson(content.toString("utf-8")); + } catch (e) { + e.message = "Cannot parse records: " + e.message; + return callback(e); + } + + return callback(); + }); + }); + } + + createChildCompiler( + compilation, + compilerName, + compilerIndex, + outputOptions, + plugins + ) { + const childCompiler = new Compiler(this.context); + if (Array.isArray(plugins)) { + for (const plugin of plugins) { + plugin.apply(childCompiler); + } + } + for (const name in this.hooks) { + if ( + ![ + "make", + "compile", + "emit", + "afterEmit", + "invalid", + "done", + "thisCompilation" + ].includes(name) + ) { + if (childCompiler.hooks[name]) { + childCompiler.hooks[name].taps = this.hooks[name].taps.slice(); + } + } + } + childCompiler.name = compilerName; + childCompiler.outputPath = this.outputPath; + childCompiler.inputFileSystem = this.inputFileSystem; + childCompiler.outputFileSystem = null; + childCompiler.resolverFactory = this.resolverFactory; + childCompiler.fileTimestamps = this.fileTimestamps; + childCompiler.contextTimestamps = this.contextTimestamps; + + const relativeCompilerName = makePathsRelative(this.context, compilerName); + if (!this.records[relativeCompilerName]) { + this.records[relativeCompilerName] = []; + } + if (this.records[relativeCompilerName][compilerIndex]) { + childCompiler.records = this.records[relativeCompilerName][compilerIndex]; + } else { + this.records[relativeCompilerName].push((childCompiler.records = {})); + } + + childCompiler.options = Object.create(this.options); + childCompiler.options.output = Object.create(childCompiler.options.output); + for (const name in outputOptions) { + childCompiler.options.output[name] = outputOptions[name]; + } + childCompiler.parentCompilation = compilation; + + compilation.hooks.childCompiler.call( + childCompiler, + compilerName, + compilerIndex + ); + + return childCompiler; + } + + isChild() { + return !!this.parentCompilation; + } + + createCompilation() { + return new Compilation(this); + } + + newCompilation(params) { + const compilation = this.createCompilation(); + compilation.fileTimestamps = this.fileTimestamps; + compilation.contextTimestamps = this.contextTimestamps; + compilation.name = this.name; + compilation.records = this.records; + compilation.compilationDependencies = params.compilationDependencies; + this.hooks.thisCompilation.call(compilation, params); + this.hooks.compilation.call(compilation, params); + return compilation; + } + + createNormalModuleFactory() { + const normalModuleFactory = new NormalModuleFactory( + this.options.context, + this.resolverFactory, + this.options.module || {} + ); + this.hooks.normalModuleFactory.call(normalModuleFactory); + return normalModuleFactory; + } + + createContextModuleFactory() { + const contextModuleFactory = new ContextModuleFactory(this.resolverFactory); + this.hooks.contextModuleFactory.call(contextModuleFactory); + return contextModuleFactory; + } + + newCompilationParams() { + const params = { + normalModuleFactory: this.createNormalModuleFactory(), + contextModuleFactory: this.createContextModuleFactory(), + compilationDependencies: new Set() + }; + return params; + } + + compile(callback) { + const params = this.newCompilationParams(); + this.hooks.beforeCompile.callAsync(params, err => { + if (err) return callback(err); + + this.hooks.compile.call(params); + + const compilation = this.newCompilation(params); + + this.hooks.make.callAsync(compilation, err => { + if (err) return callback(err); + + compilation.finish(err => { + if (err) return callback(err); + + compilation.seal(err => { + if (err) return callback(err); + + this.hooks.afterCompile.callAsync(compilation, err => { + if (err) return callback(err); + + return callback(null, compilation); + }); + }); + }); + }); + }); + } +} + +module.exports = Compiler; + +class SizeOnlySource extends Source { + constructor(size) { + super(); + this._size = size; + } + + _error() { + return new Error( + "Content and Map of this Source is no longer available (only size() is supported)" + ); + } + + size() { + return this._size; + } + + /** + * @param {any} options options + * @returns {string} the source + */ + source(options) { + throw this._error(); + } + + node() { + throw this._error(); + } + + listMap() { + throw this._error(); + } + + map() { + throw this._error(); + } + + listNode() { + throw this._error(); + } + + updateHash() { + throw this._error(); + } +} diff --git a/node_modules/webpack/lib/ConcurrentCompilationError.js b/node_modules/webpack/lib/ConcurrentCompilationError.js new file mode 100644 index 0000000..3b590e7 --- /dev/null +++ b/node_modules/webpack/lib/ConcurrentCompilationError.js @@ -0,0 +1,19 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Maksim Nazarjev @acupofspirt +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +module.exports = class ConcurrentCompilationError extends WebpackError { + constructor() { + super(); + + this.name = "ConcurrentCompilationError"; + this.message = + "You ran Webpack twice. Each instance only supports a single concurrent compilation at a time."; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/ConstPlugin.js b/node_modules/webpack/lib/ConstPlugin.js new file mode 100644 index 0000000..6b05720 --- /dev/null +++ b/node_modules/webpack/lib/ConstPlugin.js @@ -0,0 +1,348 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ConstDependency = require("./dependencies/ConstDependency"); +const NullFactory = require("./NullFactory"); +const ParserHelpers = require("./ParserHelpers"); + +const getQuery = request => { + const i = request.indexOf("?"); + return i !== -1 ? request.substr(i) : ""; +}; + +const collectDeclaration = (declarations, pattern) => { + const stack = [pattern]; + while (stack.length > 0) { + const node = stack.pop(); + switch (node.type) { + case "Identifier": + declarations.add(node.name); + break; + case "ArrayPattern": + for (const element of node.elements) { + if (element) { + stack.push(element); + } + } + break; + case "AssignmentPattern": + stack.push(node.left); + break; + case "ObjectPattern": + for (const property of node.properties) { + stack.push(property.value); + } + break; + case "RestElement": + stack.push(node.argument); + break; + } + } +}; + +const getHoistedDeclarations = (branch, includeFunctionDeclarations) => { + const declarations = new Set(); + const stack = [branch]; + while (stack.length > 0) { + const node = stack.pop(); + // Some node could be `null` or `undefined`. + if (!node) continue; + switch (node.type) { + // Walk through control statements to look for hoisted declarations. + // Some branches are skipped since they do not allow declarations. + case "BlockStatement": + for (const stmt of node.body) { + stack.push(stmt); + } + break; + case "IfStatement": + stack.push(node.consequent); + stack.push(node.alternate); + break; + case "ForStatement": + stack.push(node.init); + stack.push(node.body); + break; + case "ForInStatement": + case "ForOfStatement": + stack.push(node.left); + stack.push(node.body); + break; + case "DoWhileStatement": + case "WhileStatement": + case "LabeledStatement": + stack.push(node.body); + break; + case "SwitchStatement": + for (const cs of node.cases) { + for (const consequent of cs.consequent) { + stack.push(consequent); + } + } + break; + case "TryStatement": + stack.push(node.block); + if (node.handler) { + stack.push(node.handler.body); + } + stack.push(node.finalizer); + break; + case "FunctionDeclaration": + if (includeFunctionDeclarations) { + collectDeclaration(declarations, node.id); + } + break; + case "VariableDeclaration": + if (node.kind === "var") { + for (const decl of node.declarations) { + collectDeclaration(declarations, decl.id); + } + } + break; + } + } + return Array.from(declarations); +}; + +class ConstPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "ConstPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + const handler = parser => { + parser.hooks.statementIf.tap("ConstPlugin", statement => { + if (parser.scope.isAsmJs) return; + const param = parser.evaluateExpression(statement.test); + const bool = param.asBool(); + if (typeof bool === "boolean") { + if (statement.test.type !== "Literal") { + const dep = new ConstDependency(`${bool}`, param.range); + dep.loc = statement.loc; + parser.state.current.addDependency(dep); + } + const branchToRemove = bool + ? statement.alternate + : statement.consequent; + if (branchToRemove) { + // Before removing the dead branch, the hoisted declarations + // must be collected. + // + // Given the following code: + // + // if (true) f() else g() + // if (false) { + // function f() {} + // const g = function g() {} + // if (someTest) { + // let a = 1 + // var x, {y, z} = obj + // } + // } else { + // … + // } + // + // the generated code is: + // + // if (true) f() else {} + // if (false) { + // var f, x, y, z; (in loose mode) + // var x, y, z; (in strict mode) + // } else { + // … + // } + // + // NOTE: When code runs in strict mode, `var` declarations + // are hoisted but `function` declarations don't. + // + let declarations; + if (parser.scope.isStrict) { + // If the code runs in strict mode, variable declarations + // using `var` must be hoisted. + declarations = getHoistedDeclarations(branchToRemove, false); + } else { + // Otherwise, collect all hoisted declaration. + declarations = getHoistedDeclarations(branchToRemove, true); + } + let replacement; + if (declarations.length > 0) { + replacement = `{ var ${declarations.join(", ")}; }`; + } else { + replacement = "{}"; + } + const dep = new ConstDependency( + replacement, + branchToRemove.range + ); + dep.loc = branchToRemove.loc; + parser.state.current.addDependency(dep); + } + return bool; + } + }); + parser.hooks.expressionConditionalOperator.tap( + "ConstPlugin", + expression => { + if (parser.scope.isAsmJs) return; + const param = parser.evaluateExpression(expression.test); + const bool = param.asBool(); + if (typeof bool === "boolean") { + if (expression.test.type !== "Literal") { + const dep = new ConstDependency(` ${bool}`, param.range); + dep.loc = expression.loc; + parser.state.current.addDependency(dep); + } + // Expressions do not hoist. + // It is safe to remove the dead branch. + // + // Given the following code: + // + // false ? someExpression() : otherExpression(); + // + // the generated code is: + // + // false ? undefined : otherExpression(); + // + const branchToRemove = bool + ? expression.alternate + : expression.consequent; + const dep = new ConstDependency( + "undefined", + branchToRemove.range + ); + dep.loc = branchToRemove.loc; + parser.state.current.addDependency(dep); + return bool; + } + } + ); + parser.hooks.expressionLogicalOperator.tap( + "ConstPlugin", + expression => { + if (parser.scope.isAsmJs) return; + if ( + expression.operator === "&&" || + expression.operator === "||" + ) { + const param = parser.evaluateExpression(expression.left); + const bool = param.asBool(); + if (typeof bool === "boolean") { + // Expressions do not hoist. + // It is safe to remove the dead branch. + // + // ------------------------------------------ + // + // Given the following code: + // + // falsyExpression() && someExpression(); + // + // the generated code is: + // + // falsyExpression() && false; + // + // ------------------------------------------ + // + // Given the following code: + // + // truthyExpression() && someExpression(); + // + // the generated code is: + // + // true && someExpression(); + // + // ------------------------------------------ + // + // Given the following code: + // + // truthyExpression() || someExpression(); + // + // the generated code is: + // + // truthyExpression() || false; + // + // ------------------------------------------ + // + // Given the following code: + // + // falsyExpression() || someExpression(); + // + // the generated code is: + // + // false && someExpression(); + // + const keepRight = + (expression.operator === "&&" && bool) || + (expression.operator === "||" && !bool); + + if (param.isBoolean() || keepRight) { + // for case like + // + // return'development'===process.env.NODE_ENV&&'foo' + // + // we need a space before the bool to prevent result like + // + // returnfalse&&'foo' + // + const dep = new ConstDependency(` ${bool}`, param.range); + dep.loc = expression.loc; + parser.state.current.addDependency(dep); + } else { + parser.walkExpression(expression.left); + } + if (!keepRight) { + const dep = new ConstDependency( + "false", + expression.right.range + ); + dep.loc = expression.loc; + parser.state.current.addDependency(dep); + } + return keepRight; + } + } + } + ); + parser.hooks.evaluateIdentifier + .for("__resourceQuery") + .tap("ConstPlugin", expr => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + return ParserHelpers.evaluateToString( + getQuery(parser.state.module.resource) + )(expr); + }); + parser.hooks.expression + .for("__resourceQuery") + .tap("ConstPlugin", () => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + parser.state.current.addVariable( + "__resourceQuery", + JSON.stringify(getQuery(parser.state.module.resource)) + ); + return true; + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("ConstPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("ConstPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("ConstPlugin", handler); + } + ); + } +} + +module.exports = ConstPlugin; diff --git a/node_modules/webpack/lib/ContextExclusionPlugin.js b/node_modules/webpack/lib/ContextExclusionPlugin.js new file mode 100644 index 0000000..0b1dda0 --- /dev/null +++ b/node_modules/webpack/lib/ContextExclusionPlugin.js @@ -0,0 +1,28 @@ +"use strict"; + +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./ContextModuleFactory")} ContextModuleFactory */ + +class ContextExclusionPlugin { + /** + * @param {RegExp} negativeMatcher Matcher regular expression + */ + constructor(negativeMatcher) { + this.negativeMatcher = negativeMatcher; + } + + /** + * Apply the plugin + * @param {Compiler} compiler Webpack Compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.contextModuleFactory.tap("ContextExclusionPlugin", cmf => { + cmf.hooks.contextModuleFiles.tap("ContextExclusionPlugin", files => { + return files.filter(filePath => !this.negativeMatcher.test(filePath)); + }); + }); + } +} + +module.exports = ContextExclusionPlugin; diff --git a/node_modules/webpack/lib/ContextModule.js b/node_modules/webpack/lib/ContextModule.js new file mode 100644 index 0000000..f7fae13 --- /dev/null +++ b/node_modules/webpack/lib/ContextModule.js @@ -0,0 +1,872 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const util = require("util"); +const { OriginalSource, RawSource } = require("webpack-sources"); +const Module = require("./Module"); +const AsyncDependenciesBlock = require("./AsyncDependenciesBlock"); +const Template = require("./Template"); +const contextify = require("./util/identifier").contextify; + +/** @typedef {"sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"} ContextMode Context mode */ +/** @typedef {import("./dependencies/ContextElementDependency")} ContextElementDependency */ + +/** + * @callback ResolveDependenciesCallback + * @param {Error=} err + * @param {ContextElementDependency[]} dependencies + */ + +/** + * @callback ResolveDependencies + * @param {TODO} fs + * @param {TODO} options + * @param {ResolveDependenciesCallback} callback + */ + +class ContextModule extends Module { + // type ContextMode = "sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once" + // type ContextOptions = { resource: string, recursive: boolean, regExp: RegExp, addon?: string, mode?: ContextMode, chunkName?: string, include?: RegExp, exclude?: RegExp, groupOptions?: Object } + // resolveDependencies: (fs: FS, options: ContextOptions, (err: Error?, dependencies: Dependency[]) => void) => void + // options: ContextOptions + /** + * @param {ResolveDependencies} resolveDependencies function to get dependencies in this context + * @param {TODO} options options object + */ + constructor(resolveDependencies, options) { + let resource; + let resourceQuery; + const queryIdx = options.resource.indexOf("?"); + if (queryIdx >= 0) { + resource = options.resource.substr(0, queryIdx); + resourceQuery = options.resource.substr(queryIdx); + } else { + resource = options.resource; + resourceQuery = ""; + } + + super("javascript/dynamic", resource); + + // Info from Factory + this.resolveDependencies = resolveDependencies; + this.options = Object.assign({}, options, { + resource: resource, + resourceQuery: resourceQuery + }); + if (options.resolveOptions !== undefined) { + this.resolveOptions = options.resolveOptions; + } + + // Info from Build + this._contextDependencies = new Set([this.context]); + + if (typeof options.mode !== "string") { + throw new Error("options.mode is a required option"); + } + + this._identifier = this._createIdentifier(); + } + + updateCacheModule(module) { + this.resolveDependencies = module.resolveDependencies; + this.options = module.options; + this.resolveOptions = module.resolveOptions; + } + + prettyRegExp(regexString) { + // remove the "/" at the front and the beginning + // "/foo/" -> "foo" + return regexString.substring(1, regexString.length - 1); + } + + _createIdentifier() { + let identifier = this.context; + if (this.options.resourceQuery) { + identifier += ` ${this.options.resourceQuery}`; + } + if (this.options.mode) { + identifier += ` ${this.options.mode}`; + } + if (!this.options.recursive) { + identifier += " nonrecursive"; + } + if (this.options.addon) { + identifier += ` ${this.options.addon}`; + } + if (this.options.regExp) { + identifier += ` ${this.options.regExp}`; + } + if (this.options.include) { + identifier += ` include: ${this.options.include}`; + } + if (this.options.exclude) { + identifier += ` exclude: ${this.options.exclude}`; + } + if (this.options.groupOptions) { + identifier += ` groupOptions: ${JSON.stringify( + this.options.groupOptions + )}`; + } + if (this.options.namespaceObject === "strict") { + identifier += " strict namespace object"; + } else if (this.options.namespaceObject) { + identifier += " namespace object"; + } + + return identifier; + } + + identifier() { + return this._identifier; + } + + readableIdentifier(requestShortener) { + let identifier = requestShortener.shorten(this.context); + if (this.options.resourceQuery) { + identifier += ` ${this.options.resourceQuery}`; + } + if (this.options.mode) { + identifier += ` ${this.options.mode}`; + } + if (!this.options.recursive) { + identifier += " nonrecursive"; + } + if (this.options.addon) { + identifier += ` ${requestShortener.shorten(this.options.addon)}`; + } + if (this.options.regExp) { + identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`; + } + if (this.options.include) { + identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`; + } + if (this.options.exclude) { + identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`; + } + if (this.options.groupOptions) { + const groupOptions = this.options.groupOptions; + for (const key of Object.keys(groupOptions)) { + identifier += ` ${key}: ${groupOptions[key]}`; + } + } + if (this.options.namespaceObject === "strict") { + identifier += " strict namespace object"; + } else if (this.options.namespaceObject) { + identifier += " namespace object"; + } + + return identifier; + } + + libIdent(options) { + let identifier = contextify(options.context, this.context); + if (this.options.mode) { + identifier += ` ${this.options.mode}`; + } + if (this.options.recursive) { + identifier += " recursive"; + } + if (this.options.addon) { + identifier += ` ${contextify(options.context, this.options.addon)}`; + } + if (this.options.regExp) { + identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`; + } + if (this.options.include) { + identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`; + } + if (this.options.exclude) { + identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`; + } + + return identifier; + } + + needRebuild(fileTimestamps, contextTimestamps) { + const ts = contextTimestamps.get(this.context); + if (!ts) { + return true; + } + + return ts >= this.buildInfo.builtTime; + } + + build(options, compilation, resolver, fs, callback) { + this.built = true; + this.buildMeta = {}; + this.buildInfo = { + builtTime: Date.now(), + contextDependencies: this._contextDependencies + }; + this.resolveDependencies(fs, this.options, (err, dependencies) => { + if (err) return callback(err); + + // abort if something failed + // this will create an empty context + if (!dependencies) { + callback(); + return; + } + + // enhance dependencies with meta info + for (const dep of dependencies) { + dep.loc = { + name: dep.userRequest + }; + dep.request = this.options.addon + dep.request; + } + + if (this.options.mode === "sync" || this.options.mode === "eager") { + // if we have an sync or eager context + // just add all dependencies and continue + this.dependencies = dependencies; + } else if (this.options.mode === "lazy-once") { + // for the lazy-once mode create a new async dependency block + // and add that block to this context + if (dependencies.length > 0) { + const block = new AsyncDependenciesBlock( + Object.assign({}, this.options.groupOptions, { + name: this.options.chunkName + }), + this + ); + for (const dep of dependencies) { + block.addDependency(dep); + } + this.addBlock(block); + } + } else if ( + this.options.mode === "weak" || + this.options.mode === "async-weak" + ) { + // we mark all dependencies as weak + for (const dep of dependencies) { + dep.weak = true; + } + this.dependencies = dependencies; + } else if (this.options.mode === "lazy") { + // if we are lazy create a new async dependency block per dependency + // and add all blocks to this context + let index = 0; + for (const dep of dependencies) { + let chunkName = this.options.chunkName; + if (chunkName) { + if (!/\[(index|request)\]/.test(chunkName)) { + chunkName += "[index]"; + } + chunkName = chunkName.replace(/\[index\]/g, index++); + chunkName = chunkName.replace( + /\[request\]/g, + Template.toPath(dep.userRequest) + ); + } + const block = new AsyncDependenciesBlock( + Object.assign({}, this.options.groupOptions, { + name: chunkName + }), + dep.module, + dep.loc, + dep.userRequest + ); + block.addDependency(dep); + this.addBlock(block); + } + } else { + callback( + new Error(`Unsupported mode "${this.options.mode}" in context`) + ); + return; + } + callback(); + }); + } + + getUserRequestMap(dependencies) { + // if we filter first we get a new array + // therefor we dont need to create a clone of dependencies explicitly + // therefore the order of this is !important! + return dependencies + .filter(dependency => dependency.module) + .sort((a, b) => { + if (a.userRequest === b.userRequest) { + return 0; + } + return a.userRequest < b.userRequest ? -1 : 1; + }) + .reduce((map, dep) => { + map[dep.userRequest] = dep.module.id; + return map; + }, Object.create(null)); + } + + getFakeMap(dependencies) { + if (!this.options.namespaceObject) { + return 9; + } + // if we filter first we get a new array + // therefor we dont need to create a clone of dependencies explicitly + // therefore the order of this is !important! + let hasNonHarmony = false; + let hasNamespace = false; + let hasNamed = false; + const fakeMap = dependencies + .filter(dependency => dependency.module) + .sort((a, b) => { + return b.module.id - a.module.id; + }) + .reduce((map, dep) => { + const exportsType = + dep.module.buildMeta && dep.module.buildMeta.exportsType; + const id = dep.module.id; + if (!exportsType) { + map[id] = this.options.namespaceObject === "strict" ? 1 : 7; + hasNonHarmony = true; + } else if (exportsType === "namespace") { + map[id] = 9; + hasNamespace = true; + } else if (exportsType === "named") { + map[id] = 3; + hasNamed = true; + } + return map; + }, Object.create(null)); + if (!hasNamespace && hasNonHarmony && !hasNamed) { + return this.options.namespaceObject === "strict" ? 1 : 7; + } + if (hasNamespace && !hasNonHarmony && !hasNamed) { + return 9; + } + if (!hasNamespace && !hasNonHarmony && hasNamed) { + return 3; + } + if (!hasNamespace && !hasNonHarmony && !hasNamed) { + return 9; + } + return fakeMap; + } + + getFakeMapInitStatement(fakeMap) { + return typeof fakeMap === "object" + ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` + : ""; + } + + getReturn(type) { + if (type === 9) { + return "__webpack_require__(id)"; + } + return `__webpack_require__.t(id, ${type})`; + } + + getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") { + if (typeof fakeMap === "number") { + return `return ${this.getReturn(fakeMap)};`; + } + return `return __webpack_require__.t(id, ${fakeMapDataExpression})`; + } + + getSyncSource(dependencies, id) { + const map = this.getUserRequestMap(dependencies); + const fakeMap = this.getFakeMap(dependencies); + const returnModuleObject = this.getReturnModuleObjectSource(fakeMap); + + return `var map = ${JSON.stringify(map, null, "\t")}; +${this.getFakeMapInitStatement(fakeMap)} + +function webpackContext(req) { + var id = webpackContextResolve(req); + ${returnModuleObject} +} +function webpackContextResolve(req) { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; +} +webpackContext.keys = function webpackContextKeys() { + return Object.keys(map); +}; +webpackContext.resolve = webpackContextResolve; +module.exports = webpackContext; +webpackContext.id = ${JSON.stringify(id)};`; + } + + getWeakSyncSource(dependencies, id) { + const map = this.getUserRequestMap(dependencies); + const fakeMap = this.getFakeMap(dependencies); + const returnModuleObject = this.getReturnModuleObjectSource(fakeMap); + + return `var map = ${JSON.stringify(map, null, "\t")}; +${this.getFakeMapInitStatement(fakeMap)} + +function webpackContext(req) { + var id = webpackContextResolve(req); + if(!__webpack_require__.m[id]) { + var e = new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + ${returnModuleObject} +} +function webpackContextResolve(req) { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; +} +webpackContext.keys = function webpackContextKeys() { + return Object.keys(map); +}; +webpackContext.resolve = webpackContextResolve; +webpackContext.id = ${JSON.stringify(id)}; +module.exports = webpackContext;`; + } + + getAsyncWeakSource(dependencies, id) { + const map = this.getUserRequestMap(dependencies); + const fakeMap = this.getFakeMap(dependencies); + const returnModuleObject = this.getReturnModuleObjectSource(fakeMap); + + return `var map = ${JSON.stringify(map, null, "\t")}; +${this.getFakeMapInitStatement(fakeMap)} + +function webpackAsyncContext(req) { + return webpackAsyncContextResolve(req).then(function(id) { + if(!__webpack_require__.m[id]) { + var e = new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + ${returnModuleObject} + }); +} +function webpackAsyncContextResolve(req) { + // Here Promise.resolve().then() is used instead of new Promise() to prevent + // uncaught exception popping up in devtools + return Promise.resolve().then(function() { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; + }); +} +webpackAsyncContext.keys = function webpackAsyncContextKeys() { + return Object.keys(map); +}; +webpackAsyncContext.resolve = webpackAsyncContextResolve; +webpackAsyncContext.id = ${JSON.stringify(id)}; +module.exports = webpackAsyncContext;`; + } + + getEagerSource(dependencies, id) { + const map = this.getUserRequestMap(dependencies); + const fakeMap = this.getFakeMap(dependencies); + const thenFunction = + fakeMap !== 9 + ? `function(id) { + ${this.getReturnModuleObjectSource(fakeMap)} + }` + : "__webpack_require__"; + return `var map = ${JSON.stringify(map, null, "\t")}; +${this.getFakeMapInitStatement(fakeMap)} + +function webpackAsyncContext(req) { + return webpackAsyncContextResolve(req).then(${thenFunction}); +} +function webpackAsyncContextResolve(req) { + // Here Promise.resolve().then() is used instead of new Promise() to prevent + // uncaught exception popping up in devtools + return Promise.resolve().then(function() { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; + }); +} +webpackAsyncContext.keys = function webpackAsyncContextKeys() { + return Object.keys(map); +}; +webpackAsyncContext.resolve = webpackAsyncContextResolve; +webpackAsyncContext.id = ${JSON.stringify(id)}; +module.exports = webpackAsyncContext;`; + } + + getLazyOnceSource(block, dependencies, id, runtimeTemplate) { + const promise = runtimeTemplate.blockPromise({ + block, + message: "lazy-once context" + }); + const map = this.getUserRequestMap(dependencies); + const fakeMap = this.getFakeMap(dependencies); + const thenFunction = + fakeMap !== 9 + ? `function(id) { + ${this.getReturnModuleObjectSource(fakeMap)}; + }` + : "__webpack_require__"; + + return `var map = ${JSON.stringify(map, null, "\t")}; +${this.getFakeMapInitStatement(fakeMap)} + +function webpackAsyncContext(req) { + return webpackAsyncContextResolve(req).then(${thenFunction}); +} +function webpackAsyncContextResolve(req) { + return ${promise}.then(function() { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + return map[req]; + }); +} +webpackAsyncContext.keys = function webpackAsyncContextKeys() { + return Object.keys(map); +}; +webpackAsyncContext.resolve = webpackAsyncContextResolve; +webpackAsyncContext.id = ${JSON.stringify(id)}; +module.exports = webpackAsyncContext;`; + } + + getLazySource(blocks, id) { + let hasMultipleOrNoChunks = false; + let hasNoChunk = true; + const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0])); + const hasFakeMap = typeof fakeMap === "object"; + const map = blocks + .filter(block => block.dependencies[0].module) + .map(block => { + const chunks = block.chunkGroup ? block.chunkGroup.chunks : []; + if (chunks.length > 0) { + hasNoChunk = false; + } + if (chunks.length !== 1) { + hasMultipleOrNoChunks = true; + } + return { + dependency: block.dependencies[0], + block: block, + userRequest: block.dependencies[0].userRequest, + chunks + }; + }) + .sort((a, b) => { + if (a.userRequest === b.userRequest) return 0; + return a.userRequest < b.userRequest ? -1 : 1; + }) + .reduce((map, item) => { + const chunks = item.chunks; + + if (hasNoChunk && !hasFakeMap) { + map[item.userRequest] = item.dependency.module.id; + } else { + const arrayStart = [item.dependency.module.id]; + if (typeof fakeMap === "object") { + arrayStart.push(fakeMap[item.dependency.module.id]); + } + map[item.userRequest] = arrayStart.concat( + chunks.map(chunk => chunk.id) + ); + } + + return map; + }, Object.create(null)); + + const shortMode = hasNoChunk && !hasFakeMap; + const chunksStartPosition = hasFakeMap ? 2 : 1; + const requestPrefix = hasNoChunk + ? "Promise.resolve()" + : hasMultipleOrNoChunks + ? `Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))` + : `__webpack_require__.e(ids[${chunksStartPosition}])`; + const returnModuleObject = this.getReturnModuleObjectSource( + fakeMap, + shortMode ? "invalid" : "ids[1]" + ); + + const webpackAsyncContext = + requestPrefix === "Promise.resolve()" + ? `${shortMode ? "" : ""} +function webpackAsyncContext(req) { + return Promise.resolve().then(function() { + if(!__webpack_require__.o(map, req)) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + } + + ${shortMode ? "var id = map[req];" : "var ids = map[req], id = ids[0];"} + ${returnModuleObject} + }); +}` + : `function webpackAsyncContext(req) { + if(!__webpack_require__.o(map, req)) { + return Promise.resolve().then(function() { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + }); + } + + var ids = map[req], id = ids[0]; + return ${requestPrefix}.then(function() { + ${returnModuleObject} + }); +}`; + + return `var map = ${JSON.stringify(map, null, "\t")}; +${webpackAsyncContext} +webpackAsyncContext.keys = function webpackAsyncContextKeys() { + return Object.keys(map); +}; +webpackAsyncContext.id = ${JSON.stringify(id)}; +module.exports = webpackAsyncContext;`; + } + + getSourceForEmptyContext(id) { + return `function webpackEmptyContext(req) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; +} +webpackEmptyContext.keys = function() { return []; }; +webpackEmptyContext.resolve = webpackEmptyContext; +module.exports = webpackEmptyContext; +webpackEmptyContext.id = ${JSON.stringify(id)};`; + } + + getSourceForEmptyAsyncContext(id) { + return `function webpackEmptyAsyncContext(req) { + // Here Promise.resolve().then() is used instead of new Promise() to prevent + // uncaught exception popping up in devtools + return Promise.resolve().then(function() { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; + }); +} +webpackEmptyAsyncContext.keys = function() { return []; }; +webpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext; +module.exports = webpackEmptyAsyncContext; +webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`; + } + + getSourceString(asyncMode, runtimeTemplate) { + if (asyncMode === "lazy") { + if (this.blocks && this.blocks.length > 0) { + return this.getLazySource(this.blocks, this.id); + } + return this.getSourceForEmptyAsyncContext(this.id); + } + if (asyncMode === "eager") { + if (this.dependencies && this.dependencies.length > 0) { + return this.getEagerSource(this.dependencies, this.id); + } + return this.getSourceForEmptyAsyncContext(this.id); + } + if (asyncMode === "lazy-once") { + const block = this.blocks[0]; + if (block) { + return this.getLazyOnceSource( + block, + block.dependencies, + this.id, + runtimeTemplate + ); + } + return this.getSourceForEmptyAsyncContext(this.id); + } + if (asyncMode === "async-weak") { + if (this.dependencies && this.dependencies.length > 0) { + return this.getAsyncWeakSource(this.dependencies, this.id); + } + return this.getSourceForEmptyAsyncContext(this.id); + } + if (asyncMode === "weak") { + if (this.dependencies && this.dependencies.length > 0) { + return this.getWeakSyncSource(this.dependencies, this.id); + } + } + if (this.dependencies && this.dependencies.length > 0) { + return this.getSyncSource(this.dependencies, this.id); + } + return this.getSourceForEmptyContext(this.id); + } + + getSource(sourceString) { + if (this.useSourceMap) { + return new OriginalSource(sourceString, this.identifier()); + } + return new RawSource(sourceString); + } + + source(dependencyTemplates, runtimeTemplate) { + return this.getSource( + this.getSourceString(this.options.mode, runtimeTemplate) + ); + } + + size() { + // base penalty + const initialSize = 160; + + // if we dont have dependencies we stop here. + return this.dependencies.reduce((size, dependency) => { + const element = /** @type {ContextElementDependency} */ (dependency); + return size + 5 + element.userRequest.length; + }, initialSize); + } +} + +// TODO remove in webpack 5 +Object.defineProperty(ContextModule.prototype, "recursive", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @returns {boolean} is recursive + */ + function() { + return this.options.recursive; + }, + "ContextModule.recursive has been moved to ContextModule.options.recursive" + ), + set: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @param {boolean} value is recursive + * @returns {void} + */ + function(value) { + this.options.recursive = value; + }, + "ContextModule.recursive has been moved to ContextModule.options.recursive" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(ContextModule.prototype, "regExp", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @returns {RegExp} regular expression + */ + function() { + return this.options.regExp; + }, + "ContextModule.regExp has been moved to ContextModule.options.regExp" + ), + set: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @param {RegExp} value Regular expression + * @returns {void} + */ + function(value) { + this.options.regExp = value; + }, + "ContextModule.regExp has been moved to ContextModule.options.regExp" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(ContextModule.prototype, "addon", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @returns {string} addon + */ + function() { + return this.options.addon; + }, + "ContextModule.addon has been moved to ContextModule.options.addon" + ), + set: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @param {string} value addon + * @returns {void} + */ + function(value) { + this.options.addon = value; + }, + "ContextModule.addon has been moved to ContextModule.options.addon" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(ContextModule.prototype, "async", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @returns {boolean} is async + */ + function() { + return this.options.mode; + }, + "ContextModule.async has been moved to ContextModule.options.mode" + ), + set: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @param {ContextMode} value Context mode + * @returns {void} + */ + function(value) { + this.options.mode = value; + }, + "ContextModule.async has been moved to ContextModule.options.mode" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(ContextModule.prototype, "chunkName", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @returns {string} chunk name + */ + function() { + return this.options.chunkName; + }, + "ContextModule.chunkName has been moved to ContextModule.options.chunkName" + ), + set: util.deprecate( + /** + * @deprecated + * @this {ContextModule} + * @param {string} value chunk name + * @returns {void} + */ + function(value) { + this.options.chunkName = value; + }, + "ContextModule.chunkName has been moved to ContextModule.options.chunkName" + ) +}); + +module.exports = ContextModule; diff --git a/node_modules/webpack/lib/ContextModuleFactory.js b/node_modules/webpack/lib/ContextModuleFactory.js new file mode 100644 index 0000000..f594112 --- /dev/null +++ b/node_modules/webpack/lib/ContextModuleFactory.js @@ -0,0 +1,262 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const asyncLib = require("neo-async"); +const path = require("path"); + +const { + Tapable, + AsyncSeriesWaterfallHook, + SyncWaterfallHook +} = require("tapable"); +const ContextModule = require("./ContextModule"); +const ContextElementDependency = require("./dependencies/ContextElementDependency"); + +/** @typedef {import("./Module")} Module */ + +const EMPTY_RESOLVE_OPTIONS = {}; + +module.exports = class ContextModuleFactory extends Tapable { + constructor(resolverFactory) { + super(); + this.hooks = { + /** @type {AsyncSeriesWaterfallHook<TODO>} */ + beforeResolve: new AsyncSeriesWaterfallHook(["data"]), + /** @type {AsyncSeriesWaterfallHook<TODO>} */ + afterResolve: new AsyncSeriesWaterfallHook(["data"]), + /** @type {SyncWaterfallHook<string[]>} */ + contextModuleFiles: new SyncWaterfallHook(["files"]), + /** @type {SyncWaterfallHook<TODO[]>} */ + alternatives: new AsyncSeriesWaterfallHook(["modules"]) + }; + this._pluginCompat.tap("ContextModuleFactory", options => { + switch (options.name) { + case "before-resolve": + case "after-resolve": + case "alternatives": + options.async = true; + break; + } + }); + this.resolverFactory = resolverFactory; + } + + create(data, callback) { + const context = data.context; + const dependencies = data.dependencies; + const resolveOptions = data.resolveOptions; + const dependency = dependencies[0]; + this.hooks.beforeResolve.callAsync( + Object.assign( + { + context: context, + dependencies: dependencies, + resolveOptions + }, + dependency.options + ), + (err, beforeResolveResult) => { + if (err) return callback(err); + + // Ignored + if (!beforeResolveResult) return callback(); + + const context = beforeResolveResult.context; + const request = beforeResolveResult.request; + const resolveOptions = beforeResolveResult.resolveOptions; + + let loaders, + resource, + loadersPrefix = ""; + const idx = request.lastIndexOf("!"); + if (idx >= 0) { + let loadersRequest = request.substr(0, idx + 1); + let i; + for ( + i = 0; + i < loadersRequest.length && loadersRequest[i] === "!"; + i++ + ) { + loadersPrefix += "!"; + } + loadersRequest = loadersRequest + .substr(i) + .replace(/!+$/, "") + .replace(/!!+/g, "!"); + if (loadersRequest === "") { + loaders = []; + } else { + loaders = loadersRequest.split("!"); + } + resource = request.substr(idx + 1); + } else { + loaders = []; + resource = request; + } + + const contextResolver = this.resolverFactory.get( + "context", + resolveOptions || EMPTY_RESOLVE_OPTIONS + ); + const loaderResolver = this.resolverFactory.get( + "loader", + EMPTY_RESOLVE_OPTIONS + ); + + asyncLib.parallel( + [ + callback => { + contextResolver.resolve( + {}, + context, + resource, + {}, + (err, result) => { + if (err) return callback(err); + callback(null, result); + } + ); + }, + callback => { + asyncLib.map( + loaders, + (loader, callback) => { + loaderResolver.resolve( + {}, + context, + loader, + {}, + (err, result) => { + if (err) return callback(err); + callback(null, result); + } + ); + }, + callback + ); + } + ], + (err, result) => { + if (err) return callback(err); + + this.hooks.afterResolve.callAsync( + Object.assign( + { + addon: + loadersPrefix + + result[1].join("!") + + (result[1].length > 0 ? "!" : ""), + resource: result[0], + resolveDependencies: this.resolveDependencies.bind(this) + }, + beforeResolveResult + ), + (err, result) => { + if (err) return callback(err); + + // Ignored + if (!result) return callback(); + + return callback( + null, + new ContextModule(result.resolveDependencies, result) + ); + } + ); + } + ); + } + ); + } + + resolveDependencies(fs, options, callback) { + const cmf = this; + let resource = options.resource; + let resourceQuery = options.resourceQuery; + let recursive = options.recursive; + let regExp = options.regExp; + let include = options.include; + let exclude = options.exclude; + if (!regExp || !resource) return callback(null, []); + + const addDirectory = (directory, callback) => { + fs.readdir(directory, (err, files) => { + if (err) return callback(err); + files = cmf.hooks.contextModuleFiles.call(files); + if (!files || files.length === 0) return callback(null, []); + asyncLib.map( + files.filter(p => p.indexOf(".") !== 0), + (segment, callback) => { + const subResource = path.join(directory, segment); + + if (!exclude || !subResource.match(exclude)) { + fs.stat(subResource, (err, stat) => { + if (err) { + if (err.code === "ENOENT") { + // ENOENT is ok here because the file may have been deleted between + // the readdir and stat calls. + return callback(); + } else { + return callback(err); + } + } + + if (stat.isDirectory()) { + if (!recursive) return callback(); + addDirectory.call(this, subResource, callback); + } else if ( + stat.isFile() && + (!include || subResource.match(include)) + ) { + const obj = { + context: resource, + request: + "." + + subResource.substr(resource.length).replace(/\\/g, "/") + }; + + this.hooks.alternatives.callAsync( + [obj], + (err, alternatives) => { + if (err) return callback(err); + alternatives = alternatives + .filter(obj => regExp.test(obj.request)) + .map(obj => { + const dep = new ContextElementDependency( + obj.request + resourceQuery, + obj.request + ); + dep.optional = true; + return dep; + }); + callback(null, alternatives); + } + ); + } else { + callback(); + } + }); + } else { + callback(); + } + }, + (err, result) => { + if (err) return callback(err); + + if (!result) return callback(null, []); + + callback( + null, + result.filter(Boolean).reduce((a, i) => a.concat(i), []) + ); + } + ); + }); + }; + + addDirectory(resource, callback); + } +}; diff --git a/node_modules/webpack/lib/ContextReplacementPlugin.js b/node_modules/webpack/lib/ContextReplacementPlugin.js new file mode 100644 index 0000000..5523c8a --- /dev/null +++ b/node_modules/webpack/lib/ContextReplacementPlugin.js @@ -0,0 +1,133 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const ContextElementDependency = require("./dependencies/ContextElementDependency"); + +class ContextReplacementPlugin { + constructor( + resourceRegExp, + newContentResource, + newContentRecursive, + newContentRegExp + ) { + this.resourceRegExp = resourceRegExp; + + if (typeof newContentResource === "function") { + this.newContentCallback = newContentResource; + } else if ( + typeof newContentResource === "string" && + typeof newContentRecursive === "object" + ) { + this.newContentResource = newContentResource; + this.newContentCreateContextMap = (fs, callback) => { + callback(null, newContentRecursive); + }; + } else if ( + typeof newContentResource === "string" && + typeof newContentRecursive === "function" + ) { + this.newContentResource = newContentResource; + this.newContentCreateContextMap = newContentRecursive; + } else { + if (typeof newContentResource !== "string") { + newContentRegExp = newContentRecursive; + newContentRecursive = newContentResource; + newContentResource = undefined; + } + if (typeof newContentRecursive !== "boolean") { + newContentRegExp = newContentRecursive; + newContentRecursive = undefined; + } + this.newContentResource = newContentResource; + this.newContentRecursive = newContentRecursive; + this.newContentRegExp = newContentRegExp; + } + } + + apply(compiler) { + const resourceRegExp = this.resourceRegExp; + const newContentCallback = this.newContentCallback; + const newContentResource = this.newContentResource; + const newContentRecursive = this.newContentRecursive; + const newContentRegExp = this.newContentRegExp; + const newContentCreateContextMap = this.newContentCreateContextMap; + + compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", cmf => { + cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", result => { + if (!result) return; + if (resourceRegExp.test(result.request)) { + if (newContentResource !== undefined) { + result.request = newContentResource; + } + if (newContentRecursive !== undefined) { + result.recursive = newContentRecursive; + } + if (newContentRegExp !== undefined) { + result.regExp = newContentRegExp; + } + if (typeof newContentCallback === "function") { + newContentCallback(result); + } else { + for (const d of result.dependencies) { + if (d.critical) d.critical = false; + } + } + } + return result; + }); + cmf.hooks.afterResolve.tap("ContextReplacementPlugin", result => { + if (!result) return; + if (resourceRegExp.test(result.resource)) { + if (newContentResource !== undefined) { + result.resource = path.resolve(result.resource, newContentResource); + } + if (newContentRecursive !== undefined) { + result.recursive = newContentRecursive; + } + if (newContentRegExp !== undefined) { + result.regExp = newContentRegExp; + } + if (typeof newContentCreateContextMap === "function") { + result.resolveDependencies = createResolveDependenciesFromContextMap( + newContentCreateContextMap + ); + } + if (typeof newContentCallback === "function") { + const origResource = result.resource; + newContentCallback(result); + if (result.resource !== origResource) { + result.resource = path.resolve(origResource, result.resource); + } + } else { + for (const d of result.dependencies) { + if (d.critical) d.critical = false; + } + } + } + return result; + }); + }); + } +} + +const createResolveDependenciesFromContextMap = createContextMap => { + const resolveDependenciesFromContextMap = (fs, options, callback) => { + createContextMap(fs, (err, map) => { + if (err) return callback(err); + const dependencies = Object.keys(map).map(key => { + return new ContextElementDependency( + map[key] + options.resourceQuery, + key + ); + }); + callback(null, dependencies); + }); + }; + return resolveDependenciesFromContextMap; +}; + +module.exports = ContextReplacementPlugin; diff --git a/node_modules/webpack/lib/DefinePlugin.js b/node_modules/webpack/lib/DefinePlugin.js new file mode 100644 index 0000000..ceb4c84 --- /dev/null +++ b/node_modules/webpack/lib/DefinePlugin.js @@ -0,0 +1,289 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ConstDependency = require("./dependencies/ConstDependency"); +const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); +const ParserHelpers = require("./ParserHelpers"); +const NullFactory = require("./NullFactory"); + +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./Parser")} Parser */ +/** @typedef {null|undefined|RegExp|Function|string|number} CodeValuePrimitive */ +/** @typedef {CodeValuePrimitive|Record<string, CodeValuePrimitive>|RuntimeValue} CodeValue */ + +class RuntimeValue { + constructor(fn, fileDependencies) { + this.fn = fn; + this.fileDependencies = fileDependencies || []; + } + + exec(parser) { + if (this.fileDependencies === true) { + parser.state.module.buildInfo.cacheable = false; + } else { + for (const fileDependency of this.fileDependencies) { + parser.state.module.buildInfo.fileDependencies.add(fileDependency); + } + } + + return this.fn({ module: parser.state.module }); + } +} + +const stringifyObj = (obj, parser) => { + return ( + "Object({" + + Object.keys(obj) + .map(key => { + const code = obj[key]; + return JSON.stringify(key) + ":" + toCode(code, parser); + }) + .join(",") + + "})" + ); +}; + +/** + * Convert code to a string that evaluates + * @param {CodeValue} code Code to evaluate + * @param {Parser} parser Parser + * @returns {string} code converted to string that evaluates + */ +const toCode = (code, parser) => { + if (code === null) { + return "null"; + } + if (code === undefined) { + return "undefined"; + } + if (code instanceof RuntimeValue) { + return toCode(code.exec(parser), parser); + } + if (code instanceof RegExp && code.toString) { + return code.toString(); + } + if (typeof code === "function" && code.toString) { + return "(" + code.toString() + ")"; + } + if (typeof code === "object") { + return stringifyObj(code, parser); + } + return code + ""; +}; + +class DefinePlugin { + /** + * Create a new define plugin + * @param {Record<string, CodeValue>} definitions A map of global object definitions + */ + constructor(definitions) { + this.definitions = definitions; + } + + static runtimeValue(fn, fileDependencies) { + return new RuntimeValue(fn, fileDependencies); + } + + /** + * Apply the plugin + * @param {Compiler} compiler Webpack compiler + * @returns {void} + */ + apply(compiler) { + const definitions = this.definitions; + compiler.hooks.compilation.tap( + "DefinePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + /** + * Handler + * @param {Parser} parser Parser + * @returns {void} + */ + const handler = parser => { + /** + * Walk definitions + * @param {Object} definitions Definitions map + * @param {string} prefix Prefix string + * @returns {void} + */ + const walkDefinitions = (definitions, prefix) => { + Object.keys(definitions).forEach(key => { + const code = definitions[key]; + if ( + code && + typeof code === "object" && + !(code instanceof RuntimeValue) && + !(code instanceof RegExp) + ) { + walkDefinitions(code, prefix + key + "."); + applyObjectDefine(prefix + key, code); + return; + } + applyDefineKey(prefix, key); + applyDefine(prefix + key, code); + }); + }; + + /** + * Apply define key + * @param {string} prefix Prefix + * @param {string} key Key + * @returns {void} + */ + const applyDefineKey = (prefix, key) => { + const splittedKey = key.split("."); + splittedKey.slice(1).forEach((_, i) => { + const fullKey = prefix + splittedKey.slice(0, i + 1).join("."); + parser.hooks.canRename + .for(fullKey) + .tap("DefinePlugin", ParserHelpers.approve); + }); + }; + + /** + * Apply Code + * @param {string} key Key + * @param {CodeValue} code Code + * @returns {void} + */ + const applyDefine = (key, code) => { + const isTypeof = /^typeof\s+/.test(key); + if (isTypeof) key = key.replace(/^typeof\s+/, ""); + let recurse = false; + let recurseTypeof = false; + if (!isTypeof) { + parser.hooks.canRename + .for(key) + .tap("DefinePlugin", ParserHelpers.approve); + parser.hooks.evaluateIdentifier + .for(key) + .tap("DefinePlugin", expr => { + /** + * this is needed in case there is a recursion in the DefinePlugin + * to prevent an endless recursion + * e.g.: new DefinePlugin({ + * "a": "b", + * "b": "a" + * }); + */ + if (recurse) return; + recurse = true; + const res = parser.evaluate(toCode(code, parser)); + recurse = false; + res.setRange(expr.range); + return res; + }); + parser.hooks.expression.for(key).tap("DefinePlugin", expr => { + const strCode = toCode(code, parser); + if (/__webpack_require__/.test(strCode)) { + return ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + strCode + )(expr); + } else { + return ParserHelpers.toConstantDependency( + parser, + strCode + )(expr); + } + }); + } + parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => { + /** + * this is needed in case there is a recursion in the DefinePlugin + * to prevent an endless recursion + * e.g.: new DefinePlugin({ + * "typeof a": "typeof b", + * "typeof b": "typeof a" + * }); + */ + if (recurseTypeof) return; + recurseTypeof = true; + const typeofCode = isTypeof + ? toCode(code, parser) + : "typeof (" + toCode(code, parser) + ")"; + const res = parser.evaluate(typeofCode); + recurseTypeof = false; + res.setRange(expr.range); + return res; + }); + parser.hooks.typeof.for(key).tap("DefinePlugin", expr => { + const typeofCode = isTypeof + ? toCode(code, parser) + : "typeof (" + toCode(code, parser) + ")"; + const res = parser.evaluate(typeofCode); + if (!res.isString()) return; + return ParserHelpers.toConstantDependency( + parser, + JSON.stringify(res.string) + ).bind(parser)(expr); + }); + }; + + /** + * Apply Object + * @param {string} key Key + * @param {Object} obj Object + * @returns {void} + */ + const applyObjectDefine = (key, obj) => { + parser.hooks.canRename + .for(key) + .tap("DefinePlugin", ParserHelpers.approve); + parser.hooks.evaluateIdentifier + .for(key) + .tap("DefinePlugin", expr => + new BasicEvaluatedExpression().setTruthy().setRange(expr.range) + ); + parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => { + return ParserHelpers.evaluateToString("object")(expr); + }); + parser.hooks.expression.for(key).tap("DefinePlugin", expr => { + const strCode = stringifyObj(obj, parser); + + if (/__webpack_require__/.test(strCode)) { + return ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + strCode + )(expr); + } else { + return ParserHelpers.toConstantDependency( + parser, + strCode + )(expr); + } + }); + parser.hooks.typeof.for(key).tap("DefinePlugin", expr => { + return ParserHelpers.toConstantDependency( + parser, + JSON.stringify("object") + )(expr); + }); + }; + + walkDefinitions(definitions, ""); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("DefinePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("DefinePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("DefinePlugin", handler); + } + ); + } +} +module.exports = DefinePlugin; diff --git a/node_modules/webpack/lib/DelegatedModule.js b/node_modules/webpack/lib/DelegatedModule.js new file mode 100644 index 0000000..170ceca --- /dev/null +++ b/node_modules/webpack/lib/DelegatedModule.js @@ -0,0 +1,114 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { OriginalSource, RawSource } = require("webpack-sources"); + +const Module = require("./Module"); +const WebpackMissingModule = require("./dependencies/WebpackMissingModule"); +const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency"); +const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency"); + +/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */ +/** @typedef {import("./util/createHash").Hash} Hash */ + +class DelegatedModule extends Module { + constructor(sourceRequest, data, type, userRequest, originalRequest) { + super("javascript/dynamic", null); + + // Info from Factory + this.sourceRequest = sourceRequest; + this.request = data.id; + this.type = type; + this.userRequest = userRequest; + this.originalRequest = originalRequest; + this.delegateData = data; + + // Build info + this.delegatedSourceDependency = undefined; + } + + libIdent(options) { + return typeof this.originalRequest === "string" + ? this.originalRequest + : this.originalRequest.libIdent(options); + } + + identifier() { + return `delegated ${JSON.stringify(this.request)} from ${ + this.sourceRequest + }`; + } + + readableIdentifier() { + return `delegated ${this.userRequest} from ${this.sourceRequest}`; + } + + needRebuild() { + return false; + } + + build(options, compilation, resolver, fs, callback) { + this.built = true; + this.buildMeta = Object.assign({}, this.delegateData.buildMeta); + this.buildInfo = {}; + this.delegatedSourceDependency = new DelegatedSourceDependency( + this.sourceRequest + ); + this.addDependency(this.delegatedSourceDependency); + this.addDependency( + new DelegatedExportsDependency(this, this.delegateData.exports || true) + ); + callback(); + } + + source(depTemplates, runtime) { + const dep = /** @type {DelegatedSourceDependency} */ (this.dependencies[0]); + const sourceModule = dep.module; + let str; + + if (!sourceModule) { + str = WebpackMissingModule.moduleCode(this.sourceRequest); + } else { + str = `module.exports = (${runtime.moduleExports({ + module: sourceModule, + request: dep.request + })})`; + + switch (this.type) { + case "require": + str += `(${JSON.stringify(this.request)})`; + break; + case "object": + str += `[${JSON.stringify(this.request)}]`; + break; + } + + str += ";"; + } + + if (this.useSourceMap) { + return new OriginalSource(str, this.identifier()); + } else { + return new RawSource(str); + } + } + + size() { + return 42; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update(this.type); + hash.update(JSON.stringify(this.request)); + super.updateHash(hash); + } +} + +module.exports = DelegatedModule; diff --git a/node_modules/webpack/lib/DelegatedModuleFactoryPlugin.js b/node_modules/webpack/lib/DelegatedModuleFactoryPlugin.js new file mode 100644 index 0000000..a0a05a4 --- /dev/null +++ b/node_modules/webpack/lib/DelegatedModuleFactoryPlugin.js @@ -0,0 +1,95 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DelegatedModule = require("./DelegatedModule"); + +// options.source +// options.type +// options.context +// options.scope +// options.content +class DelegatedModuleFactoryPlugin { + constructor(options) { + this.options = options; + options.type = options.type || "require"; + options.extensions = options.extensions || [ + "", + ".wasm", + ".mjs", + ".js", + ".json" + ]; + } + + apply(normalModuleFactory) { + const scope = this.options.scope; + if (scope) { + normalModuleFactory.hooks.factory.tap( + "DelegatedModuleFactoryPlugin", + factory => (data, callback) => { + const dependency = data.dependencies[0]; + const request = dependency.request; + if (request && request.indexOf(scope + "/") === 0) { + const innerRequest = "." + request.substr(scope.length); + let resolved; + if (innerRequest in this.options.content) { + resolved = this.options.content[innerRequest]; + return callback( + null, + new DelegatedModule( + this.options.source, + resolved, + this.options.type, + innerRequest, + request + ) + ); + } + for (let i = 0; i < this.options.extensions.length; i++) { + const extension = this.options.extensions[i]; + const requestPlusExt = innerRequest + extension; + if (requestPlusExt in this.options.content) { + resolved = this.options.content[requestPlusExt]; + return callback( + null, + new DelegatedModule( + this.options.source, + resolved, + this.options.type, + requestPlusExt, + request + extension + ) + ); + } + } + } + return factory(data, callback); + } + ); + } else { + normalModuleFactory.hooks.module.tap( + "DelegatedModuleFactoryPlugin", + module => { + if (module.libIdent) { + const request = module.libIdent(this.options); + if (request && request in this.options.content) { + const resolved = this.options.content[request]; + return new DelegatedModule( + this.options.source, + resolved, + this.options.type, + request, + module + ); + } + } + return module; + } + ); + } + } +} +module.exports = DelegatedModuleFactoryPlugin; diff --git a/node_modules/webpack/lib/DelegatedPlugin.js b/node_modules/webpack/lib/DelegatedPlugin.js new file mode 100644 index 0000000..714eb85 --- /dev/null +++ b/node_modules/webpack/lib/DelegatedPlugin.js @@ -0,0 +1,39 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin"); +const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency"); +const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency"); +const NullFactory = require("./NullFactory"); + +class DelegatedPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "DelegatedPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + DelegatedSourceDependency, + normalModuleFactory + ); + compilation.dependencyFactories.set( + DelegatedExportsDependency, + new NullFactory() + ); + } + ); + + compiler.hooks.compile.tap("DelegatedPlugin", ({ normalModuleFactory }) => { + new DelegatedModuleFactoryPlugin(this.options).apply(normalModuleFactory); + }); + } +} + +module.exports = DelegatedPlugin; diff --git a/node_modules/webpack/lib/DependenciesBlock.js b/node_modules/webpack/lib/DependenciesBlock.js new file mode 100644 index 0000000..142f3ea --- /dev/null +++ b/node_modules/webpack/lib/DependenciesBlock.js @@ -0,0 +1,124 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const DependenciesBlockVariable = require("./DependenciesBlockVariable"); + +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./Dependency")} Dependency */ +/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ +/** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */ +/** @typedef {(d: Dependency) => boolean} DependencyFilterFunction */ +/** @typedef {import("./util/createHash").Hash} Hash */ + +class DependenciesBlock { + constructor() { + /** @type {Dependency[]} */ + this.dependencies = []; + /** @type {AsyncDependenciesBlock[]} */ + this.blocks = []; + /** @type {DependenciesBlockVariable[]} */ + this.variables = []; + } + + /** + * Adds a DependencyBlock to DependencyBlock relationship. + * This is used for when a Module has a AsyncDependencyBlock tie (for code-splitting) + * + * @param {AsyncDependenciesBlock} block block being added + * @returns {void} + */ + addBlock(block) { + this.blocks.push(block); + block.parent = this; + } + + /** + * @param {string} name name of dependency + * @param {string} expression expression string for variable + * @param {Dependency[]} dependencies dependency instances tied to variable + * @returns {void} + */ + addVariable(name, expression, dependencies) { + for (let v of this.variables) { + if (v.name === name && v.expression === expression) { + return; + } + } + this.variables.push( + new DependenciesBlockVariable(name, expression, dependencies) + ); + } + + /** + * @param {Dependency} dependency dependency being tied to block. + * This is an "edge" pointing to another "node" on module graph. + * @returns {void} + */ + addDependency(dependency) { + this.dependencies.push(dependency); + } + + /** + * @param {Dependency} dependency dependency being removed + * @returns {void} + */ + removeDependency(dependency) { + const idx = this.dependencies.indexOf(dependency); + if (idx >= 0) { + this.dependencies.splice(idx, 1); + } + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + for (const dep of this.dependencies) dep.updateHash(hash); + for (const block of this.blocks) block.updateHash(hash); + for (const variable of this.variables) variable.updateHash(hash); + } + + disconnect() { + for (const dep of this.dependencies) dep.disconnect(); + for (const block of this.blocks) block.disconnect(); + for (const variable of this.variables) variable.disconnect(); + } + + unseal() { + for (const block of this.blocks) block.unseal(); + } + + /** + * @param {DependencyFilterFunction} filter filter function for dependencies, gets passed all dependency ties from current instance + * @returns {boolean} returns boolean for filter + */ + hasDependencies(filter) { + if (filter) { + for (const dep of this.dependencies) { + if (filter(dep)) return true; + } + } else { + if (this.dependencies.length > 0) { + return true; + } + } + + for (const block of this.blocks) { + if (block.hasDependencies(filter)) return true; + } + for (const variable of this.variables) { + if (variable.hasDependencies(filter)) return true; + } + return false; + } + + sortItems() { + for (const block of this.blocks) block.sortItems(); + } +} + +module.exports = DependenciesBlock; diff --git a/node_modules/webpack/lib/DependenciesBlockVariable.js b/node_modules/webpack/lib/DependenciesBlockVariable.js new file mode 100644 index 0000000..c4ed916 --- /dev/null +++ b/node_modules/webpack/lib/DependenciesBlockVariable.js @@ -0,0 +1,72 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { RawSource, ReplaceSource } = require("webpack-sources"); + +/** @typedef {import("./Dependency")} Dependency */ +/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */ +/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ +/** @typedef {import("./util/createHash").Hash} Hash */ +/** @typedef {(d: Dependency) => boolean} DependencyFilterFunction */ +/** @typedef {Map<Function, DependencyTemplate>} DependencyTemplates */ + +class DependenciesBlockVariable { + /** + * Creates an instance of DependenciesBlockVariable. + * @param {string} name name of DependenciesBlockVariable + * @param {string} expression expression string + * @param {Dependency[]=} dependencies dependencies tied to this varaiable + */ + constructor(name, expression, dependencies) { + this.name = name; + this.expression = expression; + this.dependencies = dependencies || []; + } + + /** + * @param {Hash} hash hash for instance to update + * @returns {void} + */ + updateHash(hash) { + hash.update(this.name); + hash.update(this.expression); + for (const d of this.dependencies) { + d.updateHash(hash); + } + } + + /** + * @param {DependencyTemplates} dependencyTemplates Dependency constructors and templates Map. + * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate to generate expression souce + * @returns {ReplaceSource} returns constructed source for expression via templates + */ + expressionSource(dependencyTemplates, runtimeTemplate) { + const source = new ReplaceSource(new RawSource(this.expression)); + for (const dep of this.dependencies) { + const template = dependencyTemplates.get(dep.constructor); + if (!template) { + throw new Error(`No template for dependency: ${dep.constructor.name}`); + } + template.apply(dep, source, runtimeTemplate, dependencyTemplates); + } + return source; + } + + disconnect() { + for (const d of this.dependencies) { + d.disconnect(); + } + } + + hasDependencies(filter) { + if (filter) { + return this.dependencies.some(filter); + } + return this.dependencies.length > 0; + } +} + +module.exports = DependenciesBlockVariable; diff --git a/node_modules/webpack/lib/Dependency.js b/node_modules/webpack/lib/Dependency.js new file mode 100644 index 0000000..6d27b1e --- /dev/null +++ b/node_modules/webpack/lib/Dependency.js @@ -0,0 +1,89 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const util = require("util"); +const compareLocations = require("./compareLocations"); +const DependencyReference = require("./dependencies/DependencyReference"); + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ + +/** + * @typedef {Object} DependencyTemplate + * @property {function(Dependency, Source, RuntimeTemplate, Map<Function, DependencyTemplate>): void} apply + */ + +/** @typedef {Object} SourcePosition + * @property {number} line + * @property {number=} column + */ + +/** @typedef {Object} RealDependencyLocation + * @property {SourcePosition} start + * @property {SourcePosition=} end + * @property {number=} index + */ + +/** @typedef {Object} SynteticDependencyLocation + * @property {string} name + * @property {number=} index + */ + +/** @typedef {SynteticDependencyLocation|RealDependencyLocation} DependencyLocation */ + +class Dependency { + constructor() { + /** @type {Module|null} */ + this.module = null; + // TODO remove in webpack 5 + /** @type {boolean} */ + this.weak = false; + /** @type {boolean} */ + this.optional = false; + /** @type {DependencyLocation} */ + this.loc = undefined; + } + + getResourceIdentifier() { + return null; + } + + // Returns the referenced module and export + getReference() { + if (!this.module) return null; + return new DependencyReference(this.module, true, this.weak); + } + + // Returns the exported names + getExports() { + return null; + } + + getWarnings() { + return null; + } + + getErrors() { + return null; + } + + updateHash(hash) { + hash.update((this.module && this.module.id) + ""); + } + + disconnect() { + this.module = null; + } +} + +// TODO remove in webpack 5 +Dependency.compare = util.deprecate( + (a, b) => compareLocations(a.loc, b.loc), + "Dependency.compare is deprecated and will be removed in the next major version" +); + +module.exports = Dependency; diff --git a/node_modules/webpack/lib/DllEntryPlugin.js b/node_modules/webpack/lib/DllEntryPlugin.js new file mode 100644 index 0000000..562628d --- /dev/null +++ b/node_modules/webpack/lib/DllEntryPlugin.js @@ -0,0 +1,54 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DllEntryDependency = require("./dependencies/DllEntryDependency"); +const SingleEntryDependency = require("./dependencies/SingleEntryDependency"); +const DllModuleFactory = require("./DllModuleFactory"); + +class DllEntryPlugin { + constructor(context, entries, name) { + this.context = context; + this.entries = entries; + this.name = name; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "DllEntryPlugin", + (compilation, { normalModuleFactory }) => { + const dllModuleFactory = new DllModuleFactory(); + compilation.dependencyFactories.set( + DllEntryDependency, + dllModuleFactory + ); + compilation.dependencyFactories.set( + SingleEntryDependency, + normalModuleFactory + ); + } + ); + compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => { + compilation.addEntry( + this.context, + new DllEntryDependency( + this.entries.map((e, idx) => { + const dep = new SingleEntryDependency(e); + dep.loc = { + name: this.name, + index: idx + }; + return dep; + }), + this.name + ), + this.name, + callback + ); + }); + } +} + +module.exports = DllEntryPlugin; diff --git a/node_modules/webpack/lib/DllModule.js b/node_modules/webpack/lib/DllModule.js new file mode 100644 index 0000000..0cd9cbc --- /dev/null +++ b/node_modules/webpack/lib/DllModule.js @@ -0,0 +1,60 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const { RawSource } = require("webpack-sources"); +const Module = require("./Module"); + +/** @typedef {import("./util/createHash").Hash} Hash */ + +class DllModule extends Module { + constructor(context, dependencies, name, type) { + super("javascript/dynamic", context); + + // Info from Factory + this.dependencies = dependencies; + this.name = name; + this.type = type; + } + + identifier() { + return `dll ${this.name}`; + } + + readableIdentifier() { + return `dll ${this.name}`; + } + + build(options, compilation, resolver, fs, callback) { + this.built = true; + this.buildMeta = {}; + this.buildInfo = {}; + return callback(); + } + + source() { + return new RawSource("module.exports = __webpack_require__;"); + } + + needRebuild() { + return false; + } + + size() { + return 12; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update("dll module"); + hash.update(this.name || ""); + super.updateHash(hash); + } +} + +module.exports = DllModule; diff --git a/node_modules/webpack/lib/DllModuleFactory.js b/node_modules/webpack/lib/DllModuleFactory.js new file mode 100644 index 0000000..f5d12dd --- /dev/null +++ b/node_modules/webpack/lib/DllModuleFactory.js @@ -0,0 +1,29 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { Tapable } = require("tapable"); +const DllModule = require("./DllModule"); + +class DllModuleFactory extends Tapable { + constructor() { + super(); + this.hooks = {}; + } + create(data, callback) { + const dependency = data.dependencies[0]; + callback( + null, + new DllModule( + data.context, + dependency.dependencies, + dependency.name, + dependency.type + ) + ); + } +} + +module.exports = DllModuleFactory; diff --git a/node_modules/webpack/lib/DllPlugin.js b/node_modules/webpack/lib/DllPlugin.js new file mode 100644 index 0000000..ffd62cf --- /dev/null +++ b/node_modules/webpack/lib/DllPlugin.js @@ -0,0 +1,49 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const DllEntryPlugin = require("./DllEntryPlugin"); +const FlagAllModulesAsUsedPlugin = require("./FlagAllModulesAsUsedPlugin"); +const LibManifestPlugin = require("./LibManifestPlugin"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/DllPlugin.json"); + +/** @typedef {import("../declarations/plugins/DllPlugin").DllPluginOptions} DllPluginOptions */ + +class DllPlugin { + /** + * @param {DllPluginOptions} options options object + */ + constructor(options) { + validateOptions(schema, options, "Dll Plugin"); + this.options = options; + } + + apply(compiler) { + compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => { + const itemToPlugin = (item, name) => { + if (Array.isArray(item)) { + return new DllEntryPlugin(context, item, name); + } + throw new Error("DllPlugin: supply an Array as entry"); + }; + if (typeof entry === "object" && !Array.isArray(entry)) { + Object.keys(entry).forEach(name => { + itemToPlugin(entry[name], name).apply(compiler); + }); + } else { + itemToPlugin(entry, "main").apply(compiler); + } + return true; + }); + new LibManifestPlugin(this.options).apply(compiler); + if (!this.options.entryOnly) { + new FlagAllModulesAsUsedPlugin("DllPlugin").apply(compiler); + } + } +} + +module.exports = DllPlugin; diff --git a/node_modules/webpack/lib/DllReferencePlugin.js b/node_modules/webpack/lib/DllReferencePlugin.js new file mode 100644 index 0000000..62e26d8 --- /dev/null +++ b/node_modules/webpack/lib/DllReferencePlugin.js @@ -0,0 +1,156 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const parseJson = require("json-parse-better-errors"); +const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency"); +const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin"); +const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin"); +const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency"); +const NullFactory = require("./NullFactory"); +const makePathsRelative = require("./util/identifier").makePathsRelative; +const WebpackError = require("./WebpackError"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/DllReferencePlugin.json"); + +/** @typedef {import("../declarations/plugins/DllReferencePlugin").DllReferencePluginOptions} DllReferencePluginOptions */ +/** @typedef {import("../declarations/plugins/DllReferencePlugin").DllReferencePluginOptionsManifest} DllReferencePluginOptionsManifest */ + +class DllReferencePlugin { + /** + * @param {DllReferencePluginOptions} options options object + */ + constructor(options) { + validateOptions(schema, options, "Dll Reference Plugin"); + this.options = options; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "DllReferencePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + DelegatedSourceDependency, + normalModuleFactory + ); + compilation.dependencyFactories.set( + DelegatedExportsDependency, + new NullFactory() + ); + } + ); + + compiler.hooks.beforeCompile.tapAsync( + "DllReferencePlugin", + (params, callback) => { + if ("manifest" in this.options) { + const manifest = this.options.manifest; + if (typeof manifest === "string") { + params.compilationDependencies.add(manifest); + compiler.inputFileSystem.readFile(manifest, (err, result) => { + if (err) return callback(err); + // Catch errors parsing the manifest so that blank + // or malformed manifest files don't kill the process. + try { + params["dll reference " + manifest] = parseJson( + result.toString("utf-8") + ); + } catch (e) { + // Store the error in the params so that it can + // be added as a compilation error later on. + const manifestPath = makePathsRelative( + compiler.options.context, + manifest + ); + params[ + "dll reference parse error " + manifest + ] = new DllManifestError(manifestPath, e.message); + } + return callback(); + }); + return; + } + } + return callback(); + } + ); + + compiler.hooks.compile.tap("DllReferencePlugin", params => { + let name = this.options.name; + let sourceType = this.options.sourceType; + let content = + "content" in this.options ? this.options.content : undefined; + if ("manifest" in this.options) { + let manifestParameter = this.options.manifest; + let manifest; + if (typeof manifestParameter === "string") { + // If there was an error parsing the manifest + // file, exit now because the error will be added + // as a compilation error in the "compilation" hook. + if (params["dll reference parse error " + manifestParameter]) { + return; + } + manifest = + /** @type {DllReferencePluginOptionsManifest} */ (params[ + "dll reference " + manifestParameter + ]); + } else { + manifest = manifestParameter; + } + if (manifest) { + if (!name) name = manifest.name; + if (!sourceType) sourceType = manifest.type; + if (!content) content = manifest.content; + } + } + const externals = {}; + const source = "dll-reference " + name; + externals[source] = name; + const normalModuleFactory = params.normalModuleFactory; + new ExternalModuleFactoryPlugin(sourceType || "var", externals).apply( + normalModuleFactory + ); + new DelegatedModuleFactoryPlugin({ + source: source, + type: this.options.type, + scope: this.options.scope, + context: this.options.context || compiler.options.context, + content, + extensions: this.options.extensions + }).apply(normalModuleFactory); + }); + + compiler.hooks.compilation.tap( + "DllReferencePlugin", + (compilation, params) => { + if ("manifest" in this.options) { + let manifest = this.options.manifest; + if (typeof manifest === "string") { + // If there was an error parsing the manifest file, add the + // error as a compilation error to make the compilation fail. + let e = params["dll reference parse error " + manifest]; + if (e) { + compilation.errors.push(e); + } + } + } + } + ); + } +} + +class DllManifestError extends WebpackError { + constructor(filename, message) { + super(); + + this.name = "DllManifestError"; + this.message = `Dll manifest ${filename}\n${message}`; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = DllReferencePlugin; diff --git a/node_modules/webpack/lib/DynamicEntryPlugin.js b/node_modules/webpack/lib/DynamicEntryPlugin.js new file mode 100644 index 0000000..be9b237 --- /dev/null +++ b/node_modules/webpack/lib/DynamicEntryPlugin.js @@ -0,0 +1,94 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Naoyuki Kanezawa @nkzawa +*/ +"use strict"; + +const MultiEntryDependency = require("./dependencies/MultiEntryDependency"); +const SingleEntryDependency = require("./dependencies/SingleEntryDependency"); +const MultiModuleFactory = require("./MultiModuleFactory"); +const MultiEntryPlugin = require("./MultiEntryPlugin"); +const SingleEntryPlugin = require("./SingleEntryPlugin"); + +/** @typedef {import("../declarations/WebpackOptions").EntryDynamic} EntryDynamic */ +/** @typedef {import("../declarations/WebpackOptions").EntryStatic} EntryStatic */ +/** @typedef {import("./Compiler")} Compiler */ + +class DynamicEntryPlugin { + /** + * @param {string} context the context path + * @param {EntryDynamic} entry the entry value + */ + constructor(context, entry) { + this.context = context; + this.entry = entry; + } + + /** + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "DynamicEntryPlugin", + (compilation, { normalModuleFactory }) => { + const multiModuleFactory = new MultiModuleFactory(); + + compilation.dependencyFactories.set( + MultiEntryDependency, + multiModuleFactory + ); + compilation.dependencyFactories.set( + SingleEntryDependency, + normalModuleFactory + ); + } + ); + + compiler.hooks.make.tapAsync( + "DynamicEntryPlugin", + (compilation, callback) => { + /** + * @param {string|string[]} entry entry value or array of entry values + * @param {string} name name of entry + * @returns {Promise<EntryStatic>} returns the promise resolving the Compilation#addEntry function + */ + const addEntry = (entry, name) => { + const dep = DynamicEntryPlugin.createDependency(entry, name); + return new Promise((resolve, reject) => { + compilation.addEntry(this.context, dep, name, err => { + if (err) return reject(err); + resolve(); + }); + }); + }; + + Promise.resolve(this.entry()).then(entry => { + if (typeof entry === "string" || Array.isArray(entry)) { + addEntry(entry, "main").then(() => callback(), callback); + } else if (typeof entry === "object") { + Promise.all( + Object.keys(entry).map(name => { + return addEntry(entry[name], name); + }) + ).then(() => callback(), callback); + } + }); + } + ); + } +} + +module.exports = DynamicEntryPlugin; +/** + * @param {string|string[]} entry entry value or array of entry paths + * @param {string} name name of entry + * @returns {SingleEntryDependency|MultiEntryDependency} returns dep + */ +DynamicEntryPlugin.createDependency = (entry, name) => { + if (Array.isArray(entry)) { + return MultiEntryPlugin.createDependency(entry, name); + } else { + return SingleEntryPlugin.createDependency(entry, name); + } +}; diff --git a/node_modules/webpack/lib/EntryModuleNotFoundError.js b/node_modules/webpack/lib/EntryModuleNotFoundError.js new file mode 100644 index 0000000..b2458d6 --- /dev/null +++ b/node_modules/webpack/lib/EntryModuleNotFoundError.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +class EntryModuleNotFoundError extends WebpackError { + constructor(err) { + super("Entry module not found: " + err); + + this.name = "EntryModuleNotFoundError"; + this.details = err.details; + this.error = err; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = EntryModuleNotFoundError; diff --git a/node_modules/webpack/lib/EntryOptionPlugin.js b/node_modules/webpack/lib/EntryOptionPlugin.js new file mode 100644 index 0000000..ddda157 --- /dev/null +++ b/node_modules/webpack/lib/EntryOptionPlugin.js @@ -0,0 +1,46 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const SingleEntryPlugin = require("./SingleEntryPlugin"); +const MultiEntryPlugin = require("./MultiEntryPlugin"); +const DynamicEntryPlugin = require("./DynamicEntryPlugin"); + +/** @typedef {import("../declarations/WebpackOptions").EntryItem} EntryItem */ +/** @typedef {import("./Compiler")} Compiler */ + +/** + * @param {string} context context path + * @param {EntryItem} item entry array or single path + * @param {string} name entry key name + * @returns {SingleEntryPlugin | MultiEntryPlugin} returns either a single or multi entry plugin + */ +const itemToPlugin = (context, item, name) => { + if (Array.isArray(item)) { + return new MultiEntryPlugin(context, item, name); + } + return new SingleEntryPlugin(context, item, name); +}; + +module.exports = class EntryOptionPlugin { + /** + * @param {Compiler} compiler the compiler instance one is tapping into + * @returns {void} + */ + apply(compiler) { + compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => { + if (typeof entry === "string" || Array.isArray(entry)) { + itemToPlugin(context, entry, "main").apply(compiler); + } else if (typeof entry === "object") { + for (const name of Object.keys(entry)) { + itemToPlugin(context, entry[name], name).apply(compiler); + } + } else if (typeof entry === "function") { + new DynamicEntryPlugin(context, entry).apply(compiler); + } + return true; + }); + } +}; diff --git a/node_modules/webpack/lib/Entrypoint.js b/node_modules/webpack/lib/Entrypoint.js new file mode 100644 index 0000000..d82158a --- /dev/null +++ b/node_modules/webpack/lib/Entrypoint.js @@ -0,0 +1,64 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ChunkGroup = require("./ChunkGroup"); + +/** @typedef {import("./Chunk")} Chunk */ + +/** + * Entrypoint serves as an encapsulation primitive for chunks that are + * a part of a single ChunkGroup. They represent all bundles that need to be loaded for a + * single instance of a page. Multi-page application architectures will typically yield multiple Entrypoint objects + * inside of the compilation, whereas a Single Page App may only contain one with many lazy-loaded chunks. + */ +class Entrypoint extends ChunkGroup { + /** + * Creates an instance of Entrypoint. + * @param {string} name the name of the entrypoint + */ + constructor(name) { + super(name); + /** @type {Chunk=} */ + this.runtimeChunk = undefined; + } + + /** + * isInitial will always return true for Entrypoint ChunkGroup. + * @returns {true} returns true as all entrypoints are initial ChunkGroups + */ + isInitial() { + return true; + } + + /** + * Sets the runtimeChunk for an entrypoint. + * @param {Chunk} chunk the chunk being set as the runtime chunk. + * @returns {void} + */ + setRuntimeChunk(chunk) { + this.runtimeChunk = chunk; + } + + /** + * Fetches the chunk reference containing the webpack bootstrap code + * @returns {Chunk} returns the runtime chunk or first chunk in `this.chunks` + */ + getRuntimeChunk() { + return this.runtimeChunk || this.chunks[0]; + } + + /** + * @param {Chunk} oldChunk chunk to be replaced + * @param {Chunk} newChunk New chunk that will be replaced with + * @returns {boolean} returns true if the replacement was successful + */ + replaceChunk(oldChunk, newChunk) { + if (this.runtimeChunk === oldChunk) this.runtimeChunk = newChunk; + return super.replaceChunk(oldChunk, newChunk); + } +} + +module.exports = Entrypoint; diff --git a/node_modules/webpack/lib/EnvironmentPlugin.js b/node_modules/webpack/lib/EnvironmentPlugin.js new file mode 100644 index 0000000..c9fafaa --- /dev/null +++ b/node_modules/webpack/lib/EnvironmentPlugin.js @@ -0,0 +1,72 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Authors Simen Brekken @simenbrekken, Einar Löve @einarlove +*/ + +"use strict"; + +/** @typedef {import("./Compiler")} Compiler */ + +const WebpackError = require("./WebpackError"); +const DefinePlugin = require("./DefinePlugin"); + +const needsEnvVarFix = + ["8", "9"].indexOf(process.versions.node.split(".")[0]) >= 0 && + process.platform === "win32"; + +class EnvironmentPlugin { + constructor(...keys) { + if (keys.length === 1 && Array.isArray(keys[0])) { + this.keys = keys[0]; + this.defaultValues = {}; + } else if (keys.length === 1 && keys[0] && typeof keys[0] === "object") { + this.keys = Object.keys(keys[0]); + this.defaultValues = keys[0]; + } else { + this.keys = keys; + this.defaultValues = {}; + } + } + + /** + * @param {Compiler} compiler webpack compiler instance + * @returns {void} + */ + apply(compiler) { + const definitions = this.keys.reduce((defs, key) => { + // TODO remove once the fix has made its way into Node 8. + // Work around https://github.com/nodejs/node/pull/18463, + // affecting Node 8 & 9 by performing an OS-level + // operation that always succeeds before reading + // environment variables: + if (needsEnvVarFix) require("os").cpus(); + + const value = + process.env[key] !== undefined + ? process.env[key] + : this.defaultValues[key]; + + if (value === undefined) { + compiler.hooks.thisCompilation.tap("EnvironmentPlugin", compilation => { + const error = new WebpackError( + `EnvironmentPlugin - ${key} environment variable is undefined.\n\n` + + "You can pass an object with default values to suppress this warning.\n" + + "See https://webpack.js.org/plugins/environment-plugin for example." + ); + + error.name = "EnvVariableNotDefinedError"; + compilation.warnings.push(error); + }); + } + + defs[`process.env.${key}`] = + value === undefined ? "undefined" : JSON.stringify(value); + + return defs; + }, {}); + + new DefinePlugin(definitions).apply(compiler); + } +} + +module.exports = EnvironmentPlugin; diff --git a/node_modules/webpack/lib/ErrorHelpers.js b/node_modules/webpack/lib/ErrorHelpers.js new file mode 100644 index 0000000..900ae4d --- /dev/null +++ b/node_modules/webpack/lib/ErrorHelpers.js @@ -0,0 +1,60 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const loaderFlag = "LOADER_EXECUTION"; + +const webpackOptionsFlag = "WEBPACK_OPTIONS"; + +exports.cutOffByFlag = (stack, flag) => { + stack = stack.split("\n"); + for (let i = 0; i < stack.length; i++) { + if (stack[i].includes(flag)) { + stack.length = i; + } + } + return stack.join("\n"); +}; + +exports.cutOffLoaderExecution = stack => + exports.cutOffByFlag(stack, loaderFlag); + +exports.cutOffWebpackOptions = stack => + exports.cutOffByFlag(stack, webpackOptionsFlag); + +exports.cutOffMultilineMessage = (stack, message) => { + stack = stack.split("\n"); + message = message.split("\n"); + + return stack + .reduce( + (acc, line, idx) => + line.includes(message[idx]) ? acc : acc.concat(line), + [] + ) + .join("\n"); +}; + +exports.cutOffMessage = (stack, message) => { + const nextLine = stack.indexOf("\n"); + if (nextLine === -1) { + return stack === message ? "" : stack; + } else { + const firstLine = stack.substr(0, nextLine); + return firstLine === message ? stack.substr(nextLine + 1) : stack; + } +}; + +exports.cleanUp = (stack, message) => { + stack = exports.cutOffLoaderExecution(stack); + stack = exports.cutOffMessage(stack, message); + return stack; +}; + +exports.cleanUpWebpackOptions = (stack, message) => { + stack = exports.cutOffWebpackOptions(stack); + stack = exports.cutOffMultilineMessage(stack, message); + return stack; +}; diff --git a/node_modules/webpack/lib/EvalDevToolModulePlugin.js b/node_modules/webpack/lib/EvalDevToolModulePlugin.js new file mode 100644 index 0000000..2af11f9 --- /dev/null +++ b/node_modules/webpack/lib/EvalDevToolModulePlugin.js @@ -0,0 +1,27 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const EvalDevToolModuleTemplatePlugin = require("./EvalDevToolModuleTemplatePlugin"); + +class EvalDevToolModulePlugin { + constructor(options) { + this.sourceUrlComment = options.sourceUrlComment; + this.moduleFilenameTemplate = options.moduleFilenameTemplate; + this.namespace = options.namespace; + } + + apply(compiler) { + compiler.hooks.compilation.tap("EvalDevToolModulePlugin", compilation => { + new EvalDevToolModuleTemplatePlugin({ + sourceUrlComment: this.sourceUrlComment, + moduleFilenameTemplate: this.moduleFilenameTemplate, + namespace: this.namespace + }).apply(compilation.moduleTemplates.javascript); + }); + } +} + +module.exports = EvalDevToolModulePlugin; diff --git a/node_modules/webpack/lib/EvalDevToolModuleTemplatePlugin.js b/node_modules/webpack/lib/EvalDevToolModuleTemplatePlugin.js new file mode 100644 index 0000000..ab5dd1a --- /dev/null +++ b/node_modules/webpack/lib/EvalDevToolModuleTemplatePlugin.js @@ -0,0 +1,61 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { RawSource } = require("webpack-sources"); +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); + +const cache = new WeakMap(); + +class EvalDevToolModuleTemplatePlugin { + constructor(options) { + this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]"; + this.moduleFilenameTemplate = + options.moduleFilenameTemplate || + "webpack://[namespace]/[resourcePath]?[loaders]"; + this.namespace = options.namespace || ""; + } + + apply(moduleTemplate) { + moduleTemplate.hooks.module.tap( + "EvalDevToolModuleTemplatePlugin", + (source, module) => { + const cacheEntry = cache.get(source); + if (cacheEntry !== undefined) return cacheEntry; + const content = source.source(); + const str = ModuleFilenameHelpers.createFilename( + module, + { + moduleFilenameTemplate: this.moduleFilenameTemplate, + namespace: this.namespace + }, + moduleTemplate.runtimeTemplate.requestShortener + ); + const footer = + "\n" + + this.sourceUrlComment.replace( + /\[url\]/g, + encodeURI(str) + .replace(/%2F/g, "/") + .replace(/%20/g, "_") + .replace(/%5E/g, "^") + .replace(/%5C/g, "\\") + .replace(/^\//, "") + ); + const result = new RawSource( + `eval(${JSON.stringify(content + footer)});` + ); + cache.set(source, result); + return result; + } + ); + moduleTemplate.hooks.hash.tap("EvalDevToolModuleTemplatePlugin", hash => { + hash.update("EvalDevToolModuleTemplatePlugin"); + hash.update("2"); + }); + } +} + +module.exports = EvalDevToolModuleTemplatePlugin; diff --git a/node_modules/webpack/lib/EvalSourceMapDevToolModuleTemplatePlugin.js b/node_modules/webpack/lib/EvalSourceMapDevToolModuleTemplatePlugin.js new file mode 100644 index 0000000..73659fc --- /dev/null +++ b/node_modules/webpack/lib/EvalSourceMapDevToolModuleTemplatePlugin.js @@ -0,0 +1,120 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { RawSource } = require("webpack-sources"); +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); +const { absolutify } = require("./util/identifier"); + +const cache = new WeakMap(); + +class EvalSourceMapDevToolModuleTemplatePlugin { + constructor(compilation, options) { + this.compilation = compilation; + this.sourceMapComment = + options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]"; + this.moduleFilenameTemplate = + options.moduleFilenameTemplate || + "webpack://[namespace]/[resource-path]?[hash]"; + this.namespace = options.namespace || ""; + this.options = options; + } + + apply(moduleTemplate) { + const self = this; + const options = this.options; + const matchModule = ModuleFilenameHelpers.matchObject.bind( + ModuleFilenameHelpers, + options + ); + moduleTemplate.hooks.module.tap( + "EvalSourceMapDevToolModuleTemplatePlugin", + (source, module) => { + const cachedSource = cache.get(source); + if (cachedSource !== undefined) { + return cachedSource; + } + + if (!matchModule(module.resource)) { + return source; + } + + /** @type {{ [key: string]: TODO; }} */ + let sourceMap; + let content; + if (source.sourceAndMap) { + const sourceAndMap = source.sourceAndMap(options); + sourceMap = sourceAndMap.map; + content = sourceAndMap.source; + } else { + sourceMap = source.map(options); + content = source.source(); + } + if (!sourceMap) { + return source; + } + + // Clone (flat) the sourcemap to ensure that the mutations below do not persist. + sourceMap = Object.keys(sourceMap).reduce((obj, key) => { + obj[key] = sourceMap[key]; + return obj; + }, {}); + const context = this.compilation.compiler.options.context; + const modules = sourceMap.sources.map(source => { + if (source.startsWith("webpack://")) { + source = absolutify(context, source.slice(10)); + } + const module = self.compilation.findModule(source); + return module || source; + }); + let moduleFilenames = modules.map(module => { + return ModuleFilenameHelpers.createFilename( + module, + { + moduleFilenameTemplate: self.moduleFilenameTemplate, + namespace: self.namespace + }, + moduleTemplate.runtimeTemplate.requestShortener + ); + }); + moduleFilenames = ModuleFilenameHelpers.replaceDuplicates( + moduleFilenames, + (filename, i, n) => { + for (let j = 0; j < n; j++) filename += "*"; + return filename; + } + ); + sourceMap.sources = moduleFilenames; + sourceMap.sourceRoot = options.sourceRoot || ""; + sourceMap.file = `${module.id}.js`; + + const footer = + self.sourceMapComment.replace( + /\[url\]/g, + `data:application/json;charset=utf-8;base64,${Buffer.from( + JSON.stringify(sourceMap), + "utf8" + ).toString("base64")}` + ) + `\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug + + const evalSource = new RawSource( + `eval(${JSON.stringify(content + footer)});` + ); + + cache.set(source, evalSource); + + return evalSource; + } + ); + moduleTemplate.hooks.hash.tap( + "EvalSourceMapDevToolModuleTemplatePlugin", + hash => { + hash.update("eval-source-map"); + hash.update("2"); + } + ); + } +} +module.exports = EvalSourceMapDevToolModuleTemplatePlugin; diff --git a/node_modules/webpack/lib/EvalSourceMapDevToolPlugin.js b/node_modules/webpack/lib/EvalSourceMapDevToolPlugin.js new file mode 100644 index 0000000..daf9aad --- /dev/null +++ b/node_modules/webpack/lib/EvalSourceMapDevToolPlugin.js @@ -0,0 +1,41 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const EvalSourceMapDevToolModuleTemplatePlugin = require("./EvalSourceMapDevToolModuleTemplatePlugin"); +const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOptionsPlugin"); + +class EvalSourceMapDevToolPlugin { + constructor(options) { + if (arguments.length > 1) { + throw new Error( + "EvalSourceMapDevToolPlugin only takes one argument (pass an options object)" + ); + } + if (typeof options === "string") { + options = { + append: options + }; + } + if (!options) options = {}; + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap( + "EvalSourceMapDevToolPlugin", + compilation => { + new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation); + new EvalSourceMapDevToolModuleTemplatePlugin( + compilation, + options + ).apply(compilation.moduleTemplates.javascript); + } + ); + } +} + +module.exports = EvalSourceMapDevToolPlugin; diff --git a/node_modules/webpack/lib/ExportPropertyMainTemplatePlugin.js b/node_modules/webpack/lib/ExportPropertyMainTemplatePlugin.js new file mode 100644 index 0000000..90df031 --- /dev/null +++ b/node_modules/webpack/lib/ExportPropertyMainTemplatePlugin.js @@ -0,0 +1,53 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +/** @typedef {import("./Compilation")} Compilation */ + +/** + * @param {string[]} accessor the accessor to convert to path + * @returns {string} the path + */ +const accessorToObjectAccess = accessor => { + return accessor.map(a => `[${JSON.stringify(a)}]`).join(""); +}; + +class ExportPropertyMainTemplatePlugin { + /** + * @param {string|string[]} property the name of the property to export + */ + constructor(property) { + this.property = property; + } + + /** + * @param {Compilation} compilation the compilation instance + * @returns {void} + */ + apply(compilation) { + const { mainTemplate, chunkTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + const postfix = `${accessorToObjectAccess([].concat(this.property))}`; + return new ConcatSource(source, postfix); + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "ExportPropertyMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.hash.tap("ExportPropertyMainTemplatePlugin", hash => { + hash.update("export property"); + hash.update(`${this.property}`); + }); + } +} + +module.exports = ExportPropertyMainTemplatePlugin; diff --git a/node_modules/webpack/lib/ExtendedAPIPlugin.js b/node_modules/webpack/lib/ExtendedAPIPlugin.js new file mode 100644 index 0000000..e41defb --- /dev/null +++ b/node_modules/webpack/lib/ExtendedAPIPlugin.js @@ -0,0 +1,88 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("./Template"); +const ConstDependency = require("./dependencies/ConstDependency"); +const ParserHelpers = require("./ParserHelpers"); +const NullFactory = require("./NullFactory"); + +const REPLACEMENTS = { + // eslint-disable-next-line camelcase + __webpack_hash__: "__webpack_require__.h", + // eslint-disable-next-line camelcase + __webpack_chunkname__: "__webpack_require__.cn" +}; +const REPLACEMENT_TYPES = { + // eslint-disable-next-line camelcase + __webpack_hash__: "string", + // eslint-disable-next-line camelcase + __webpack_chunkname__: "string" +}; + +class ExtendedAPIPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "ExtendedAPIPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + const mainTemplate = compilation.mainTemplate; + mainTemplate.hooks.requireExtensions.tap( + "ExtendedAPIPlugin", + (source, chunk, hash) => { + const buf = [source]; + buf.push(""); + buf.push("// __webpack_hash__"); + buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`); + buf.push(""); + buf.push("// __webpack_chunkname__"); + buf.push( + `${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};` + ); + return Template.asString(buf); + } + ); + mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true); + + const handler = (parser, parserOptions) => { + Object.keys(REPLACEMENTS).forEach(key => { + parser.hooks.expression + .for(key) + .tap( + "ExtendedAPIPlugin", + ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + REPLACEMENTS[key] + ) + ); + parser.hooks.evaluateTypeof + .for(key) + .tap( + "ExtendedAPIPlugin", + ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key]) + ); + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("ExtendedAPIPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("ExtendedAPIPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("ExtendedAPIPlugin", handler); + } + ); + } +} + +module.exports = ExtendedAPIPlugin; diff --git a/node_modules/webpack/lib/ExternalModule.js b/node_modules/webpack/lib/ExternalModule.js new file mode 100644 index 0000000..e2da635 --- /dev/null +++ b/node_modules/webpack/lib/ExternalModule.js @@ -0,0 +1,179 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { OriginalSource, RawSource } = require("webpack-sources"); +const Module = require("./Module"); +const WebpackMissingModule = require("./dependencies/WebpackMissingModule"); +const Template = require("./Template"); + +/** @typedef {import("./util/createHash").Hash} Hash */ + +class ExternalModule extends Module { + constructor(request, type, userRequest) { + super("javascript/dynamic", null); + + // Info from Factory + this.request = request; + this.externalType = type; + this.userRequest = userRequest; + this.external = true; + } + + libIdent() { + return this.userRequest; + } + + chunkCondition(chunk) { + return chunk.hasEntryModule(); + } + + identifier() { + return "external " + JSON.stringify(this.request); + } + + readableIdentifier() { + return "external " + JSON.stringify(this.request); + } + + needRebuild() { + return false; + } + + build(options, compilation, resolver, fs, callback) { + this.built = true; + this.buildMeta = {}; + this.buildInfo = {}; + callback(); + } + + getSourceForGlobalVariableExternal(variableName, type) { + if (!Array.isArray(variableName)) { + // make it an array as the look up works the same basically + variableName = [variableName]; + } + + // needed for e.g. window["some"]["thing"] + const objectLookup = variableName + .map(r => `[${JSON.stringify(r)}]`) + .join(""); + return `(function() { module.exports = ${type}${objectLookup}; }());`; + } + + getSourceForCommonJsExternal(moduleAndSpecifiers) { + if (!Array.isArray(moduleAndSpecifiers)) { + return `module.exports = require(${JSON.stringify( + moduleAndSpecifiers + )});`; + } + + const moduleName = moduleAndSpecifiers[0]; + const objectLookup = moduleAndSpecifiers + .slice(1) + .map(r => `[${JSON.stringify(r)}]`) + .join(""); + return `module.exports = require(${JSON.stringify( + moduleName + )})${objectLookup};`; + } + + checkExternalVariable(variableToCheck, request) { + return `if(typeof ${variableToCheck} === 'undefined') {${WebpackMissingModule.moduleCode( + request + )}}\n`; + } + + getSourceForAmdOrUmdExternal(id, optional, request) { + const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier( + `${id}` + )}__`; + const missingModuleError = optional + ? this.checkExternalVariable(externalVariable, request) + : ""; + return `${missingModuleError}module.exports = ${externalVariable};`; + } + + getSourceForDefaultCase(optional, request) { + if (!Array.isArray(request)) { + // make it an array as the look up works the same basically + request = [request]; + } + + const variableName = request[0]; + const missingModuleError = optional + ? this.checkExternalVariable(variableName, request.join(".")) + : ""; + const objectLookup = request + .slice(1) + .map(r => `[${JSON.stringify(r)}]`) + .join(""); + return `${missingModuleError}module.exports = ${variableName}${objectLookup};`; + } + + getSourceString(runtime) { + const request = + typeof this.request === "object" && !Array.isArray(this.request) + ? this.request[this.externalType] + : this.request; + switch (this.externalType) { + case "this": + case "window": + case "self": + return this.getSourceForGlobalVariableExternal( + request, + this.externalType + ); + case "global": + return this.getSourceForGlobalVariableExternal( + request, + runtime.outputOptions.globalObject + ); + case "commonjs": + case "commonjs2": + return this.getSourceForCommonJsExternal(request); + case "amd": + case "amd-require": + case "umd": + case "umd2": + case "system": + return this.getSourceForAmdOrUmdExternal( + this.id, + this.optional, + request + ); + default: + return this.getSourceForDefaultCase(this.optional, request); + } + } + + getSource(sourceString) { + if (this.useSourceMap) { + return new OriginalSource(sourceString, this.identifier()); + } + + return new RawSource(sourceString); + } + + source(dependencyTemplates, runtime) { + return this.getSource(this.getSourceString(runtime)); + } + + size() { + return 42; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update(this.externalType); + hash.update(JSON.stringify(this.request)); + hash.update(JSON.stringify(Boolean(this.optional))); + super.updateHash(hash); + } +} + +module.exports = ExternalModule; diff --git a/node_modules/webpack/lib/ExternalModuleFactoryPlugin.js b/node_modules/webpack/lib/ExternalModuleFactoryPlugin.js new file mode 100644 index 0000000..b75cc74 --- /dev/null +++ b/node_modules/webpack/lib/ExternalModuleFactoryPlugin.js @@ -0,0 +1,110 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ExternalModule = require("./ExternalModule"); + +class ExternalModuleFactoryPlugin { + constructor(type, externals) { + this.type = type; + this.externals = externals; + } + + apply(normalModuleFactory) { + const globalType = this.type; + normalModuleFactory.hooks.factory.tap( + "ExternalModuleFactoryPlugin", + factory => (data, callback) => { + const context = data.context; + const dependency = data.dependencies[0]; + + const handleExternal = (value, type, callback) => { + if (typeof type === "function") { + callback = type; + type = undefined; + } + if (value === false) return factory(data, callback); + if (value === true) value = dependency.request; + if (type === undefined && /^[a-z0-9]+ /.test(value)) { + const idx = value.indexOf(" "); + type = value.substr(0, idx); + value = value.substr(idx + 1); + } + callback( + null, + new ExternalModule(value, type || globalType, dependency.request) + ); + return true; + }; + + const handleExternals = (externals, callback) => { + if (typeof externals === "string") { + if (externals === dependency.request) { + return handleExternal(dependency.request, callback); + } + } else if (Array.isArray(externals)) { + let i = 0; + const next = () => { + let asyncFlag; + const handleExternalsAndCallback = (err, module) => { + if (err) return callback(err); + if (!module) { + if (asyncFlag) { + asyncFlag = false; + return; + } + return next(); + } + callback(null, module); + }; + + do { + asyncFlag = true; + if (i >= externals.length) return callback(); + handleExternals(externals[i++], handleExternalsAndCallback); + } while (!asyncFlag); + asyncFlag = false; + }; + + next(); + return; + } else if (externals instanceof RegExp) { + if (externals.test(dependency.request)) { + return handleExternal(dependency.request, callback); + } + } else if (typeof externals === "function") { + externals.call( + null, + context, + dependency.request, + (err, value, type) => { + if (err) return callback(err); + if (value !== undefined) { + handleExternal(value, type, callback); + } else { + callback(); + } + } + ); + return; + } else if ( + typeof externals === "object" && + Object.prototype.hasOwnProperty.call(externals, dependency.request) + ) { + return handleExternal(externals[dependency.request], callback); + } + callback(); + }; + + handleExternals(this.externals, (err, module) => { + if (err) return callback(err); + if (!module) return handleExternal(false, callback); + return callback(null, module); + }); + } + ); + } +} +module.exports = ExternalModuleFactoryPlugin; diff --git a/node_modules/webpack/lib/ExternalsPlugin.js b/node_modules/webpack/lib/ExternalsPlugin.js new file mode 100644 index 0000000..697f1aa --- /dev/null +++ b/node_modules/webpack/lib/ExternalsPlugin.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin"); + +class ExternalsPlugin { + constructor(type, externals) { + this.type = type; + this.externals = externals; + } + apply(compiler) { + compiler.hooks.compile.tap("ExternalsPlugin", ({ normalModuleFactory }) => { + new ExternalModuleFactoryPlugin(this.type, this.externals).apply( + normalModuleFactory + ); + }); + } +} + +module.exports = ExternalsPlugin; diff --git a/node_modules/webpack/lib/FlagAllModulesAsUsedPlugin.js b/node_modules/webpack/lib/FlagAllModulesAsUsedPlugin.js new file mode 100644 index 0000000..db783cf --- /dev/null +++ b/node_modules/webpack/lib/FlagAllModulesAsUsedPlugin.js @@ -0,0 +1,38 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +/** @typedef {import("./Compiler")} Compiler */ + +class FlagAllModulesAsUsedPlugin { + constructor(explanation) { + this.explanation = explanation; + } + + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "FlagAllModulesAsUsedPlugin", + compilation => { + compilation.hooks.optimizeDependencies.tap( + "FlagAllModulesAsUsedPlugin", + modules => { + for (const module of modules) { + module.used = true; + module.usedExports = true; + module.addReason(null, null, this.explanation); + } + } + ); + } + ); + } +} + +module.exports = FlagAllModulesAsUsedPlugin; diff --git a/node_modules/webpack/lib/FlagDependencyExportsPlugin.js b/node_modules/webpack/lib/FlagDependencyExportsPlugin.js new file mode 100644 index 0000000..72231df --- /dev/null +++ b/node_modules/webpack/lib/FlagDependencyExportsPlugin.js @@ -0,0 +1,174 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Queue = require("./util/Queue"); + +const addToSet = (a, b) => { + for (const item of b) { + a.add(item); + } +}; + +class FlagDependencyExportsPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "FlagDependencyExportsPlugin", + compilation => { + compilation.hooks.finishModules.tap( + "FlagDependencyExportsPlugin", + modules => { + const dependencies = new Map(); + + const queue = new Queue(); + + let module; + let moduleWithExports; + let moduleProvidedExports; + let providedExportsAreTemporary; + + const processDependenciesBlock = depBlock => { + for (const dep of depBlock.dependencies) { + if (processDependency(dep)) return true; + } + for (const variable of depBlock.variables) { + for (const dep of variable.dependencies) { + if (processDependency(dep)) return true; + } + } + for (const block of depBlock.blocks) { + if (processDependenciesBlock(block)) return true; + } + return false; + }; + + const processDependency = dep => { + const exportDesc = dep.getExports && dep.getExports(); + if (!exportDesc) return; + moduleWithExports = true; + const exports = exportDesc.exports; + // break early if it's only in the worst state + if (module.buildMeta.providedExports === true) { + return true; + } + // break if it should move to the worst state + if (exports === true) { + module.buildMeta.providedExports = true; + return true; + } + // merge in new exports + if (Array.isArray(exports)) { + addToSet(moduleProvidedExports, exports); + } + // store dependencies + const exportDeps = exportDesc.dependencies; + if (exportDeps) { + providedExportsAreTemporary = true; + for (const exportDependency of exportDeps) { + // add dependency for this module + const set = dependencies.get(exportDependency); + if (set === undefined) { + dependencies.set(exportDependency, new Set([module])); + } else { + set.add(module); + } + } + } + return false; + }; + + const notifyDependencies = () => { + const deps = dependencies.get(module); + if (deps !== undefined) { + for (const dep of deps) { + queue.enqueue(dep); + } + } + }; + + const notifyDependenciesIfDifferent = (set, array) => { + const deps = dependencies.get(module); + if (deps !== undefined) { + if (set.size === array.length) { + let i = 0; + let different = false; + for (const item of set) { + if (item !== array[i++]) { + different = true; + break; + } + } + if (!different) return; + } + for (const dep of deps) { + queue.enqueue(dep); + } + } + }; + + // Start with all modules without provided exports + for (const module of modules) { + if (module.buildInfo.temporaryProvidedExports) { + // Clear exports when they are temporary + // and recreate them + module.buildMeta.providedExports = null; + queue.enqueue(module); + } else if (!module.buildMeta.providedExports) { + queue.enqueue(module); + } + } + + while (queue.length > 0) { + module = queue.dequeue(); + + if (module.buildMeta.providedExports !== true) { + moduleWithExports = + module.buildMeta && module.buildMeta.exportsType; + moduleProvidedExports = new Set(); + providedExportsAreTemporary = false; + processDependenciesBlock(module); + module.buildInfo.temporaryProvidedExports = providedExportsAreTemporary; + if (!moduleWithExports) { + notifyDependencies(); + module.buildMeta.providedExports = true; + } else if (module.buildMeta.providedExports === true) { + notifyDependencies(); + } else if (!module.buildMeta.providedExports) { + notifyDependencies(); + module.buildMeta.providedExports = Array.from( + moduleProvidedExports + ); + } else { + notifyDependenciesIfDifferent( + moduleProvidedExports, + module.buildMeta.providedExports + ); + module.buildMeta.providedExports = Array.from( + moduleProvidedExports + ); + } + } + } + } + ); + const providedExportsCache = new WeakMap(); + compilation.hooks.rebuildModule.tap( + "FlagDependencyExportsPlugin", + module => { + providedExportsCache.set(module, module.buildMeta.providedExports); + } + ); + compilation.hooks.finishRebuildingModule.tap( + "FlagDependencyExportsPlugin", + module => { + module.buildMeta.providedExports = providedExportsCache.get(module); + } + ); + } + ); + } +} + +module.exports = FlagDependencyExportsPlugin; diff --git a/node_modules/webpack/lib/FlagDependencyUsagePlugin.js b/node_modules/webpack/lib/FlagDependencyUsagePlugin.js new file mode 100644 index 0000000..2f2a52e --- /dev/null +++ b/node_modules/webpack/lib/FlagDependencyUsagePlugin.js @@ -0,0 +1,116 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./DependenciesBlock")} DependenciesBlock */ + +/** @typedef {false | true | string[]} UsedExports */ + +const addToSet = (a, b) => { + for (const item of b) { + if (!a.includes(item)) a.push(item); + } + return a; +}; + +const isSubset = (biggerSet, subset) => { + if (biggerSet === true) return true; + if (subset === true) return false; + return subset.every(item => biggerSet.indexOf(item) >= 0); +}; + +class FlagDependencyUsagePlugin { + apply(compiler) { + compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => { + compilation.hooks.optimizeDependencies.tap( + "FlagDependencyUsagePlugin", + modules => { + const processModule = (module, usedExports) => { + module.used = true; + if (module.usedExports === true) return; + if (usedExports === true) { + module.usedExports = true; + } else if (Array.isArray(usedExports)) { + const old = module.usedExports ? module.usedExports.length : -1; + module.usedExports = addToSet( + module.usedExports || [], + usedExports + ); + if (module.usedExports.length === old) { + return; + } + } else if (Array.isArray(module.usedExports)) { + return; + } else { + module.usedExports = false; + } + + // for a module without side effects we stop tracking usage here when no export is used + // This module won't be evaluated in this case + if (module.factoryMeta.sideEffectFree) { + if (module.usedExports === false) return; + if ( + Array.isArray(module.usedExports) && + module.usedExports.length === 0 + ) + return; + } + + queue.push([module, module, module.usedExports]); + }; + + const processDependenciesBlock = (module, depBlock, usedExports) => { + for (const dep of depBlock.dependencies) { + processDependency(module, dep); + } + for (const variable of depBlock.variables) { + for (const dep of variable.dependencies) { + processDependency(module, dep); + } + } + for (const block of depBlock.blocks) { + queue.push([module, block, usedExports]); + } + }; + + const processDependency = (module, dep) => { + const reference = compilation.getDependencyReference(module, dep); + if (!reference) return; + const referenceModule = reference.module; + const importedNames = reference.importedNames; + const oldUsed = referenceModule.used; + const oldUsedExports = referenceModule.usedExports; + if ( + !oldUsed || + (importedNames && + (!oldUsedExports || !isSubset(oldUsedExports, importedNames))) + ) { + processModule(referenceModule, importedNames); + } + }; + + for (const module of modules) { + if (!module.used) module.used = false; + } + + /** @type {[Module, DependenciesBlock, UsedExports][]} */ + const queue = []; + for (const preparedEntrypoint of compilation._preparedEntrypoints) { + if (preparedEntrypoint.module) { + processModule(preparedEntrypoint.module, true); + } + } + + while (queue.length) { + const queueItem = queue.pop(); + processDependenciesBlock(queueItem[0], queueItem[1], queueItem[2]); + } + } + ); + }); + } +} +module.exports = FlagDependencyUsagePlugin; diff --git a/node_modules/webpack/lib/FlagInitialModulesAsUsedPlugin.js b/node_modules/webpack/lib/FlagInitialModulesAsUsedPlugin.js new file mode 100644 index 0000000..7272ddb --- /dev/null +++ b/node_modules/webpack/lib/FlagInitialModulesAsUsedPlugin.js @@ -0,0 +1,36 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class FlagInitialModulesAsUsedPlugin { + constructor(explanation) { + this.explanation = explanation; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "FlagInitialModulesAsUsedPlugin", + compilation => { + compilation.hooks.afterOptimizeChunks.tap( + "FlagInitialModulesAsUsedPlugin", + chunks => { + for (const chunk of chunks) { + if (!chunk.isOnlyInitial()) { + return; + } + for (const module of chunk.modulesIterable) { + module.used = true; + module.usedExports = true; + module.addReason(null, null, this.explanation); + } + } + } + ); + } + ); + } +} + +module.exports = FlagInitialModulesAsUsedPlugin; diff --git a/node_modules/webpack/lib/FunctionModulePlugin.js b/node_modules/webpack/lib/FunctionModulePlugin.js new file mode 100644 index 0000000..fc4b270 --- /dev/null +++ b/node_modules/webpack/lib/FunctionModulePlugin.js @@ -0,0 +1,19 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const FunctionModuleTemplatePlugin = require("./FunctionModuleTemplatePlugin"); + +class FunctionModulePlugin { + apply(compiler) { + compiler.hooks.compilation.tap("FunctionModulePlugin", compilation => { + new FunctionModuleTemplatePlugin().apply( + compilation.moduleTemplates.javascript + ); + }); + } +} + +module.exports = FunctionModulePlugin; diff --git a/node_modules/webpack/lib/FunctionModuleTemplatePlugin.js b/node_modules/webpack/lib/FunctionModuleTemplatePlugin.js new file mode 100644 index 0000000..3402d99 --- /dev/null +++ b/node_modules/webpack/lib/FunctionModuleTemplatePlugin.js @@ -0,0 +1,102 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); +const Template = require("./Template"); + +class FunctionModuleTemplatePlugin { + apply(moduleTemplate) { + moduleTemplate.hooks.render.tap( + "FunctionModuleTemplatePlugin", + (moduleSource, module) => { + const source = new ConcatSource(); + const args = [module.moduleArgument]; + // TODO remove HACK checking type for javascript + if (module.type && module.type.startsWith("javascript")) { + args.push(module.exportsArgument); + if (module.hasDependencies(d => d.requireWebpackRequire !== false)) { + args.push("__webpack_require__"); + } + } else if (module.type && module.type.startsWith("json")) { + // no additional arguments needed + } else { + args.push(module.exportsArgument, "__webpack_require__"); + } + source.add("/***/ (function(" + args.join(", ") + ") {\n\n"); + if (module.buildInfo.strict) source.add('"use strict";\n'); + source.add(moduleSource); + source.add("\n\n/***/ })"); + return source; + } + ); + + moduleTemplate.hooks.package.tap( + "FunctionModuleTemplatePlugin", + (moduleSource, module) => { + if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) { + const source = new ConcatSource(); + const req = module.readableIdentifier( + moduleTemplate.runtimeTemplate.requestShortener + ); + const reqStr = req.replace(/\*\//g, "*_/"); + const reqStrStar = "*".repeat(reqStr.length); + source.add("/*!****" + reqStrStar + "****!*\\\n"); + source.add(" !*** " + reqStr + " ***!\n"); + source.add(" \\****" + reqStrStar + "****/\n"); + if ( + Array.isArray(module.buildMeta.providedExports) && + module.buildMeta.providedExports.length === 0 + ) { + source.add(Template.toComment("no exports provided") + "\n"); + } else if (Array.isArray(module.buildMeta.providedExports)) { + source.add( + Template.toComment( + "exports provided: " + + module.buildMeta.providedExports.join(", ") + ) + "\n" + ); + } else if (module.buildMeta.providedExports) { + source.add(Template.toComment("no static exports found") + "\n"); + } + if ( + Array.isArray(module.usedExports) && + module.usedExports.length === 0 + ) { + source.add(Template.toComment("no exports used") + "\n"); + } else if (Array.isArray(module.usedExports)) { + source.add( + Template.toComment( + "exports used: " + module.usedExports.join(", ") + ) + "\n" + ); + } else if (module.usedExports) { + source.add(Template.toComment("all exports used") + "\n"); + } + if (module.optimizationBailout) { + for (const text of module.optimizationBailout) { + let code; + if (typeof text === "function") { + code = text(moduleTemplate.runtimeTemplate.requestShortener); + } else { + code = text; + } + source.add(Template.toComment(`${code}`) + "\n"); + } + } + source.add(moduleSource); + return source; + } + return moduleSource; + } + ); + + moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => { + hash.update("FunctionModuleTemplatePlugin"); + hash.update("2"); + }); + } +} +module.exports = FunctionModuleTemplatePlugin; diff --git a/node_modules/webpack/lib/Generator.js b/node_modules/webpack/lib/Generator.js new file mode 100644 index 0000000..655a9b1 --- /dev/null +++ b/node_modules/webpack/lib/Generator.js @@ -0,0 +1,60 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** @typedef {import("./NormalModule")} NormalModule */ +/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */ + +/** + * + */ +class Generator { + static byType(map) { + return new ByTypeGenerator(map); + } + + /** + * @abstract + * @param {NormalModule} module module for which the code should be generated + * @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates + * @param {RuntimeTemplate} runtimeTemplate the runtime template + * @param {string} type which kind of code should be generated + * @returns {Source} generated code + */ + generate(module, dependencyTemplates, runtimeTemplate, type) { + throw new Error("Generator.generate: must be overridden"); + } +} + +class ByTypeGenerator extends Generator { + constructor(map) { + super(); + this.map = map; + } + + /** + * @param {NormalModule} module module for which the code should be generated + * @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates + * @param {RuntimeTemplate} runtimeTemplate the runtime template + * @param {string} type which kind of code should be generated + * @returns {Source} generated code + */ + generate(module, dependencyTemplates, runtimeTemplate, type) { + const generator = this.map[type]; + if (!generator) { + throw new Error(`Generator.byType: no generator specified for ${type}`); + } + return generator.generate( + module, + dependencyTemplates, + runtimeTemplate, + type + ); + } +} + +module.exports = Generator; diff --git a/node_modules/webpack/lib/GraphHelpers.js b/node_modules/webpack/lib/GraphHelpers.js new file mode 100644 index 0000000..73c5674 --- /dev/null +++ b/node_modules/webpack/lib/GraphHelpers.js @@ -0,0 +1,65 @@ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./DependenciesBlock")} DependenciesBlock */ +/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ + +/** + * @param {ChunkGroup} chunkGroup the ChunkGroup to connect + * @param {Chunk} chunk chunk to tie to ChunkGroup + * @returns {void} + */ +const connectChunkGroupAndChunk = (chunkGroup, chunk) => { + if (chunkGroup.pushChunk(chunk)) { + chunk.addGroup(chunkGroup); + } +}; + +/** + * @param {ChunkGroup} parent parent ChunkGroup to connect + * @param {ChunkGroup} child child ChunkGroup to connect + * @returns {void} + */ +const connectChunkGroupParentAndChild = (parent, child) => { + if (parent.addChild(child)) { + child.addParent(parent); + } +}; + +/** + * @param {Chunk} chunk Chunk to connect to Module + * @param {Module} module Module to connect to Chunk + * @returns {void} + */ +const connectChunkAndModule = (chunk, module) => { + if (module.addChunk(chunk)) { + chunk.addModule(module); + } +}; + +/** + * @param {Chunk} chunk Chunk being disconnected + * @param {Module} module Module being disconnected + * @returns {void} + */ +const disconnectChunkAndModule = (chunk, module) => { + chunk.removeModule(module); + module.removeChunk(chunk); +}; + +/** + * @param {AsyncDependenciesBlock} depBlock DepBlock being tied to ChunkGroup + * @param {ChunkGroup} chunkGroup ChunkGroup being tied to DepBlock + * @returns {void} + */ +const connectDependenciesBlockAndChunkGroup = (depBlock, chunkGroup) => { + if (chunkGroup.addBlock(depBlock)) { + depBlock.chunkGroup = chunkGroup; + } +}; + +exports.connectChunkGroupAndChunk = connectChunkGroupAndChunk; +exports.connectChunkGroupParentAndChild = connectChunkGroupParentAndChild; +exports.connectChunkAndModule = connectChunkAndModule; +exports.disconnectChunkAndModule = disconnectChunkAndModule; +exports.connectDependenciesBlockAndChunkGroup = connectDependenciesBlockAndChunkGroup; diff --git a/node_modules/webpack/lib/HarmonyLinkingError.js b/node_modules/webpack/lib/HarmonyLinkingError.js new file mode 100644 index 0000000..78ce16d --- /dev/null +++ b/node_modules/webpack/lib/HarmonyLinkingError.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +module.exports = class HarmonyLinkingError extends WebpackError { + /** @param {string} message Error message */ + constructor(message) { + super(message); + this.name = "HarmonyLinkingError"; + this.hideStack = true; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/HashedModuleIdsPlugin.js b/node_modules/webpack/lib/HashedModuleIdsPlugin.js new file mode 100644 index 0000000..7a860f7 --- /dev/null +++ b/node_modules/webpack/lib/HashedModuleIdsPlugin.js @@ -0,0 +1,63 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const createHash = require("./util/createHash"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/HashedModuleIdsPlugin.json"); + +/** @typedef {import("../declarations/plugins/HashedModuleIdsPlugin").HashedModuleIdsPluginOptions} HashedModuleIdsPluginOptions */ + +class HashedModuleIdsPlugin { + /** + * @param {HashedModuleIdsPluginOptions=} options options object + */ + constructor(options) { + if (!options) options = {}; + + validateOptions(schema, options, "Hashed Module Ids Plugin"); + + /** @type {HashedModuleIdsPluginOptions} */ + this.options = Object.assign( + { + context: null, + hashFunction: "md4", + hashDigest: "base64", + hashDigestLength: 4 + }, + options + ); + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => { + const usedIds = new Set(); + compilation.hooks.beforeModuleIds.tap( + "HashedModuleIdsPlugin", + modules => { + for (const module of modules) { + if (module.id === null && module.libIdent) { + const id = module.libIdent({ + context: this.options.context || compiler.options.context + }); + const hash = createHash(options.hashFunction); + hash.update(id); + const hashId = /** @type {string} */ (hash.digest( + options.hashDigest + )); + let len = options.hashDigestLength; + while (usedIds.has(hashId.substr(0, len))) len++; + module.id = hashId.substr(0, len); + usedIds.add(module.id); + } + } + } + ); + }); + } +} + +module.exports = HashedModuleIdsPlugin; diff --git a/node_modules/webpack/lib/HotModuleReplacement.runtime.js b/node_modules/webpack/lib/HotModuleReplacement.runtime.js new file mode 100644 index 0000000..02b3e8c --- /dev/null +++ b/node_modules/webpack/lib/HotModuleReplacement.runtime.js @@ -0,0 +1,721 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// eslint-disable no-unused-vars +var $hash$ = undefined; +var $requestTimeout$ = undefined; +var installedModules = undefined; +var $require$ = undefined; +var hotDownloadManifest = undefined; +var hotDownloadUpdateChunk = undefined; +var hotDisposeChunk = undefined; +var modules = undefined; +var chunkId = undefined; + +module.exports = function() { + var hotApplyOnUpdate = true; + // eslint-disable-next-line no-unused-vars + var hotCurrentHash = $hash$; + var hotRequestTimeout = $requestTimeout$; + var hotCurrentModuleData = {}; + var hotCurrentChildModule; + // eslint-disable-next-line no-unused-vars + var hotCurrentParents = []; + // eslint-disable-next-line no-unused-vars + var hotCurrentParentsTemp = []; + + // eslint-disable-next-line no-unused-vars + function hotCreateRequire(moduleId) { + var me = installedModules[moduleId]; + if (!me) return $require$; + var fn = function(request) { + if (me.hot.active) { + if (installedModules[request]) { + if (installedModules[request].parents.indexOf(moduleId) === -1) { + installedModules[request].parents.push(moduleId); + } + } else { + hotCurrentParents = [moduleId]; + hotCurrentChildModule = request; + } + if (me.children.indexOf(request) === -1) { + me.children.push(request); + } + } else { + console.warn( + "[HMR] unexpected require(" + + request + + ") from disposed module " + + moduleId + ); + hotCurrentParents = []; + } + return $require$(request); + }; + var ObjectFactory = function ObjectFactory(name) { + return { + configurable: true, + enumerable: true, + get: function() { + return $require$[name]; + }, + set: function(value) { + $require$[name] = value; + } + }; + }; + for (var name in $require$) { + if ( + Object.prototype.hasOwnProperty.call($require$, name) && + name !== "e" && + name !== "t" + ) { + Object.defineProperty(fn, name, ObjectFactory(name)); + } + } + fn.e = function(chunkId) { + if (hotStatus === "ready") hotSetStatus("prepare"); + hotChunksLoading++; + return $require$.e(chunkId).then(finishChunkLoading, function(err) { + finishChunkLoading(); + throw err; + }); + + function finishChunkLoading() { + hotChunksLoading--; + if (hotStatus === "prepare") { + if (!hotWaitingFilesMap[chunkId]) { + hotEnsureUpdateChunk(chunkId); + } + if (hotChunksLoading === 0 && hotWaitingFiles === 0) { + hotUpdateDownloaded(); + } + } + } + }; + fn.t = function(value, mode) { + if (mode & 1) value = fn(value); + return $require$.t(value, mode & ~1); + }; + return fn; + } + + // eslint-disable-next-line no-unused-vars + function hotCreateModule(moduleId) { + var hot = { + // private stuff + _acceptedDependencies: {}, + _declinedDependencies: {}, + _selfAccepted: false, + _selfDeclined: false, + _selfInvalidated: false, + _disposeHandlers: [], + _main: hotCurrentChildModule !== moduleId, + + // Module API + active: true, + accept: function(dep, callback) { + if (dep === undefined) hot._selfAccepted = true; + else if (typeof dep === "function") hot._selfAccepted = dep; + else if (typeof dep === "object") + for (var i = 0; i < dep.length; i++) + hot._acceptedDependencies[dep[i]] = callback || function() {}; + else hot._acceptedDependencies[dep] = callback || function() {}; + }, + decline: function(dep) { + if (dep === undefined) hot._selfDeclined = true; + else if (typeof dep === "object") + for (var i = 0; i < dep.length; i++) + hot._declinedDependencies[dep[i]] = true; + else hot._declinedDependencies[dep] = true; + }, + dispose: function(callback) { + hot._disposeHandlers.push(callback); + }, + addDisposeHandler: function(callback) { + hot._disposeHandlers.push(callback); + }, + removeDisposeHandler: function(callback) { + var idx = hot._disposeHandlers.indexOf(callback); + if (idx >= 0) hot._disposeHandlers.splice(idx, 1); + }, + invalidate: function() { + this._selfInvalidated = true; + switch (hotStatus) { + case "idle": + hotUpdate = {}; + hotUpdate[moduleId] = modules[moduleId]; + hotSetStatus("ready"); + break; + case "ready": + hotApplyInvalidatedModule(moduleId); + break; + case "prepare": + case "check": + case "dispose": + case "apply": + (hotQueuedInvalidatedModules = + hotQueuedInvalidatedModules || []).push(moduleId); + break; + default: + // ignore requests in error states + break; + } + }, + + // Management API + check: hotCheck, + apply: hotApply, + status: function(l) { + if (!l) return hotStatus; + hotStatusHandlers.push(l); + }, + addStatusHandler: function(l) { + hotStatusHandlers.push(l); + }, + removeStatusHandler: function(l) { + var idx = hotStatusHandlers.indexOf(l); + if (idx >= 0) hotStatusHandlers.splice(idx, 1); + }, + + //inherit from previous dispose call + data: hotCurrentModuleData[moduleId] + }; + hotCurrentChildModule = undefined; + return hot; + } + + var hotStatusHandlers = []; + var hotStatus = "idle"; + + function hotSetStatus(newStatus) { + hotStatus = newStatus; + for (var i = 0; i < hotStatusHandlers.length; i++) + hotStatusHandlers[i].call(null, newStatus); + } + + // while downloading + var hotWaitingFiles = 0; + var hotChunksLoading = 0; + var hotWaitingFilesMap = {}; + var hotRequestedFilesMap = {}; + var hotAvailableFilesMap = {}; + var hotDeferred; + + // The update info + var hotUpdate, hotUpdateNewHash, hotQueuedInvalidatedModules; + + function toModuleId(id) { + var isNumber = +id + "" === id; + return isNumber ? +id : id; + } + + function hotCheck(apply) { + if (hotStatus !== "idle") { + throw new Error("check() is only allowed in idle status"); + } + hotApplyOnUpdate = apply; + hotSetStatus("check"); + return hotDownloadManifest(hotRequestTimeout).then(function(update) { + if (!update) { + hotSetStatus(hotApplyInvalidatedModules() ? "ready" : "idle"); + return null; + } + hotRequestedFilesMap = {}; + hotWaitingFilesMap = {}; + hotAvailableFilesMap = update.c; + hotUpdateNewHash = update.h; + + hotSetStatus("prepare"); + var promise = new Promise(function(resolve, reject) { + hotDeferred = { + resolve: resolve, + reject: reject + }; + }); + hotUpdate = {}; + /*foreachInstalledChunks*/ + // eslint-disable-next-line no-lone-blocks + { + hotEnsureUpdateChunk(chunkId); + } + if ( + hotStatus === "prepare" && + hotChunksLoading === 0 && + hotWaitingFiles === 0 + ) { + hotUpdateDownloaded(); + } + return promise; + }); + } + + // eslint-disable-next-line no-unused-vars + function hotAddUpdateChunk(chunkId, moreModules) { + if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId]) + return; + hotRequestedFilesMap[chunkId] = false; + for (var moduleId in moreModules) { + if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { + hotUpdate[moduleId] = moreModules[moduleId]; + } + } + if (--hotWaitingFiles === 0 && hotChunksLoading === 0) { + hotUpdateDownloaded(); + } + } + + function hotEnsureUpdateChunk(chunkId) { + if (!hotAvailableFilesMap[chunkId]) { + hotWaitingFilesMap[chunkId] = true; + } else { + hotRequestedFilesMap[chunkId] = true; + hotWaitingFiles++; + hotDownloadUpdateChunk(chunkId); + } + } + + function hotUpdateDownloaded() { + hotSetStatus("ready"); + var deferred = hotDeferred; + hotDeferred = null; + if (!deferred) return; + if (hotApplyOnUpdate) { + // Wrap deferred object in Promise to mark it as a well-handled Promise to + // avoid triggering uncaught exception warning in Chrome. + // See https://bugs.chromium.org/p/chromium/issues/detail?id=465666 + Promise.resolve() + .then(function() { + return hotApply(hotApplyOnUpdate); + }) + .then( + function(result) { + deferred.resolve(result); + }, + function(err) { + deferred.reject(err); + } + ); + } else { + var outdatedModules = []; + for (var id in hotUpdate) { + if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) { + outdatedModules.push(toModuleId(id)); + } + } + deferred.resolve(outdatedModules); + } + } + + function hotApply(options) { + if (hotStatus !== "ready") + throw new Error("apply() is only allowed in ready status"); + options = options || {}; + return hotApplyInternal(options); + } + + function hotApplyInternal(options) { + hotApplyInvalidatedModules(); + + var cb; + var i; + var j; + var module; + var moduleId; + + function getAffectedStuff(updateModuleId) { + var outdatedModules = [updateModuleId]; + var outdatedDependencies = {}; + + var queue = outdatedModules.map(function(id) { + return { + chain: [id], + id: id + }; + }); + while (queue.length > 0) { + var queueItem = queue.pop(); + var moduleId = queueItem.id; + var chain = queueItem.chain; + module = installedModules[moduleId]; + if ( + !module || + (module.hot._selfAccepted && !module.hot._selfInvalidated) + ) + continue; + if (module.hot._selfDeclined) { + return { + type: "self-declined", + chain: chain, + moduleId: moduleId + }; + } + if (module.hot._main) { + return { + type: "unaccepted", + chain: chain, + moduleId: moduleId + }; + } + for (var i = 0; i < module.parents.length; i++) { + var parentId = module.parents[i]; + var parent = installedModules[parentId]; + if (!parent) continue; + if (parent.hot._declinedDependencies[moduleId]) { + return { + type: "declined", + chain: chain.concat([parentId]), + moduleId: moduleId, + parentId: parentId + }; + } + if (outdatedModules.indexOf(parentId) !== -1) continue; + if (parent.hot._acceptedDependencies[moduleId]) { + if (!outdatedDependencies[parentId]) + outdatedDependencies[parentId] = []; + addAllToSet(outdatedDependencies[parentId], [moduleId]); + continue; + } + delete outdatedDependencies[parentId]; + outdatedModules.push(parentId); + queue.push({ + chain: chain.concat([parentId]), + id: parentId + }); + } + } + + return { + type: "accepted", + moduleId: updateModuleId, + outdatedModules: outdatedModules, + outdatedDependencies: outdatedDependencies + }; + } + + function addAllToSet(a, b) { + for (var i = 0; i < b.length; i++) { + var item = b[i]; + if (a.indexOf(item) === -1) a.push(item); + } + } + + // at begin all updates modules are outdated + // the "outdated" status can propagate to parents if they don't accept the children + var outdatedDependencies = {}; + var outdatedModules = []; + var appliedUpdate = {}; + + var warnUnexpectedRequire = function warnUnexpectedRequire() { + console.warn( + "[HMR] unexpected require(" + result.moduleId + ") to disposed module" + ); + }; + + for (var id in hotUpdate) { + if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) { + moduleId = toModuleId(id); + /** @type {TODO} */ + var result; + if (hotUpdate[id]) { + result = getAffectedStuff(moduleId); + } else { + result = { + type: "disposed", + moduleId: id + }; + } + /** @type {Error|false} */ + var abortError = false; + var doApply = false; + var doDispose = false; + var chainInfo = ""; + if (result.chain) { + chainInfo = "\nUpdate propagation: " + result.chain.join(" -> "); + } + switch (result.type) { + case "self-declined": + if (options.onDeclined) options.onDeclined(result); + if (!options.ignoreDeclined) + abortError = new Error( + "Aborted because of self decline: " + + result.moduleId + + chainInfo + ); + break; + case "declined": + if (options.onDeclined) options.onDeclined(result); + if (!options.ignoreDeclined) + abortError = new Error( + "Aborted because of declined dependency: " + + result.moduleId + + " in " + + result.parentId + + chainInfo + ); + break; + case "unaccepted": + if (options.onUnaccepted) options.onUnaccepted(result); + if (!options.ignoreUnaccepted) + abortError = new Error( + "Aborted because " + moduleId + " is not accepted" + chainInfo + ); + break; + case "accepted": + if (options.onAccepted) options.onAccepted(result); + doApply = true; + break; + case "disposed": + if (options.onDisposed) options.onDisposed(result); + doDispose = true; + break; + default: + throw new Error("Unexception type " + result.type); + } + if (abortError) { + hotSetStatus("abort"); + return Promise.reject(abortError); + } + if (doApply) { + appliedUpdate[moduleId] = hotUpdate[moduleId]; + addAllToSet(outdatedModules, result.outdatedModules); + for (moduleId in result.outdatedDependencies) { + if ( + Object.prototype.hasOwnProperty.call( + result.outdatedDependencies, + moduleId + ) + ) { + if (!outdatedDependencies[moduleId]) + outdatedDependencies[moduleId] = []; + addAllToSet( + outdatedDependencies[moduleId], + result.outdatedDependencies[moduleId] + ); + } + } + } + if (doDispose) { + addAllToSet(outdatedModules, [result.moduleId]); + appliedUpdate[moduleId] = warnUnexpectedRequire; + } + } + } + + // Store self accepted outdated modules to require them later by the module system + var outdatedSelfAcceptedModules = []; + for (i = 0; i < outdatedModules.length; i++) { + moduleId = outdatedModules[i]; + if ( + installedModules[moduleId] && + installedModules[moduleId].hot._selfAccepted && + // removed self-accepted modules should not be required + appliedUpdate[moduleId] !== warnUnexpectedRequire && + // when called invalidate self-accepting is not possible + !installedModules[moduleId].hot._selfInvalidated + ) { + outdatedSelfAcceptedModules.push({ + module: moduleId, + parents: installedModules[moduleId].parents.slice(), + errorHandler: installedModules[moduleId].hot._selfAccepted + }); + } + } + + // Now in "dispose" phase + hotSetStatus("dispose"); + Object.keys(hotAvailableFilesMap).forEach(function(chunkId) { + if (hotAvailableFilesMap[chunkId] === false) { + hotDisposeChunk(chunkId); + } + }); + + var idx; + var queue = outdatedModules.slice(); + while (queue.length > 0) { + moduleId = queue.pop(); + module = installedModules[moduleId]; + if (!module) continue; + + var data = {}; + + // Call dispose handlers + var disposeHandlers = module.hot._disposeHandlers; + for (j = 0; j < disposeHandlers.length; j++) { + cb = disposeHandlers[j]; + cb(data); + } + hotCurrentModuleData[moduleId] = data; + + // disable module (this disables requires from this module) + module.hot.active = false; + + // remove module from cache + delete installedModules[moduleId]; + + // when disposing there is no need to call dispose handler + delete outdatedDependencies[moduleId]; + + // remove "parents" references from all children + for (j = 0; j < module.children.length; j++) { + var child = installedModules[module.children[j]]; + if (!child) continue; + idx = child.parents.indexOf(moduleId); + if (idx >= 0) { + child.parents.splice(idx, 1); + } + } + } + + // remove outdated dependency from module children + var dependency; + var moduleOutdatedDependencies; + for (moduleId in outdatedDependencies) { + if ( + Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId) + ) { + module = installedModules[moduleId]; + if (module) { + moduleOutdatedDependencies = outdatedDependencies[moduleId]; + for (j = 0; j < moduleOutdatedDependencies.length; j++) { + dependency = moduleOutdatedDependencies[j]; + idx = module.children.indexOf(dependency); + if (idx >= 0) module.children.splice(idx, 1); + } + } + } + } + + // Now in "apply" phase + hotSetStatus("apply"); + + if (hotUpdateNewHash !== undefined) { + hotCurrentHash = hotUpdateNewHash; + hotUpdateNewHash = undefined; + } + hotUpdate = undefined; + + // insert new code + for (moduleId in appliedUpdate) { + if (Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) { + modules[moduleId] = appliedUpdate[moduleId]; + } + } + + // call accept handlers + var error = null; + for (moduleId in outdatedDependencies) { + if ( + Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId) + ) { + module = installedModules[moduleId]; + if (module) { + moduleOutdatedDependencies = outdatedDependencies[moduleId]; + var callbacks = []; + for (i = 0; i < moduleOutdatedDependencies.length; i++) { + dependency = moduleOutdatedDependencies[i]; + cb = module.hot._acceptedDependencies[dependency]; + if (cb) { + if (callbacks.indexOf(cb) !== -1) continue; + callbacks.push(cb); + } + } + for (i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + try { + cb(moduleOutdatedDependencies); + } catch (err) { + if (options.onErrored) { + options.onErrored({ + type: "accept-errored", + moduleId: moduleId, + dependencyId: moduleOutdatedDependencies[i], + error: err + }); + } + if (!options.ignoreErrored) { + if (!error) error = err; + } + } + } + } + } + } + + // Load self accepted modules + for (i = 0; i < outdatedSelfAcceptedModules.length; i++) { + var item = outdatedSelfAcceptedModules[i]; + moduleId = item.module; + hotCurrentParents = item.parents; + hotCurrentChildModule = moduleId; + try { + $require$(moduleId); + } catch (err) { + if (typeof item.errorHandler === "function") { + try { + item.errorHandler(err); + } catch (err2) { + if (options.onErrored) { + options.onErrored({ + type: "self-accept-error-handler-errored", + moduleId: moduleId, + error: err2, + originalError: err + }); + } + if (!options.ignoreErrored) { + if (!error) error = err2; + } + if (!error) error = err; + } + } else { + if (options.onErrored) { + options.onErrored({ + type: "self-accept-errored", + moduleId: moduleId, + error: err + }); + } + if (!options.ignoreErrored) { + if (!error) error = err; + } + } + } + } + + // handle errors in accept handlers and self accepted module load + if (error) { + hotSetStatus("fail"); + return Promise.reject(error); + } + + if (hotQueuedInvalidatedModules) { + return hotApplyInternal(options).then(function(list) { + outdatedModules.forEach(function(moduleId) { + if (list.indexOf(moduleId) < 0) list.push(moduleId); + }); + return list; + }); + } + + hotSetStatus("idle"); + return new Promise(function(resolve) { + resolve(outdatedModules); + }); + } + + function hotApplyInvalidatedModules() { + if (hotQueuedInvalidatedModules) { + if (!hotUpdate) hotUpdate = {}; + hotQueuedInvalidatedModules.forEach(hotApplyInvalidatedModule); + hotQueuedInvalidatedModules = undefined; + return true; + } + } + + function hotApplyInvalidatedModule(moduleId) { + if (!Object.prototype.hasOwnProperty.call(hotUpdate, moduleId)) + hotUpdate[moduleId] = modules[moduleId]; + } +}; diff --git a/node_modules/webpack/lib/HotModuleReplacementPlugin.js b/node_modules/webpack/lib/HotModuleReplacementPlugin.js new file mode 100644 index 0000000..58a1f1f --- /dev/null +++ b/node_modules/webpack/lib/HotModuleReplacementPlugin.js @@ -0,0 +1,425 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { SyncBailHook } = require("tapable"); +const { RawSource } = require("webpack-sources"); +const Template = require("./Template"); +const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency"); +const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency"); +const ConstDependency = require("./dependencies/ConstDependency"); +const NullFactory = require("./NullFactory"); +const ParserHelpers = require("./ParserHelpers"); + +module.exports = class HotModuleReplacementPlugin { + constructor(options) { + this.options = options || {}; + this.multiStep = this.options.multiStep; + this.fullBuildTimeout = this.options.fullBuildTimeout || 200; + this.requestTimeout = this.options.requestTimeout || 10000; + } + + apply(compiler) { + const multiStep = this.multiStep; + const fullBuildTimeout = this.fullBuildTimeout; + const requestTimeout = this.requestTimeout; + const hotUpdateChunkFilename = + compiler.options.output.hotUpdateChunkFilename; + const hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename; + compiler.hooks.additionalPass.tapAsync( + "HotModuleReplacementPlugin", + callback => { + if (multiStep) return setTimeout(callback, fullBuildTimeout); + return callback(); + } + ); + + const addParserPlugins = (parser, parserOptions) => { + parser.hooks.expression + .for("__webpack_hash__") + .tap( + "HotModuleReplacementPlugin", + ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + "__webpack_require__.h()" + ) + ); + parser.hooks.evaluateTypeof + .for("__webpack_hash__") + .tap( + "HotModuleReplacementPlugin", + ParserHelpers.evaluateToString("string") + ); + parser.hooks.evaluateIdentifier.for("module.hot").tap( + { + name: "HotModuleReplacementPlugin", + before: "NodeStuffPlugin" + }, + expr => { + return ParserHelpers.evaluateToIdentifier( + "module.hot", + !!parser.state.compilation.hotUpdateChunkTemplate + )(expr); + } + ); + // TODO webpack 5: refactor this, no custom hooks + if (!parser.hooks.hotAcceptCallback) { + parser.hooks.hotAcceptCallback = new SyncBailHook([ + "expression", + "requests" + ]); + } + if (!parser.hooks.hotAcceptWithoutCallback) { + parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([ + "expression", + "requests" + ]); + } + parser.hooks.call + .for("module.hot.accept") + .tap("HotModuleReplacementPlugin", expr => { + if (!parser.state.compilation.hotUpdateChunkTemplate) { + return false; + } + if (expr.arguments.length >= 1) { + const arg = parser.evaluateExpression(expr.arguments[0]); + let params = []; + let requests = []; + if (arg.isString()) { + params = [arg]; + } else if (arg.isArray()) { + params = arg.items.filter(param => param.isString()); + } + if (params.length > 0) { + params.forEach((param, idx) => { + const request = param.string; + const dep = new ModuleHotAcceptDependency(request, param.range); + dep.optional = true; + dep.loc = Object.create(expr.loc); + dep.loc.index = idx; + parser.state.module.addDependency(dep); + requests.push(request); + }); + if (expr.arguments.length > 1) { + parser.hooks.hotAcceptCallback.call( + expr.arguments[1], + requests + ); + parser.walkExpression(expr.arguments[1]); // other args are ignored + return true; + } else { + parser.hooks.hotAcceptWithoutCallback.call(expr, requests); + return true; + } + } + } + }); + parser.hooks.call + .for("module.hot.decline") + .tap("HotModuleReplacementPlugin", expr => { + if (!parser.state.compilation.hotUpdateChunkTemplate) { + return false; + } + if (expr.arguments.length === 1) { + const arg = parser.evaluateExpression(expr.arguments[0]); + let params = []; + if (arg.isString()) { + params = [arg]; + } else if (arg.isArray()) { + params = arg.items.filter(param => param.isString()); + } + params.forEach((param, idx) => { + const dep = new ModuleHotDeclineDependency( + param.string, + param.range + ); + dep.optional = true; + dep.loc = Object.create(expr.loc); + dep.loc.index = idx; + parser.state.module.addDependency(dep); + }); + } + }); + parser.hooks.expression + .for("module.hot") + .tap("HotModuleReplacementPlugin", ParserHelpers.skipTraversal); + }; + + compiler.hooks.compilation.tap( + "HotModuleReplacementPlugin", + (compilation, { normalModuleFactory }) => { + // This applies the HMR plugin only to the targeted compiler + // It should not affect child compilations + if (compilation.compiler !== compiler) return; + + const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate; + if (!hotUpdateChunkTemplate) return; + + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + compilation.dependencyFactories.set( + ModuleHotAcceptDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + ModuleHotAcceptDependency, + new ModuleHotAcceptDependency.Template() + ); + + compilation.dependencyFactories.set( + ModuleHotDeclineDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + ModuleHotDeclineDependency, + new ModuleHotDeclineDependency.Template() + ); + + compilation.hooks.record.tap( + "HotModuleReplacementPlugin", + (compilation, records) => { + if (records.hash === compilation.hash) return; + records.hash = compilation.hash; + records.moduleHashs = {}; + for (const module of compilation.modules) { + const identifier = module.identifier(); + records.moduleHashs[identifier] = module.hash; + } + records.chunkHashs = {}; + for (const chunk of compilation.chunks) { + records.chunkHashs[chunk.id] = chunk.hash; + } + records.chunkModuleIds = {}; + for (const chunk of compilation.chunks) { + records.chunkModuleIds[chunk.id] = Array.from( + chunk.modulesIterable, + m => m.id + ); + } + } + ); + let initialPass = false; + let recompilation = false; + compilation.hooks.afterHash.tap("HotModuleReplacementPlugin", () => { + let records = compilation.records; + if (!records) { + initialPass = true; + return; + } + if (!records.hash) initialPass = true; + const preHash = records.preHash || "x"; + const prepreHash = records.prepreHash || "x"; + if (preHash === compilation.hash) { + recompilation = true; + compilation.modifyHash(prepreHash); + return; + } + records.prepreHash = records.hash || "x"; + records.preHash = compilation.hash; + compilation.modifyHash(records.prepreHash); + }); + compilation.hooks.shouldGenerateChunkAssets.tap( + "HotModuleReplacementPlugin", + () => { + if (multiStep && !recompilation && !initialPass) return false; + } + ); + compilation.hooks.needAdditionalPass.tap( + "HotModuleReplacementPlugin", + () => { + if (multiStep && !recompilation && !initialPass) return true; + } + ); + compilation.hooks.additionalChunkAssets.tap( + "HotModuleReplacementPlugin", + () => { + const records = compilation.records; + if (records.hash === compilation.hash) return; + if ( + !records.moduleHashs || + !records.chunkHashs || + !records.chunkModuleIds + ) + return; + for (const module of compilation.modules) { + const identifier = module.identifier(); + let hash = module.hash; + module.hotUpdate = records.moduleHashs[identifier] !== hash; + } + const hotUpdateMainContent = { + h: compilation.hash, + c: {} + }; + for (const key of Object.keys(records.chunkHashs)) { + const chunkId = isNaN(+key) ? key : +key; + const currentChunk = compilation.chunks.find( + chunk => `${chunk.id}` === key + ); + if (currentChunk) { + const newModules = currentChunk + .getModules() + .filter(module => module.hotUpdate); + const allModules = new Set(); + for (const module of currentChunk.modulesIterable) { + allModules.add(module.id); + } + const removedModules = records.chunkModuleIds[chunkId].filter( + id => !allModules.has(id) + ); + if (newModules.length > 0 || removedModules.length > 0) { + const source = hotUpdateChunkTemplate.render( + chunkId, + newModules, + removedModules, + compilation.hash, + compilation.moduleTemplates.javascript, + compilation.dependencyTemplates + ); + const { + path: filename, + info: assetInfo + } = compilation.getPathWithInfo(hotUpdateChunkFilename, { + hash: records.hash, + chunk: currentChunk + }); + compilation.additionalChunkAssets.push(filename); + compilation.emitAsset( + filename, + source, + Object.assign({ hotModuleReplacement: true }, assetInfo) + ); + hotUpdateMainContent.c[chunkId] = true; + currentChunk.files.push(filename); + compilation.hooks.chunkAsset.call(currentChunk, filename); + } + } else { + hotUpdateMainContent.c[chunkId] = false; + } + } + const source = new RawSource(JSON.stringify(hotUpdateMainContent)); + const { + path: filename, + info: assetInfo + } = compilation.getPathWithInfo(hotUpdateMainFilename, { + hash: records.hash + }); + compilation.emitAsset( + filename, + source, + Object.assign({ hotModuleReplacement: true }, assetInfo) + ); + } + ); + + const mainTemplate = compilation.mainTemplate; + + mainTemplate.hooks.hash.tap("HotModuleReplacementPlugin", hash => { + hash.update("HotMainTemplateDecorator"); + }); + + mainTemplate.hooks.moduleRequire.tap( + "HotModuleReplacementPlugin", + (_, chunk, hash, varModuleId) => { + return `hotCreateRequire(${varModuleId})`; + } + ); + + mainTemplate.hooks.requireExtensions.tap( + "HotModuleReplacementPlugin", + source => { + const buf = [source]; + buf.push(""); + buf.push("// __webpack_hash__"); + buf.push( + mainTemplate.requireFn + + ".h = function() { return hotCurrentHash; };" + ); + return Template.asString(buf); + } + ); + + const needChunkLoadingCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.chunks.length > 1) return true; + if (chunkGroup.getNumberOfChildren() > 0) return true; + } + return false; + }; + + mainTemplate.hooks.bootstrap.tap( + "HotModuleReplacementPlugin", + (source, chunk, hash) => { + source = mainTemplate.hooks.hotBootstrap.call(source, chunk, hash); + return Template.asString([ + source, + "", + hotInitCode + .replace(/\$require\$/g, mainTemplate.requireFn) + .replace(/\$hash\$/g, JSON.stringify(hash)) + .replace(/\$requestTimeout\$/g, requestTimeout) + .replace( + /\/\*foreachInstalledChunks\*\//g, + needChunkLoadingCode(chunk) + ? "for(var chunkId in installedChunks)" + : `var chunkId = ${JSON.stringify(chunk.id)};` + ) + ]); + } + ); + + mainTemplate.hooks.globalHash.tap( + "HotModuleReplacementPlugin", + () => true + ); + + mainTemplate.hooks.currentHash.tap( + "HotModuleReplacementPlugin", + (_, length) => { + if (isFinite(length)) { + return `hotCurrentHash.substr(0, ${length})`; + } else { + return "hotCurrentHash"; + } + } + ); + + mainTemplate.hooks.moduleObj.tap( + "HotModuleReplacementPlugin", + (source, chunk, hash, varModuleId) => { + return Template.asString([ + `${source},`, + `hot: hotCreateModule(${varModuleId}),`, + "parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),", + "children: []" + ]); + } + ); + + // TODO add HMR support for javascript/esm + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("HotModuleReplacementPlugin", addParserPlugins); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("HotModuleReplacementPlugin", addParserPlugins); + + compilation.hooks.normalModuleLoader.tap( + "HotModuleReplacementPlugin", + context => { + context.hot = true; + } + ); + } + ); + } +}; + +const hotInitCode = Template.getFunctionContent( + require("./HotModuleReplacement.runtime") +); diff --git a/node_modules/webpack/lib/HotUpdateChunk.js b/node_modules/webpack/lib/HotUpdateChunk.js new file mode 100644 index 0000000..8845643 --- /dev/null +++ b/node_modules/webpack/lib/HotUpdateChunk.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Chunk = require("./Chunk"); + +class HotUpdateChunk extends Chunk { + constructor() { + super(); + /** @type {(string|number)[]} */ + this.removedModules = undefined; + } +} + +module.exports = HotUpdateChunk; diff --git a/node_modules/webpack/lib/HotUpdateChunkTemplate.js b/node_modules/webpack/lib/HotUpdateChunkTemplate.js new file mode 100644 index 0000000..92ab8db --- /dev/null +++ b/node_modules/webpack/lib/HotUpdateChunkTemplate.js @@ -0,0 +1,78 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("./Template"); +const HotUpdateChunk = require("./HotUpdateChunk"); +const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable"); + +module.exports = class HotUpdateChunkTemplate extends Tapable { + constructor(outputOptions) { + super(); + this.outputOptions = outputOptions || {}; + this.hooks = { + modules: new SyncWaterfallHook([ + "source", + "modules", + "removedModules", + "moduleTemplate", + "dependencyTemplates" + ]), + render: new SyncWaterfallHook([ + "source", + "modules", + "removedModules", + "hash", + "id", + "moduleTemplate", + "dependencyTemplates" + ]), + hash: new SyncHook(["hash"]) + }; + } + + render( + id, + modules, + removedModules, + hash, + moduleTemplate, + dependencyTemplates + ) { + const hotUpdateChunk = new HotUpdateChunk(); + hotUpdateChunk.id = id; + hotUpdateChunk.setModules(modules); + hotUpdateChunk.removedModules = removedModules; + const modulesSource = Template.renderChunkModules( + hotUpdateChunk, + m => typeof m.source === "function", + moduleTemplate, + dependencyTemplates + ); + const core = this.hooks.modules.call( + modulesSource, + modules, + removedModules, + moduleTemplate, + dependencyTemplates + ); + const source = this.hooks.render.call( + core, + modules, + removedModules, + hash, + id, + moduleTemplate, + dependencyTemplates + ); + return source; + } + + updateHash(hash) { + hash.update("HotUpdateChunkTemplate"); + hash.update("1"); + this.hooks.hash.call(hash); + } +}; diff --git a/node_modules/webpack/lib/IgnorePlugin.js b/node_modules/webpack/lib/IgnorePlugin.js new file mode 100644 index 0000000..cd824db --- /dev/null +++ b/node_modules/webpack/lib/IgnorePlugin.js @@ -0,0 +1,91 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/IgnorePlugin.json"); + +/** @typedef {import("../declarations/plugins/IgnorePlugin").IgnorePluginOptions} IgnorePluginOptions */ +/** @typedef {import("./Compiler")} Compiler */ + +class IgnorePlugin { + /** + * @param {IgnorePluginOptions} options IgnorePlugin options + */ + constructor(options) { + // TODO webpack 5 remove this compat-layer + if (arguments.length > 1 || options instanceof RegExp) { + options = { + resourceRegExp: arguments[0], + contextRegExp: arguments[1] + }; + } + + validateOptions(schema, options, "IgnorePlugin"); + this.options = options; + + /** @private @type {Function} */ + this.checkIgnore = this.checkIgnore.bind(this); + } + + /** + * Note that if "contextRegExp" is given, both the "resourceRegExp" + * and "contextRegExp" have to match. + * + * @param {TODO} result result + * @returns {TODO|null} returns result or null if result should be ignored + */ + checkIgnore(result) { + if (!result) return result; + + if ( + "checkResource" in this.options && + this.options.checkResource && + this.options.checkResource(result.request, result.context) + ) { + // TODO webpack 5 remove checkContext, as checkResource already gets context + if ("checkContext" in this.options && this.options.checkContext) { + if (this.options.checkContext(result.context)) { + return null; + } + } else { + return null; + } + } + + if ( + "resourceRegExp" in this.options && + this.options.resourceRegExp && + this.options.resourceRegExp.test(result.request) + ) { + if ("contextRegExp" in this.options && this.options.contextRegExp) { + // if "contextRegExp" is given, + // both the "resourceRegExp" and "contextRegExp" have to match. + if (this.options.contextRegExp.test(result.context)) { + return null; + } + } else { + return null; + } + } + + return result; + } + + /** + * @param {Compiler} compiler Webpack Compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.normalModuleFactory.tap("IgnorePlugin", nmf => { + nmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore); + }); + compiler.hooks.contextModuleFactory.tap("IgnorePlugin", cmf => { + cmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore); + }); + } +} + +module.exports = IgnorePlugin; diff --git a/node_modules/webpack/lib/JavascriptGenerator.js b/node_modules/webpack/lib/JavascriptGenerator.js new file mode 100644 index 0000000..882f7d4 --- /dev/null +++ b/node_modules/webpack/lib/JavascriptGenerator.js @@ -0,0 +1,229 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { RawSource, ReplaceSource } = require("webpack-sources"); + +// TODO: clean up this file +// replace with newer constructs + +// TODO: remove DependencyVariables and replace them with something better + +class JavascriptGenerator { + generate(module, dependencyTemplates, runtimeTemplate) { + const originalSource = module.originalSource(); + if (!originalSource) { + return new RawSource("throw new Error('No source available');"); + } + + const source = new ReplaceSource(originalSource); + + this.sourceBlock( + module, + module, + [], + dependencyTemplates, + source, + runtimeTemplate + ); + + return source; + } + + sourceBlock( + module, + block, + availableVars, + dependencyTemplates, + source, + runtimeTemplate + ) { + for (const dependency of block.dependencies) { + this.sourceDependency( + dependency, + dependencyTemplates, + source, + runtimeTemplate + ); + } + + /** + * Get the variables of all blocks that we need to inject. + * These will contain the variable name and its expression. + * The name will be added as a parameter in a IIFE the expression as its value. + */ + const vars = block.variables.reduce((result, value) => { + const variable = this.sourceVariables( + value, + availableVars, + dependencyTemplates, + runtimeTemplate + ); + + if (variable) { + result.push(variable); + } + + return result; + }, []); + + /** + * if we actually have variables + * this is important as how #splitVariablesInUniqueNamedChunks works + * it will always return an array in an array which would lead to a IIFE wrapper around + * a module if we do this with an empty vars array. + */ + if (vars.length > 0) { + /** + * Split all variables up into chunks of unique names. + * e.g. imagine you have the following variable names that need to be injected: + * [foo, bar, baz, foo, some, more] + * we can not inject "foo" twice, therefore we just make two IIFEs like so: + * (function(foo, bar, baz){ + * (function(foo, some, more){ + * … + * }(…)); + * }(…)); + * + * "splitVariablesInUniqueNamedChunks" splits the variables shown above up to this: + * [[foo, bar, baz], [foo, some, more]] + */ + const injectionVariableChunks = this.splitVariablesInUniqueNamedChunks( + vars + ); + + // create all the beginnings of IIFEs + const functionWrapperStarts = injectionVariableChunks.map( + variableChunk => { + return this.variableInjectionFunctionWrapperStartCode( + variableChunk.map(variable => variable.name) + ); + } + ); + + // and all the ends + const functionWrapperEnds = injectionVariableChunks.map(variableChunk => { + return this.variableInjectionFunctionWrapperEndCode( + module, + variableChunk.map(variable => variable.expression), + block + ); + }); + + // join them to one big string + const varStartCode = functionWrapperStarts.join(""); + + // reverse the ends first before joining them, as the last added must be the inner most + const varEndCode = functionWrapperEnds.reverse().join(""); + + // if we have anything, add it to the source + if (varStartCode && varEndCode) { + const start = block.range ? block.range[0] : -10; + const end = block.range + ? block.range[1] + : module.originalSource().size() + 1; + source.insert(start + 0.5, varStartCode); + source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode); + } + } + + for (const childBlock of block.blocks) { + this.sourceBlock( + module, + childBlock, + availableVars.concat(vars), + dependencyTemplates, + source, + runtimeTemplate + ); + } + } + + sourceDependency(dependency, dependencyTemplates, source, runtimeTemplate) { + const template = dependencyTemplates.get(dependency.constructor); + if (!template) { + throw new Error( + "No template for dependency: " + dependency.constructor.name + ); + } + template.apply(dependency, source, runtimeTemplate, dependencyTemplates); + } + + sourceVariables( + variable, + availableVars, + dependencyTemplates, + runtimeTemplate + ) { + const name = variable.name; + const expr = variable.expressionSource( + dependencyTemplates, + runtimeTemplate + ); + + if ( + availableVars.some( + v => v.name === name && v.expression.source() === expr.source() + ) + ) { + return; + } + return { + name: name, + expression: expr + }; + } + + /* + * creates the start part of a IIFE around the module to inject a variable name + * (function(…){ <- this part + * }.call(…)) + */ + variableInjectionFunctionWrapperStartCode(varNames) { + const args = varNames.join(", "); + return `/* WEBPACK VAR INJECTION */(function(${args}) {`; + } + + contextArgument(module, block) { + if (this === block) { + return module.exportsArgument; + } + return "this"; + } + + /* + * creates the end part of a IIFE around the module to inject a variable name + * (function(…){ + * }.call(…)) <- this part + */ + variableInjectionFunctionWrapperEndCode(module, varExpressions, block) { + const firstParam = this.contextArgument(module, block); + const furtherParams = varExpressions.map(e => e.source()).join(", "); + return `}.call(${firstParam}, ${furtherParams}))`; + } + + splitVariablesInUniqueNamedChunks(vars) { + const startState = [[]]; + return vars.reduce((chunks, variable) => { + const current = chunks[chunks.length - 1]; + // check if variable with same name exists already + // if so create a new chunk of variables. + const variableNameAlreadyExists = current.some( + v => v.name === variable.name + ); + + if (variableNameAlreadyExists) { + // start new chunk with current variable + chunks.push([variable]); + } else { + // else add it to current chunk + current.push(variable); + } + return chunks; + }, startState); + } +} + +module.exports = JavascriptGenerator; diff --git a/node_modules/webpack/lib/JavascriptModulesPlugin.js b/node_modules/webpack/lib/JavascriptModulesPlugin.js new file mode 100644 index 0000000..2c1bbe4 --- /dev/null +++ b/node_modules/webpack/lib/JavascriptModulesPlugin.js @@ -0,0 +1,185 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Parser = require("./Parser"); +const Template = require("./Template"); +const { ConcatSource } = require("webpack-sources"); +const JavascriptGenerator = require("./JavascriptGenerator"); +const createHash = require("./util/createHash"); + +class JavascriptModulesPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "JavascriptModulesPlugin", + (compilation, { normalModuleFactory }) => { + normalModuleFactory.hooks.createParser + .for("javascript/auto") + .tap("JavascriptModulesPlugin", options => { + return new Parser(options, "auto"); + }); + normalModuleFactory.hooks.createParser + .for("javascript/dynamic") + .tap("JavascriptModulesPlugin", options => { + return new Parser(options, "script"); + }); + normalModuleFactory.hooks.createParser + .for("javascript/esm") + .tap("JavascriptModulesPlugin", options => { + return new Parser(options, "module"); + }); + normalModuleFactory.hooks.createGenerator + .for("javascript/auto") + .tap("JavascriptModulesPlugin", () => { + return new JavascriptGenerator(); + }); + normalModuleFactory.hooks.createGenerator + .for("javascript/dynamic") + .tap("JavascriptModulesPlugin", () => { + return new JavascriptGenerator(); + }); + normalModuleFactory.hooks.createGenerator + .for("javascript/esm") + .tap("JavascriptModulesPlugin", () => { + return new JavascriptGenerator(); + }); + compilation.mainTemplate.hooks.renderManifest.tap( + "JavascriptModulesPlugin", + (result, options) => { + const chunk = options.chunk; + const hash = options.hash; + const fullHash = options.fullHash; + const outputOptions = options.outputOptions; + const moduleTemplates = options.moduleTemplates; + const dependencyTemplates = options.dependencyTemplates; + + const filenameTemplate = + chunk.filenameTemplate || outputOptions.filename; + + const useChunkHash = compilation.mainTemplate.useChunkHash(chunk); + + result.push({ + render: () => + compilation.mainTemplate.render( + hash, + chunk, + moduleTemplates.javascript, + dependencyTemplates + ), + filenameTemplate, + pathOptions: { + noChunkHash: !useChunkHash, + contentHashType: "javascript", + chunk + }, + identifier: `chunk${chunk.id}`, + hash: useChunkHash ? chunk.hash : fullHash + }); + return result; + } + ); + compilation.mainTemplate.hooks.modules.tap( + "JavascriptModulesPlugin", + (source, chunk, hash, moduleTemplate, dependencyTemplates) => { + return Template.renderChunkModules( + chunk, + m => typeof m.source === "function", + moduleTemplate, + dependencyTemplates, + "/******/ " + ); + } + ); + compilation.chunkTemplate.hooks.renderManifest.tap( + "JavascriptModulesPlugin", + (result, options) => { + const chunk = options.chunk; + const outputOptions = options.outputOptions; + const moduleTemplates = options.moduleTemplates; + const dependencyTemplates = options.dependencyTemplates; + const filenameTemplate = + chunk.filenameTemplate || outputOptions.chunkFilename; + + result.push({ + render: () => + this.renderJavascript( + compilation.chunkTemplate, + chunk, + moduleTemplates.javascript, + dependencyTemplates + ), + filenameTemplate, + pathOptions: { + chunk, + contentHashType: "javascript" + }, + identifier: `chunk${chunk.id}`, + hash: chunk.hash + }); + + return result; + } + ); + compilation.hooks.contentHash.tap("JavascriptModulesPlugin", chunk => { + const outputOptions = compilation.outputOptions; + const { + hashSalt, + hashDigest, + hashDigestLength, + hashFunction + } = outputOptions; + const hash = createHash(hashFunction); + if (hashSalt) hash.update(hashSalt); + const template = chunk.hasRuntime() + ? compilation.mainTemplate + : compilation.chunkTemplate; + hash.update(`${chunk.id} `); + hash.update(chunk.ids ? chunk.ids.join(",") : ""); + template.updateHashForChunk( + hash, + chunk, + compilation.moduleTemplates.javascript, + compilation.dependencyTemplates + ); + for (const m of chunk.modulesIterable) { + if (typeof m.source === "function") { + hash.update(m.hash); + } + } + const digest = /** @type {string} */ (hash.digest(hashDigest)); + chunk.contentHash.javascript = digest.substr(0, hashDigestLength); + }); + } + ); + } + + renderJavascript(chunkTemplate, chunk, moduleTemplate, dependencyTemplates) { + const moduleSources = Template.renderChunkModules( + chunk, + m => typeof m.source === "function", + moduleTemplate, + dependencyTemplates + ); + const core = chunkTemplate.hooks.modules.call( + moduleSources, + chunk, + moduleTemplate, + dependencyTemplates + ); + let source = chunkTemplate.hooks.render.call( + core, + chunk, + moduleTemplate, + dependencyTemplates + ); + if (chunk.hasEntryModule()) { + source = chunkTemplate.hooks.renderWithEntry.call(source, chunk); + } + chunk.rendered = true; + return new ConcatSource(source, ";"); + } +} + +module.exports = JavascriptModulesPlugin; diff --git a/node_modules/webpack/lib/JsonGenerator.js b/node_modules/webpack/lib/JsonGenerator.js new file mode 100644 index 0000000..bac87c4 --- /dev/null +++ b/node_modules/webpack/lib/JsonGenerator.js @@ -0,0 +1,57 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource, RawSource } = require("webpack-sources"); + +const stringifySafe = data => { + const stringified = JSON.stringify(data); + if (!stringified) { + return undefined; // Invalid JSON + } + + return stringified.replace(/\u2028|\u2029/g, str => + str === "\u2029" ? "\\u2029" : "\\u2028" + ); // invalid in JavaScript but valid JSON +}; + +class JsonGenerator { + generate(module, dependencyTemplates, runtimeTemplate) { + const source = new ConcatSource(); + const data = module.buildInfo.jsonData; + if (data === undefined) { + return new RawSource( + runtimeTemplate.missingModuleStatement({ + request: module.rawRequest + }) + ); + } + let finalJson; + if ( + Array.isArray(module.buildMeta.providedExports) && + !module.isUsed("default") + ) { + // Only some exports are used: We can optimize here, by only generating a part of the JSON + const reducedJson = {}; + for (const exportName of module.buildMeta.providedExports) { + if (exportName === "default") continue; + const used = module.isUsed(exportName); + if (used) { + reducedJson[used] = data[exportName]; + } + } + finalJson = reducedJson; + } else { + finalJson = data; + } + // Use JSON because JSON.parse() is much faster than JavaScript evaluation + const jsonSource = JSON.stringify(stringifySafe(finalJson)); + const jsonExpr = `JSON.parse(${jsonSource})`; + source.add(`${module.moduleArgument}.exports = ${jsonExpr};`); + return source; + } +} + +module.exports = JsonGenerator; diff --git a/node_modules/webpack/lib/JsonModulesPlugin.js b/node_modules/webpack/lib/JsonModulesPlugin.js new file mode 100644 index 0000000..20b8a03 --- /dev/null +++ b/node_modules/webpack/lib/JsonModulesPlugin.js @@ -0,0 +1,30 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const JsonParser = require("./JsonParser"); +const JsonGenerator = require("./JsonGenerator"); + +class JsonModulesPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "JsonModulesPlugin", + (compilation, { normalModuleFactory }) => { + normalModuleFactory.hooks.createParser + .for("json") + .tap("JsonModulesPlugin", () => { + return new JsonParser(); + }); + normalModuleFactory.hooks.createGenerator + .for("json") + .tap("JsonModulesPlugin", () => { + return new JsonGenerator(); + }); + } + ); + } +} + +module.exports = JsonModulesPlugin; diff --git a/node_modules/webpack/lib/JsonParser.js b/node_modules/webpack/lib/JsonParser.js new file mode 100644 index 0000000..f0c5977 --- /dev/null +++ b/node_modules/webpack/lib/JsonParser.js @@ -0,0 +1,27 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const parseJson = require("json-parse-better-errors"); +const JsonExportsDependency = require("./dependencies/JsonExportsDependency"); + +class JsonParser { + constructor(options) { + this.options = options; + } + + parse(source, state) { + const data = parseJson(source[0] === "\ufeff" ? source.slice(1) : source); + state.module.buildInfo.jsonData = data; + state.module.buildMeta.exportsType = "named"; + if (typeof data === "object" && data) { + state.module.addDependency(new JsonExportsDependency(Object.keys(data))); + } + state.module.addDependency(new JsonExportsDependency(["default"])); + return state; + } +} + +module.exports = JsonParser; diff --git a/node_modules/webpack/lib/LibManifestPlugin.js b/node_modules/webpack/lib/LibManifestPlugin.js new file mode 100644 index 0000000..05e98b0 --- /dev/null +++ b/node_modules/webpack/lib/LibManifestPlugin.js @@ -0,0 +1,90 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const asyncLib = require("neo-async"); +const SingleEntryDependency = require("./dependencies/SingleEntryDependency"); + +class LibManifestPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.emit.tapAsync( + "LibManifestPlugin", + (compilation, callback) => { + asyncLib.forEach( + compilation.chunks, + (chunk, callback) => { + if (!chunk.isOnlyInitial()) { + callback(); + return; + } + const targetPath = compilation.getPath(this.options.path, { + hash: compilation.hash, + chunk + }); + const name = + this.options.name && + compilation.getPath(this.options.name, { + hash: compilation.hash, + chunk + }); + const manifest = { + name, + type: this.options.type, + content: Array.from(chunk.modulesIterable, module => { + if ( + this.options.entryOnly && + !module.reasons.some( + r => r.dependency instanceof SingleEntryDependency + ) + ) { + return; + } + if (module.libIdent) { + const ident = module.libIdent({ + context: this.options.context || compiler.options.context + }); + if (ident) { + return { + ident, + data: { + id: module.id, + buildMeta: module.buildMeta + } + }; + } + } + }) + .filter(Boolean) + .reduce((obj, item) => { + obj[item.ident] = item.data; + return obj; + }, Object.create(null)) + }; + // Apply formatting to content if format flag is true; + const manifestContent = this.options.format + ? JSON.stringify(manifest, null, 2) + : JSON.stringify(manifest); + const content = Buffer.from(manifestContent, "utf8"); + compiler.outputFileSystem.mkdirp(path.dirname(targetPath), err => { + if (err) return callback(err); + compiler.outputFileSystem.writeFile( + targetPath, + content, + callback + ); + }); + }, + callback + ); + } + ); + } +} +module.exports = LibManifestPlugin; diff --git a/node_modules/webpack/lib/LibraryTemplatePlugin.js b/node_modules/webpack/lib/LibraryTemplatePlugin.js new file mode 100644 index 0000000..87b558c --- /dev/null +++ b/node_modules/webpack/lib/LibraryTemplatePlugin.js @@ -0,0 +1,186 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const SetVarMainTemplatePlugin = require("./SetVarMainTemplatePlugin"); + +/** @typedef {import("../declarations/WebpackOptions").LibraryCustomUmdObject} LibraryCustomUmdObject */ +/** @typedef {import("./Compiler")} Compiler */ + +/** + * @param {string[]} accessor the accessor to convert to path + * @returns {string} the path + */ +const accessorToObjectAccess = accessor => { + return accessor.map(a => `[${JSON.stringify(a)}]`).join(""); +}; + +/** + * @param {string=} base the path prefix + * @param {string|string[]|LibraryCustomUmdObject} accessor the accessor + * @param {"amd" | "commonjs" | "root"} umdProperty property used when a custom umd object is provided + * @param {string=} joinWith the element separator + * @returns {string} the path + */ +const accessorAccess = (base, accessor, umdProperty, joinWith = "; ") => { + const normalizedAccessor = + typeof accessor === "object" && !Array.isArray(accessor) + ? accessor[umdProperty] + : accessor; + const accessors = Array.isArray(normalizedAccessor) + ? normalizedAccessor + : [normalizedAccessor]; + return accessors + .map((_, idx) => { + const a = base + ? base + accessorToObjectAccess(accessors.slice(0, idx + 1)) + : accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1)); + if (idx === accessors.length - 1) return a; + if (idx === 0 && base === undefined) { + return `${a} = typeof ${a} === "object" ? ${a} : {}`; + } + return `${a} = ${a} || {}`; + }) + .join(joinWith); +}; + +class LibraryTemplatePlugin { + /** + * @param {string|string[]|LibraryCustomUmdObject} name name of library + * @param {string} target type of library + * @param {boolean} umdNamedDefine setting this to true will name the UMD module + * @param {string|TODO} auxiliaryComment comment in the UMD wrapper + * @param {string|string[]} exportProperty which export should be exposed as library + */ + constructor(name, target, umdNamedDefine, auxiliaryComment, exportProperty) { + this.name = name; + this.target = target; + this.umdNamedDefine = umdNamedDefine; + this.auxiliaryComment = auxiliaryComment; + this.exportProperty = exportProperty; + } + + /** + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + compiler.hooks.thisCompilation.tap("LibraryTemplatePlugin", compilation => { + if (this.exportProperty) { + const ExportPropertyMainTemplatePlugin = require("./ExportPropertyMainTemplatePlugin"); + new ExportPropertyMainTemplatePlugin(this.exportProperty).apply( + compilation + ); + } + switch (this.target) { + case "var": + if ( + !this.name || + (typeof this.name === "object" && !Array.isArray(this.name)) + ) { + throw new Error( + "library name must be set and not an UMD custom object for non-UMD target" + ); + } + new SetVarMainTemplatePlugin( + `var ${accessorAccess(undefined, this.name, "root")}`, + false + ).apply(compilation); + break; + case "assign": + new SetVarMainTemplatePlugin( + accessorAccess(undefined, this.name, "root"), + false + ).apply(compilation); + break; + case "this": + case "self": + case "window": + if (this.name) { + new SetVarMainTemplatePlugin( + accessorAccess(this.target, this.name, "root"), + false + ).apply(compilation); + } else { + new SetVarMainTemplatePlugin(this.target, true).apply(compilation); + } + break; + case "global": + if (this.name) { + new SetVarMainTemplatePlugin( + accessorAccess( + compilation.runtimeTemplate.outputOptions.globalObject, + this.name, + "root" + ), + false + ).apply(compilation); + } else { + new SetVarMainTemplatePlugin( + compilation.runtimeTemplate.outputOptions.globalObject, + true + ).apply(compilation); + } + break; + case "commonjs": + if (this.name) { + new SetVarMainTemplatePlugin( + accessorAccess("exports", this.name, "commonjs"), + false + ).apply(compilation); + } else { + new SetVarMainTemplatePlugin("exports", true).apply(compilation); + } + break; + case "commonjs2": + case "commonjs-module": + new SetVarMainTemplatePlugin("module.exports", false).apply( + compilation + ); + break; + case "amd": + case "amd-require": { + const AmdMainTemplatePlugin = require("./AmdMainTemplatePlugin"); + if (this.name && typeof this.name !== "string") { + throw new Error("library name must be a string for amd target"); + } + new AmdMainTemplatePlugin({ + name: this.name, + requireAsWrapper: this.target === "amd-require" + }).apply(compilation); + break; + } + case "umd": + case "umd2": { + const UmdMainTemplatePlugin = require("./UmdMainTemplatePlugin"); + new UmdMainTemplatePlugin(this.name, { + optionalAmdExternalAsGlobal: this.target === "umd2", + namedDefine: this.umdNamedDefine, + auxiliaryComment: this.auxiliaryComment + }).apply(compilation); + break; + } + case "jsonp": { + const JsonpExportMainTemplatePlugin = require("./web/JsonpExportMainTemplatePlugin"); + if (typeof this.name !== "string") + throw new Error("library name must be a string for jsonp target"); + new JsonpExportMainTemplatePlugin(this.name).apply(compilation); + break; + } + case "system": { + const SystemMainTemplatePlugin = require("./SystemMainTemplatePlugin"); + new SystemMainTemplatePlugin({ + name: this.name + }).apply(compilation); + break; + } + default: + throw new Error(`${this.target} is not a valid Library target`); + } + }); + } +} + +module.exports = LibraryTemplatePlugin; diff --git a/node_modules/webpack/lib/LoaderOptionsPlugin.js b/node_modules/webpack/lib/LoaderOptionsPlugin.js new file mode 100644 index 0000000..651987b --- /dev/null +++ b/node_modules/webpack/lib/LoaderOptionsPlugin.js @@ -0,0 +1,58 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/LoaderOptionsPlugin.json"); + +/** @typedef {import("../declarations/plugins/LoaderOptionsPlugin").LoaderOptionsPluginOptions} LoaderOptionsPluginOptions */ + +class LoaderOptionsPlugin { + /** + * @param {LoaderOptionsPluginOptions} options options object + */ + constructor(options) { + validateOptions(schema, options || {}, "Loader Options Plugin"); + + if (typeof options !== "object") options = {}; + if (!options.test) { + options.test = { + test: () => true + }; + } + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap("LoaderOptionsPlugin", compilation => { + compilation.hooks.normalModuleLoader.tap( + "LoaderOptionsPlugin", + (context, module) => { + const resource = module.resource; + if (!resource) return; + const i = resource.indexOf("?"); + if ( + ModuleFilenameHelpers.matchObject( + options, + i < 0 ? resource : resource.substr(0, i) + ) + ) { + for (const key of Object.keys(options)) { + if (key === "include" || key === "exclude" || key === "test") { + continue; + } + context[key] = options[key]; + } + } + } + ); + }); + } +} + +module.exports = LoaderOptionsPlugin; diff --git a/node_modules/webpack/lib/LoaderTargetPlugin.js b/node_modules/webpack/lib/LoaderTargetPlugin.js new file mode 100644 index 0000000..99ffbc9 --- /dev/null +++ b/node_modules/webpack/lib/LoaderTargetPlugin.js @@ -0,0 +1,24 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class LoaderTargetPlugin { + constructor(target) { + this.target = target; + } + + apply(compiler) { + compiler.hooks.compilation.tap("LoaderTargetPlugin", compilation => { + compilation.hooks.normalModuleLoader.tap( + "LoaderTargetPlugin", + loaderContext => { + loaderContext.target = this.target; + } + ); + }); + } +} + +module.exports = LoaderTargetPlugin; diff --git a/node_modules/webpack/lib/MainTemplate.js b/node_modules/webpack/lib/MainTemplate.js new file mode 100644 index 0000000..5134106 --- /dev/null +++ b/node_modules/webpack/lib/MainTemplate.js @@ -0,0 +1,568 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { + ConcatSource, + OriginalSource, + PrefixSource, + RawSource +} = require("webpack-sources"); +const { + Tapable, + SyncWaterfallHook, + SyncHook, + SyncBailHook +} = require("tapable"); +const Template = require("./Template"); + +/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./Module")} Module} */ +/** @typedef {import("./util/createHash").Hash} Hash} */ +/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate} */ + +/** + * @typedef {Object} RenderManifestOptions + * @property {Chunk} chunk the chunk used to render + * @property {string} hash + * @property {string} fullHash + * @property {TODO} outputOptions + * @property {{javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates + * @property {Map<TODO, TODO>} dependencyTemplates + */ + +// require function shortcuts: +// __webpack_require__.s = the module id of the entry point +// __webpack_require__.c = the module cache +// __webpack_require__.m = the module functions +// __webpack_require__.p = the bundle public path +// __webpack_require__.i = the identity function used for harmony imports +// __webpack_require__.e = the chunk ensure function +// __webpack_require__.d = the exported property define getter function +// __webpack_require__.o = Object.prototype.hasOwnProperty.call +// __webpack_require__.r = define compatibility on export +// __webpack_require__.t = create a fake namespace object +// __webpack_require__.n = compatibility get default export +// __webpack_require__.h = the webpack hash +// __webpack_require__.w = an object containing all installed WebAssembly.Instance export objects keyed by module id +// __webpack_require__.oe = the uncaught error handler for the webpack runtime +// __webpack_require__.nc = the script nonce + +module.exports = class MainTemplate extends Tapable { + /** + * + * @param {TODO=} outputOptions output options for the MainTemplate + */ + constructor(outputOptions) { + super(); + /** @type {TODO?} */ + this.outputOptions = outputOptions || {}; + this.hooks = { + /** @type {SyncWaterfallHook<TODO[], RenderManifestOptions>} */ + renderManifest: new SyncWaterfallHook(["result", "options"]), + modules: new SyncWaterfallHook([ + "modules", + "chunk", + "hash", + "moduleTemplate", + "dependencyTemplates" + ]), + moduleObj: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "moduleIdExpression" + ]), + requireEnsure: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "chunkIdExpression" + ]), + bootstrap: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "moduleTemplate", + "dependencyTemplates" + ]), + localVars: new SyncWaterfallHook(["source", "chunk", "hash"]), + require: new SyncWaterfallHook(["source", "chunk", "hash"]), + requireExtensions: new SyncWaterfallHook(["source", "chunk", "hash"]), + /** @type {SyncWaterfallHook<string, Chunk, string>} */ + beforeStartup: new SyncWaterfallHook(["source", "chunk", "hash"]), + /** @type {SyncWaterfallHook<string, Chunk, string>} */ + startup: new SyncWaterfallHook(["source", "chunk", "hash"]), + /** @type {SyncWaterfallHook<string, Chunk, string>} */ + afterStartup: new SyncWaterfallHook(["source", "chunk", "hash"]), + render: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "moduleTemplate", + "dependencyTemplates" + ]), + renderWithEntry: new SyncWaterfallHook(["source", "chunk", "hash"]), + moduleRequire: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "moduleIdExpression" + ]), + addModule: new SyncWaterfallHook([ + "source", + "chunk", + "hash", + "moduleIdExpression", + "moduleExpression" + ]), + currentHash: new SyncWaterfallHook(["source", "requestedLength"]), + assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]), + hash: new SyncHook(["hash"]), + hashForChunk: new SyncHook(["hash", "chunk"]), + globalHashPaths: new SyncWaterfallHook(["paths"]), + globalHash: new SyncBailHook(["chunk", "paths"]), + + // TODO this should be moved somewhere else + // It's weird here + hotBootstrap: new SyncWaterfallHook(["source", "chunk", "hash"]) + }; + this.hooks.startup.tap("MainTemplate", (source, chunk, hash) => { + /** @type {string[]} */ + const buf = []; + if (chunk.entryModule) { + buf.push("// Load entry module and return exports"); + buf.push( + `return ${this.renderRequireFunctionForModule( + hash, + chunk, + JSON.stringify(chunk.entryModule.id) + )}(${this.requireFn}.s = ${JSON.stringify(chunk.entryModule.id)});` + ); + } + return Template.asString(buf); + }); + this.hooks.render.tap( + "MainTemplate", + (bootstrapSource, chunk, hash, moduleTemplate, dependencyTemplates) => { + const source = new ConcatSource(); + source.add("/******/ (function(modules) { // webpackBootstrap\n"); + source.add(new PrefixSource("/******/", bootstrapSource)); + source.add("/******/ })\n"); + source.add( + "/************************************************************************/\n" + ); + source.add("/******/ ("); + source.add( + this.hooks.modules.call( + new RawSource(""), + chunk, + hash, + moduleTemplate, + dependencyTemplates + ) + ); + source.add(")"); + return source; + } + ); + this.hooks.localVars.tap("MainTemplate", (source, chunk, hash) => { + return Template.asString([ + source, + "// The module cache", + "var installedModules = {};" + ]); + }); + this.hooks.require.tap("MainTemplate", (source, chunk, hash) => { + return Template.asString([ + source, + "// Check if module is in cache", + "if(installedModules[moduleId]) {", + Template.indent("return installedModules[moduleId].exports;"), + "}", + "// Create a new module (and put it into the cache)", + "var module = installedModules[moduleId] = {", + Template.indent(this.hooks.moduleObj.call("", chunk, hash, "moduleId")), + "};", + "", + Template.asString( + outputOptions.strictModuleExceptionHandling + ? [ + "// Execute the module function", + "var threw = true;", + "try {", + Template.indent([ + `modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule( + hash, + chunk, + "moduleId" + )});`, + "threw = false;" + ]), + "} finally {", + Template.indent([ + "if(threw) delete installedModules[moduleId];" + ]), + "}" + ] + : [ + "// Execute the module function", + `modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule( + hash, + chunk, + "moduleId" + )});` + ] + ), + "", + "// Flag the module as loaded", + "module.l = true;", + "", + "// Return the exports of the module", + "return module.exports;" + ]); + }); + this.hooks.moduleObj.tap( + "MainTemplate", + (source, chunk, hash, varModuleId) => { + return Template.asString(["i: moduleId,", "l: false,", "exports: {}"]); + } + ); + this.hooks.requireExtensions.tap("MainTemplate", (source, chunk, hash) => { + const buf = []; + const chunkMaps = chunk.getChunkMaps(); + // Check if there are non initial chunks which need to be imported using require-ensure + if (Object.keys(chunkMaps.hash).length) { + buf.push("// This file contains only the entry chunk."); + buf.push("// The chunk loading function for additional chunks"); + buf.push(`${this.requireFn}.e = function requireEnsure(chunkId) {`); + buf.push(Template.indent("var promises = [];")); + buf.push( + Template.indent( + this.hooks.requireEnsure.call("", chunk, hash, "chunkId") + ) + ); + buf.push(Template.indent("return Promise.all(promises);")); + buf.push("};"); + } else if ( + chunk.hasModuleInGraph(m => + m.blocks.some(b => b.chunkGroup && b.chunkGroup.chunks.length > 0) + ) + ) { + // There async blocks in the graph, so we need to add an empty requireEnsure + // function anyway. This can happen with multiple entrypoints. + buf.push("// The chunk loading function for additional chunks"); + buf.push("// Since all referenced chunks are already included"); + buf.push("// in this file, this function is empty here."); + buf.push(`${this.requireFn}.e = function requireEnsure() {`); + buf.push(Template.indent("return Promise.resolve();")); + buf.push("};"); + } + buf.push(""); + buf.push("// expose the modules object (__webpack_modules__)"); + buf.push(`${this.requireFn}.m = modules;`); + + buf.push(""); + buf.push("// expose the module cache"); + buf.push(`${this.requireFn}.c = installedModules;`); + + buf.push(""); + buf.push("// define getter function for harmony exports"); + buf.push(`${this.requireFn}.d = function(exports, name, getter) {`); + buf.push( + Template.indent([ + `if(!${this.requireFn}.o(exports, name)) {`, + Template.indent([ + "Object.defineProperty(exports, name, { enumerable: true, get: getter });" + ]), + "}" + ]) + ); + buf.push("};"); + + buf.push(""); + buf.push("// define __esModule on exports"); + buf.push(`${this.requireFn}.r = function(exports) {`); + buf.push( + Template.indent([ + "if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {", + Template.indent([ + "Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });" + ]), + "}", + "Object.defineProperty(exports, '__esModule', { value: true });" + ]) + ); + buf.push("};"); + + buf.push(""); + buf.push("// create a fake namespace object"); + buf.push("// mode & 1: value is a module id, require it"); + buf.push("// mode & 2: merge all properties of value into the ns"); + buf.push("// mode & 4: return value when already ns object"); + buf.push("// mode & 8|1: behave like require"); + buf.push(`${this.requireFn}.t = function(value, mode) {`); + buf.push( + Template.indent([ + `if(mode & 1) value = ${this.requireFn}(value);`, + `if(mode & 8) return value;`, + "if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;", + "var ns = Object.create(null);", + `${this.requireFn}.r(ns);`, + "Object.defineProperty(ns, 'default', { enumerable: true, value: value });", + "if(mode & 2 && typeof value != 'string') for(var key in value) " + + `${this.requireFn}.d(ns, key, function(key) { ` + + "return value[key]; " + + "}.bind(null, key));", + "return ns;" + ]) + ); + buf.push("};"); + + buf.push(""); + buf.push( + "// getDefaultExport function for compatibility with non-harmony modules" + ); + buf.push(this.requireFn + ".n = function(module) {"); + buf.push( + Template.indent([ + "var getter = module && module.__esModule ?", + Template.indent([ + "function getDefault() { return module['default']; } :", + "function getModuleExports() { return module; };" + ]), + `${this.requireFn}.d(getter, 'a', getter);`, + "return getter;" + ]) + ); + buf.push("};"); + + buf.push(""); + buf.push("// Object.prototype.hasOwnProperty.call"); + buf.push( + `${this.requireFn}.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };` + ); + + const publicPath = this.getPublicPath({ + hash: hash + }); + buf.push(""); + buf.push("// __webpack_public_path__"); + buf.push(`${this.requireFn}.p = ${JSON.stringify(publicPath)};`); + return Template.asString(buf); + }); + + this.requireFn = "__webpack_require__"; + } + + /** + * + * @param {RenderManifestOptions} options render manifest options + * @returns {TODO[]} returns render manifest + */ + getRenderManifest(options) { + const result = []; + + this.hooks.renderManifest.call(result, options); + + return result; + } + + /** + * TODO webpack 5: remove moduleTemplate and dependencyTemplates + * @param {string} hash hash to be used for render call + * @param {Chunk} chunk Chunk instance + * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render + * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates + * @returns {string[]} the generated source of the bootstrap code + */ + renderBootstrap(hash, chunk, moduleTemplate, dependencyTemplates) { + const buf = []; + buf.push( + this.hooks.bootstrap.call( + "", + chunk, + hash, + moduleTemplate, + dependencyTemplates + ) + ); + buf.push(this.hooks.localVars.call("", chunk, hash)); + buf.push(""); + buf.push("// The require function"); + buf.push(`function ${this.requireFn}(moduleId) {`); + buf.push(Template.indent(this.hooks.require.call("", chunk, hash))); + buf.push("}"); + buf.push(""); + buf.push( + Template.asString(this.hooks.requireExtensions.call("", chunk, hash)) + ); + buf.push(""); + buf.push(Template.asString(this.hooks.beforeStartup.call("", chunk, hash))); + const afterStartupCode = Template.asString( + this.hooks.afterStartup.call("", chunk, hash) + ); + if (afterStartupCode) { + // TODO webpack 5: this is a bit hacky to avoid a breaking change + // change it to a better way + buf.push("var startupResult = (function() {"); + } + buf.push(Template.asString(this.hooks.startup.call("", chunk, hash))); + if (afterStartupCode) { + buf.push("})();"); + buf.push(afterStartupCode); + buf.push("return startupResult;"); + } + return buf; + } + + /** + * @param {string} hash hash to be used for render call + * @param {Chunk} chunk Chunk instance + * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render + * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates + * @returns {ConcatSource} the newly generated source from rendering + */ + render(hash, chunk, moduleTemplate, dependencyTemplates) { + const buf = this.renderBootstrap( + hash, + chunk, + moduleTemplate, + dependencyTemplates + ); + let source = this.hooks.render.call( + new OriginalSource( + Template.prefix(buf, " \t") + "\n", + "webpack/bootstrap" + ), + chunk, + hash, + moduleTemplate, + dependencyTemplates + ); + if (chunk.hasEntryModule()) { + source = this.hooks.renderWithEntry.call(source, chunk, hash); + } + if (!source) { + throw new Error( + "Compiler error: MainTemplate plugin 'render' should return something" + ); + } + chunk.rendered = true; + return new ConcatSource(source, ";"); + } + + /** + * + * @param {string} hash hash for render fn + * @param {Chunk} chunk Chunk instance for require + * @param {(number|string)=} varModuleId module id + * @returns {TODO} the moduleRequire hook call return signature + */ + renderRequireFunctionForModule(hash, chunk, varModuleId) { + return this.hooks.moduleRequire.call( + this.requireFn, + chunk, + hash, + varModuleId + ); + } + + /** + * + * @param {string} hash hash for render add fn + * @param {Chunk} chunk Chunk instance for require add fn + * @param {(string|number)=} varModuleId module id + * @param {Module} varModule Module instance + * @returns {TODO} renderAddModule call + */ + renderAddModule(hash, chunk, varModuleId, varModule) { + return this.hooks.addModule.call( + `modules[${varModuleId}] = ${varModule};`, + chunk, + hash, + varModuleId, + varModule + ); + } + + /** + * + * @param {string} hash string hash + * @param {number=} length length + * @returns {string} call hook return + */ + renderCurrentHashCode(hash, length) { + length = length || Infinity; + return this.hooks.currentHash.call( + JSON.stringify(hash.substr(0, length)), + length + ); + } + + /** + * + * @param {object} options get public path options + * @returns {string} hook call + */ + getPublicPath(options) { + return this.hooks.assetPath.call( + this.outputOptions.publicPath || "", + options + ); + } + + getAssetPath(path, options) { + return this.hooks.assetPath.call(path, options); + } + + getAssetPathWithInfo(path, options) { + const assetInfo = {}; + // TODO webpack 5: refactor assetPath hook to receive { path, info } object + const newPath = this.hooks.assetPath.call(path, options, assetInfo); + return { path: newPath, info: assetInfo }; + } + + /** + * Updates hash with information from this template + * @param {Hash} hash the hash to update + * @returns {void} + */ + updateHash(hash) { + hash.update("maintemplate"); + hash.update("3"); + this.hooks.hash.call(hash); + } + + /** + * TODO webpack 5: remove moduleTemplate and dependencyTemplates + * Updates hash with chunk-specific information from this template + * @param {Hash} hash the hash to update + * @param {Chunk} chunk the chunk + * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render + * @param {Map<Function, DependencyTemplate>} dependencyTemplates dependency templates + * @returns {void} + */ + updateHashForChunk(hash, chunk, moduleTemplate, dependencyTemplates) { + this.updateHash(hash); + this.hooks.hashForChunk.call(hash, chunk); + for (const line of this.renderBootstrap( + "0000", + chunk, + moduleTemplate, + dependencyTemplates + )) { + hash.update(line); + } + } + + useChunkHash(chunk) { + const paths = this.hooks.globalHashPaths.call([]); + return !this.hooks.globalHash.call(chunk, paths); + } +}; diff --git a/node_modules/webpack/lib/MemoryOutputFileSystem.js b/node_modules/webpack/lib/MemoryOutputFileSystem.js new file mode 100644 index 0000000..8476148 --- /dev/null +++ b/node_modules/webpack/lib/MemoryOutputFileSystem.js @@ -0,0 +1,5 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +module.exports = require("memory-fs"); diff --git a/node_modules/webpack/lib/Module.js b/node_modules/webpack/lib/Module.js new file mode 100644 index 0000000..3fb571c --- /dev/null +++ b/node_modules/webpack/lib/Module.js @@ -0,0 +1,435 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const util = require("util"); + +const DependenciesBlock = require("./DependenciesBlock"); +const ModuleReason = require("./ModuleReason"); +const SortableSet = require("./util/SortableSet"); +const Template = require("./Template"); + +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./RequestShortener")} RequestShortener */ +/** @typedef {import("./WebpackError")} WebpackError */ +/** @typedef {import("./util/createHash").Hash} Hash */ + +const EMPTY_RESOLVE_OPTIONS = {}; + +let debugId = 1000; + +const sortById = (a, b) => { + return a.id - b.id; +}; + +const sortByDebugId = (a, b) => { + return a.debugId - b.debugId; +}; + +/** @typedef {(requestShortener: RequestShortener) => string} OptimizationBailoutFunction */ + +class Module extends DependenciesBlock { + constructor(type, context = null) { + super(); + /** @type {string} */ + this.type = type; + /** @type {string} */ + this.context = context; + + // Unique Id + /** @type {number} */ + this.debugId = debugId++; + + // Hash + /** @type {string} */ + this.hash = undefined; + /** @type {string} */ + this.renderedHash = undefined; + + // Info from Factory + /** @type {TODO} */ + this.resolveOptions = EMPTY_RESOLVE_OPTIONS; + /** @type {object} */ + this.factoryMeta = {}; + + // Info from Build + /** @type {WebpackError[]} */ + this.warnings = []; + /** @type {WebpackError[]} */ + this.errors = []; + /** @type {object} */ + this.buildMeta = undefined; + /** @type {object} */ + this.buildInfo = undefined; + + // Graph (per Compilation) + /** @type {ModuleReason[]} */ + this.reasons = []; + /** @type {SortableSet<Chunk>} */ + this._chunks = new SortableSet(undefined, sortById); + + // Info from Compilation (per Compilation) + /** @type {number|string} */ + this.id = null; + /** @type {number} */ + this.index = null; + /** @type {number} */ + this.index2 = null; + /** @type {number} */ + this.depth = null; + /** @type {Module} */ + this.issuer = null; + /** @type {undefined | object} */ + this.profile = undefined; + /** @type {boolean} */ + this.prefetched = false; + /** @type {boolean} */ + this.built = false; + + // Info from Optimization (per Compilation) + /** @type {null | boolean} */ + this.used = null; + /** @type {false | true | string[]} */ + this.usedExports = null; + /** @type {(string | OptimizationBailoutFunction)[]} */ + this.optimizationBailout = []; + + // delayed operations + /** @type {undefined | {oldChunk: Chunk, newChunks: Chunk[]}[] } */ + this._rewriteChunkInReasons = undefined; + + /** @type {boolean} */ + this.useSourceMap = false; + + // info from build + this._source = null; + } + + get exportsArgument() { + return (this.buildInfo && this.buildInfo.exportsArgument) || "exports"; + } + + get moduleArgument() { + return (this.buildInfo && this.buildInfo.moduleArgument) || "module"; + } + + disconnect() { + this.hash = undefined; + this.renderedHash = undefined; + + this.reasons.length = 0; + this._rewriteChunkInReasons = undefined; + this._chunks.clear(); + + this.id = null; + this.index = null; + this.index2 = null; + this.depth = null; + this.issuer = null; + this.profile = undefined; + this.prefetched = false; + this.built = false; + + this.used = null; + this.usedExports = null; + this.optimizationBailout.length = 0; + super.disconnect(); + } + + unseal() { + this.id = null; + this.index = null; + this.index2 = null; + this.depth = null; + this._chunks.clear(); + super.unseal(); + } + + setChunks(chunks) { + this._chunks = new SortableSet(chunks, sortById); + } + + addChunk(chunk) { + if (this._chunks.has(chunk)) return false; + this._chunks.add(chunk); + return true; + } + + removeChunk(chunk) { + if (this._chunks.delete(chunk)) { + chunk.removeModule(this); + return true; + } + return false; + } + + isInChunk(chunk) { + return this._chunks.has(chunk); + } + + isEntryModule() { + for (const chunk of this._chunks) { + if (chunk.entryModule === this) return true; + } + return false; + } + + get optional() { + return ( + this.reasons.length > 0 && + this.reasons.every(r => r.dependency && r.dependency.optional) + ); + } + + /** + * @returns {Chunk[]} all chunks which contain the module + */ + getChunks() { + return Array.from(this._chunks); + } + + getNumberOfChunks() { + return this._chunks.size; + } + + get chunksIterable() { + return this._chunks; + } + + hasEqualsChunks(otherModule) { + if (this._chunks.size !== otherModule._chunks.size) return false; + this._chunks.sortWith(sortByDebugId); + otherModule._chunks.sortWith(sortByDebugId); + const a = this._chunks[Symbol.iterator](); + const b = otherModule._chunks[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = a.next(); + const bItem = b.next(); + if (aItem.done) return true; + if (aItem.value !== bItem.value) return false; + } + } + + addReason(module, dependency, explanation) { + this.reasons.push(new ModuleReason(module, dependency, explanation)); + } + + removeReason(module, dependency) { + for (let i = 0; i < this.reasons.length; i++) { + let r = this.reasons[i]; + if (r.module === module && r.dependency === dependency) { + this.reasons.splice(i, 1); + return true; + } + } + return false; + } + + hasReasonForChunk(chunk) { + if (this._rewriteChunkInReasons) { + for (const operation of this._rewriteChunkInReasons) { + this._doRewriteChunkInReasons(operation.oldChunk, operation.newChunks); + } + this._rewriteChunkInReasons = undefined; + } + for (let i = 0; i < this.reasons.length; i++) { + if (this.reasons[i].hasChunk(chunk)) return true; + } + return false; + } + + hasReasons() { + return this.reasons.length > 0; + } + + rewriteChunkInReasons(oldChunk, newChunks) { + // This is expensive. Delay operation until we really need the data + if (this._rewriteChunkInReasons === undefined) { + this._rewriteChunkInReasons = []; + } + this._rewriteChunkInReasons.push({ + oldChunk, + newChunks + }); + } + + _doRewriteChunkInReasons(oldChunk, newChunks) { + for (let i = 0; i < this.reasons.length; i++) { + this.reasons[i].rewriteChunks(oldChunk, newChunks); + } + } + + /** + * @param {string=} exportName the name of the export + * @returns {boolean|string} false if the export isn't used, true if no exportName is provided and the module is used, or the name to access it if the export is used + */ + isUsed(exportName) { + if (!exportName) return this.used !== false; + if (this.used === null || this.usedExports === null) return exportName; + if (!this.used) return false; + if (!this.usedExports) return false; + if (this.usedExports === true) return exportName; + let idx = this.usedExports.indexOf(exportName); + if (idx < 0) return false; + + // Mangle export name if possible + if (this.isProvided(exportName)) { + if (this.buildMeta.exportsType === "namespace") { + return Template.numberToIdentifer(idx); + } + if ( + this.buildMeta.exportsType === "named" && + !this.usedExports.includes("default") + ) { + return Template.numberToIdentifer(idx); + } + } + return exportName; + } + + isProvided(exportName) { + if (!Array.isArray(this.buildMeta.providedExports)) return null; + return this.buildMeta.providedExports.includes(exportName); + } + + toString() { + return `Module[${this.id || this.debugId}]`; + } + + needRebuild(fileTimestamps, contextTimestamps) { + return true; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update(`${this.id}`); + hash.update(JSON.stringify(this.usedExports)); + super.updateHash(hash); + } + + sortItems(sortChunks) { + super.sortItems(); + if (sortChunks) this._chunks.sort(); + this.reasons.sort((a, b) => { + if (a.module === b.module) return 0; + if (!a.module) return -1; + if (!b.module) return 1; + return sortById(a.module, b.module); + }); + if (Array.isArray(this.usedExports)) { + this.usedExports.sort(); + } + } + + unbuild() { + this.dependencies.length = 0; + this.blocks.length = 0; + this.variables.length = 0; + this.buildMeta = undefined; + this.buildInfo = undefined; + this.disconnect(); + } + + get arguments() { + throw new Error("Module.arguments was removed, there is no replacement."); + } + + set arguments(value) { + throw new Error("Module.arguments was removed, there is no replacement."); + } +} + +// TODO remove in webpack 5 +Object.defineProperty(Module.prototype, "forEachChunk", { + configurable: false, + value: util.deprecate( + /** + * @deprecated + * @param {function(any, any, Set<any>): void} fn callback function + * @returns {void} + * @this {Module} + */ + function(fn) { + this._chunks.forEach(fn); + }, + "Module.forEachChunk: Use for(const chunk of module.chunksIterable) instead" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(Module.prototype, "mapChunks", { + configurable: false, + value: util.deprecate( + /** + * @deprecated + * @param {function(any, any): void} fn Mapper function + * @returns {Array<TODO>} Array of chunks mapped + * @this {Module} + */ + function(fn) { + return Array.from(this._chunks, fn); + }, + "Module.mapChunks: Use Array.from(module.chunksIterable, fn) instead" + ) +}); + +// TODO remove in webpack 5 +Object.defineProperty(Module.prototype, "entry", { + configurable: false, + get() { + throw new Error("Module.entry was removed. Use Chunk.entryModule"); + }, + set() { + throw new Error("Module.entry was removed. Use Chunk.entryModule"); + } +}); + +// TODO remove in webpack 5 +Object.defineProperty(Module.prototype, "meta", { + configurable: false, + get: util.deprecate( + /** + * @deprecated + * @returns {void} + * @this {Module} + */ + function() { + return this.buildMeta; + }, + "Module.meta was renamed to Module.buildMeta" + ), + set: util.deprecate( + /** + * @deprecated + * @param {TODO} value Value + * @returns {void} + * @this {Module} + */ + function(value) { + this.buildMeta = value; + }, + "Module.meta was renamed to Module.buildMeta" + ) +}); + +/** @type {function(): string} */ +Module.prototype.identifier = null; + +/** @type {function(RequestShortener): string} */ +Module.prototype.readableIdentifier = null; + +Module.prototype.build = null; +Module.prototype.source = null; +Module.prototype.size = null; +Module.prototype.nameForCondition = null; +/** @type {null | function(Chunk): boolean} */ +Module.prototype.chunkCondition = null; +Module.prototype.updateCacheModule = null; + +module.exports = Module; diff --git a/node_modules/webpack/lib/ModuleBuildError.js b/node_modules/webpack/lib/ModuleBuildError.js new file mode 100644 index 0000000..d6b498e --- /dev/null +++ b/node_modules/webpack/lib/ModuleBuildError.js @@ -0,0 +1,52 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); +const { cutOffLoaderExecution } = require("./ErrorHelpers"); + +class ModuleBuildError extends WebpackError { + constructor(module, err, { from = null } = {}) { + let message = "Module build failed"; + let details = undefined; + if (from) { + message += ` (from ${from}):\n`; + } else { + message += ": "; + } + if (err !== null && typeof err === "object") { + if (typeof err.stack === "string" && err.stack) { + const stack = cutOffLoaderExecution(err.stack); + if (!err.hideStack) { + message += stack; + } else { + details = stack; + if (typeof err.message === "string" && err.message) { + message += err.message; + } else { + message += err; + } + } + } else if (typeof err.message === "string" && err.message) { + message += err.message; + } else { + message += err; + } + } else { + message = err; + } + + super(message); + + this.name = "ModuleBuildError"; + this.details = details; + this.module = module; + this.error = err; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleBuildError; diff --git a/node_modules/webpack/lib/ModuleDependencyError.js b/node_modules/webpack/lib/ModuleDependencyError.js new file mode 100644 index 0000000..cb16cc3 --- /dev/null +++ b/node_modules/webpack/lib/ModuleDependencyError.js @@ -0,0 +1,35 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ + +class ModuleDependencyError extends WebpackError { + /** + * Creates an instance of ModuleDependencyError. + * @param {Module} module module tied to dependency + * @param {Error} err error thrown + * @param {TODO} loc location of dependency + */ + constructor(module, err, loc) { + super(err.message); + + this.name = "ModuleDependencyError"; + this.details = err.stack + .split("\n") + .slice(1) + .join("\n"); + this.module = module; + this.loc = loc; + this.error = err; + this.origin = module.issuer; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleDependencyError; diff --git a/node_modules/webpack/lib/ModuleDependencyWarning.js b/node_modules/webpack/lib/ModuleDependencyWarning.js new file mode 100644 index 0000000..be62791 --- /dev/null +++ b/node_modules/webpack/lib/ModuleDependencyWarning.js @@ -0,0 +1,25 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +module.exports = class ModuleDependencyWarning extends WebpackError { + constructor(module, err, loc) { + super(err.message); + + this.name = "ModuleDependencyWarning"; + this.details = err.stack + .split("\n") + .slice(1) + .join("\n"); + this.module = module; + this.loc = loc; + this.error = err; + this.origin = module.issuer; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/ModuleError.js b/node_modules/webpack/lib/ModuleError.js new file mode 100644 index 0000000..7079d61 --- /dev/null +++ b/node_modules/webpack/lib/ModuleError.js @@ -0,0 +1,36 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); +const { cleanUp } = require("./ErrorHelpers"); + +class ModuleError extends WebpackError { + constructor(module, err, { from = null } = {}) { + let message = "Module Error"; + if (from) { + message += ` (from ${from}):\n`; + } else { + message += ": "; + } + if (err && typeof err === "object" && err.message) { + message += err.message; + } else if (err) { + message += err; + } + super(message); + this.name = "ModuleError"; + this.module = module; + this.error = err; + this.details = + err && typeof err === "object" && err.stack + ? cleanUp(err.stack, this.message) + : undefined; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleError; diff --git a/node_modules/webpack/lib/ModuleFilenameHelpers.js b/node_modules/webpack/lib/ModuleFilenameHelpers.js new file mode 100644 index 0000000..bd0742b --- /dev/null +++ b/node_modules/webpack/lib/ModuleFilenameHelpers.js @@ -0,0 +1,179 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const createHash = require("./util/createHash"); + +const ModuleFilenameHelpers = exports; + +ModuleFilenameHelpers.ALL_LOADERS_RESOURCE = "[all-loaders][resource]"; +ModuleFilenameHelpers.REGEXP_ALL_LOADERS_RESOURCE = /\[all-?loaders\]\[resource\]/gi; +ModuleFilenameHelpers.LOADERS_RESOURCE = "[loaders][resource]"; +ModuleFilenameHelpers.REGEXP_LOADERS_RESOURCE = /\[loaders\]\[resource\]/gi; +ModuleFilenameHelpers.RESOURCE = "[resource]"; +ModuleFilenameHelpers.REGEXP_RESOURCE = /\[resource\]/gi; +ModuleFilenameHelpers.ABSOLUTE_RESOURCE_PATH = "[absolute-resource-path]"; +ModuleFilenameHelpers.REGEXP_ABSOLUTE_RESOURCE_PATH = /\[abs(olute)?-?resource-?path\]/gi; +ModuleFilenameHelpers.RESOURCE_PATH = "[resource-path]"; +ModuleFilenameHelpers.REGEXP_RESOURCE_PATH = /\[resource-?path\]/gi; +ModuleFilenameHelpers.ALL_LOADERS = "[all-loaders]"; +ModuleFilenameHelpers.REGEXP_ALL_LOADERS = /\[all-?loaders\]/gi; +ModuleFilenameHelpers.LOADERS = "[loaders]"; +ModuleFilenameHelpers.REGEXP_LOADERS = /\[loaders\]/gi; +ModuleFilenameHelpers.QUERY = "[query]"; +ModuleFilenameHelpers.REGEXP_QUERY = /\[query\]/gi; +ModuleFilenameHelpers.ID = "[id]"; +ModuleFilenameHelpers.REGEXP_ID = /\[id\]/gi; +ModuleFilenameHelpers.HASH = "[hash]"; +ModuleFilenameHelpers.REGEXP_HASH = /\[hash\]/gi; +ModuleFilenameHelpers.NAMESPACE = "[namespace]"; +ModuleFilenameHelpers.REGEXP_NAMESPACE = /\[namespace\]/gi; + +const getAfter = (str, token) => { + const idx = str.indexOf(token); + return idx < 0 ? "" : str.substr(idx); +}; + +const getBefore = (str, token) => { + const idx = str.lastIndexOf(token); + return idx < 0 ? "" : str.substr(0, idx); +}; + +const getHash = str => { + const hash = createHash("md4"); + hash.update(str); + const digest = /** @type {string} */ (hash.digest("hex")); + return digest.substr(0, 4); +}; + +const asRegExp = test => { + if (typeof test === "string") { + test = new RegExp("^" + test.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")); + } + return test; +}; + +ModuleFilenameHelpers.createFilename = (module, options, requestShortener) => { + const opts = Object.assign( + { + namespace: "", + moduleFilenameTemplate: "" + }, + typeof options === "object" + ? options + : { + moduleFilenameTemplate: options + } + ); + + let absoluteResourcePath; + let hash; + let identifier; + let moduleId; + let shortIdentifier; + if (module === undefined) module = ""; + if (typeof module === "string") { + shortIdentifier = requestShortener.shorten(module); + identifier = shortIdentifier; + moduleId = ""; + absoluteResourcePath = module.split("!").pop(); + hash = getHash(identifier); + } else { + shortIdentifier = module.readableIdentifier(requestShortener); + identifier = requestShortener.shorten(module.identifier()); + moduleId = module.id; + absoluteResourcePath = module + .identifier() + .split("!") + .pop(); + hash = getHash(identifier); + } + const resource = shortIdentifier.split("!").pop(); + const loaders = getBefore(shortIdentifier, "!"); + const allLoaders = getBefore(identifier, "!"); + const query = getAfter(resource, "?"); + const resourcePath = resource.substr(0, resource.length - query.length); + if (typeof opts.moduleFilenameTemplate === "function") { + return opts.moduleFilenameTemplate({ + identifier: identifier, + shortIdentifier: shortIdentifier, + resource: resource, + resourcePath: resourcePath, + absoluteResourcePath: absoluteResourcePath, + allLoaders: allLoaders, + query: query, + moduleId: moduleId, + hash: hash, + namespace: opts.namespace + }); + } + return opts.moduleFilenameTemplate + .replace(ModuleFilenameHelpers.REGEXP_ALL_LOADERS_RESOURCE, identifier) + .replace(ModuleFilenameHelpers.REGEXP_LOADERS_RESOURCE, shortIdentifier) + .replace(ModuleFilenameHelpers.REGEXP_RESOURCE, resource) + .replace(ModuleFilenameHelpers.REGEXP_RESOURCE_PATH, resourcePath) + .replace( + ModuleFilenameHelpers.REGEXP_ABSOLUTE_RESOURCE_PATH, + absoluteResourcePath + ) + .replace(ModuleFilenameHelpers.REGEXP_ALL_LOADERS, allLoaders) + .replace(ModuleFilenameHelpers.REGEXP_LOADERS, loaders) + .replace(ModuleFilenameHelpers.REGEXP_QUERY, query) + .replace(ModuleFilenameHelpers.REGEXP_ID, moduleId) + .replace(ModuleFilenameHelpers.REGEXP_HASH, hash) + .replace(ModuleFilenameHelpers.REGEXP_NAMESPACE, opts.namespace); +}; + +ModuleFilenameHelpers.replaceDuplicates = (array, fn, comparator) => { + const countMap = Object.create(null); + const posMap = Object.create(null); + array.forEach((item, idx) => { + countMap[item] = countMap[item] || []; + countMap[item].push(idx); + posMap[item] = 0; + }); + if (comparator) { + Object.keys(countMap).forEach(item => { + countMap[item].sort(comparator); + }); + } + return array.map((item, i) => { + if (countMap[item].length > 1) { + if (comparator && countMap[item][0] === i) return item; + return fn(item, i, posMap[item]++); + } else { + return item; + } + }); +}; + +ModuleFilenameHelpers.matchPart = (str, test) => { + if (!test) return true; + test = asRegExp(test); + if (Array.isArray(test)) { + return test.map(asRegExp).some(regExp => regExp.test(str)); + } else { + return test.test(str); + } +}; + +ModuleFilenameHelpers.matchObject = (obj, str) => { + if (obj.test) { + if (!ModuleFilenameHelpers.matchPart(str, obj.test)) { + return false; + } + } + if (obj.include) { + if (!ModuleFilenameHelpers.matchPart(str, obj.include)) { + return false; + } + } + if (obj.exclude) { + if (ModuleFilenameHelpers.matchPart(str, obj.exclude)) { + return false; + } + } + return true; +}; diff --git a/node_modules/webpack/lib/ModuleNotFoundError.js b/node_modules/webpack/lib/ModuleNotFoundError.js new file mode 100644 index 0000000..cdfc314 --- /dev/null +++ b/node_modules/webpack/lib/ModuleNotFoundError.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +class ModuleNotFoundError extends WebpackError { + constructor(module, err) { + super("Module not found: " + err); + + this.name = "ModuleNotFoundError"; + this.details = err.details; + this.missing = err.missing; + this.module = module; + this.error = err; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleNotFoundError; diff --git a/node_modules/webpack/lib/ModuleParseError.js b/node_modules/webpack/lib/ModuleParseError.js new file mode 100644 index 0000000..2ff22b7 --- /dev/null +++ b/node_modules/webpack/lib/ModuleParseError.js @@ -0,0 +1,67 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ + +class ModuleParseError extends WebpackError { + /** + * @param {Module} module the errored module + * @param {string} source source code + * @param {Error&any} err the parse error + * @param {string[]} loaders the loaders used + */ + constructor(module, source, err, loaders) { + let message = "Module parse failed: " + err.message; + let loc = undefined; + if (loaders.length >= 1) { + message += `\nFile was processed with these loaders:${loaders + .map(loader => `\n * ${loader}`) + .join("")}`; + message += + "\nYou may need an additional loader to handle the result of these loaders."; + } else { + message += + "\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders"; + } + if ( + err.loc && + typeof err.loc === "object" && + typeof err.loc.line === "number" + ) { + var lineNumber = err.loc.line; + if (/[\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007]/.test(source)) { + // binary file + message += "\n(Source code omitted for this binary file)"; + } else { + const sourceLines = source.split(/\r?\n/); + const start = Math.max(0, lineNumber - 3); + const linesBefore = sourceLines.slice(start, lineNumber - 1); + const theLine = sourceLines[lineNumber - 1]; + const linesAfter = sourceLines.slice(lineNumber, lineNumber + 2); + message += + linesBefore.map(l => `\n| ${l}`).join("") + + `\n> ${theLine}` + + linesAfter.map(l => `\n| ${l}`).join(""); + } + loc = err.loc; + } else { + message += "\n" + err.stack; + } + + super(message); + + this.name = "ModuleParseError"; + this.module = module; + this.loc = loc; + this.error = err; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleParseError; diff --git a/node_modules/webpack/lib/ModuleReason.js b/node_modules/webpack/lib/ModuleReason.js new file mode 100644 index 0000000..3697f84 --- /dev/null +++ b/node_modules/webpack/lib/ModuleReason.js @@ -0,0 +1,48 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Dependency")} Dependency */ + +class ModuleReason { + /** + * @param {Module} module the referencing module + * @param {Dependency} dependency the referencing dependency + * @param {string=} explanation some extra detail + */ + constructor(module, dependency, explanation) { + this.module = module; + this.dependency = dependency; + this.explanation = explanation; + this._chunks = null; + } + + hasChunk(chunk) { + if (this._chunks) { + if (this._chunks.has(chunk)) return true; + } else if (this.module && this.module._chunks.has(chunk)) return true; + return false; + } + + rewriteChunks(oldChunk, newChunks) { + if (!this._chunks) { + if (this.module) { + if (!this.module._chunks.has(oldChunk)) return; + this._chunks = new Set(this.module._chunks); + } else { + this._chunks = new Set(); + } + } + if (this._chunks.has(oldChunk)) { + this._chunks.delete(oldChunk); + for (let i = 0; i < newChunks.length; i++) { + this._chunks.add(newChunks[i]); + } + } + } +} + +module.exports = ModuleReason; diff --git a/node_modules/webpack/lib/ModuleTemplate.js b/node_modules/webpack/lib/ModuleTemplate.js new file mode 100644 index 0000000..06e787e --- /dev/null +++ b/node_modules/webpack/lib/ModuleTemplate.js @@ -0,0 +1,93 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable"); + +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./Module")} Module */ + +module.exports = class ModuleTemplate extends Tapable { + constructor(runtimeTemplate, type) { + super(); + this.runtimeTemplate = runtimeTemplate; + this.type = type; + this.hooks = { + content: new SyncWaterfallHook([ + "source", + "module", + "options", + "dependencyTemplates" + ]), + module: new SyncWaterfallHook([ + "source", + "module", + "options", + "dependencyTemplates" + ]), + render: new SyncWaterfallHook([ + "source", + "module", + "options", + "dependencyTemplates" + ]), + package: new SyncWaterfallHook([ + "source", + "module", + "options", + "dependencyTemplates" + ]), + hash: new SyncHook(["hash"]) + }; + } + + /** + * @param {Module} module the module + * @param {TODO} dependencyTemplates templates for dependencies + * @param {TODO} options render options + * @returns {Source} the source + */ + render(module, dependencyTemplates, options) { + try { + const moduleSource = module.source( + dependencyTemplates, + this.runtimeTemplate, + this.type + ); + const moduleSourcePostContent = this.hooks.content.call( + moduleSource, + module, + options, + dependencyTemplates + ); + const moduleSourcePostModule = this.hooks.module.call( + moduleSourcePostContent, + module, + options, + dependencyTemplates + ); + const moduleSourcePostRender = this.hooks.render.call( + moduleSourcePostModule, + module, + options, + dependencyTemplates + ); + return this.hooks.package.call( + moduleSourcePostRender, + module, + options, + dependencyTemplates + ); + } catch (e) { + e.message = `${module.identifier()}\n${e.message}`; + throw e; + } + } + + updateHash(hash) { + hash.update("1"); + this.hooks.hash.call(hash); + } +}; diff --git a/node_modules/webpack/lib/ModuleWarning.js b/node_modules/webpack/lib/ModuleWarning.js new file mode 100644 index 0000000..1306819 --- /dev/null +++ b/node_modules/webpack/lib/ModuleWarning.js @@ -0,0 +1,36 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); +const { cleanUp } = require("./ErrorHelpers"); + +class ModuleWarning extends WebpackError { + constructor(module, warning, { from = null } = {}) { + let message = "Module Warning"; + if (from) { + message += ` (from ${from}):\n`; + } else { + message += ": "; + } + if (warning && typeof warning === "object" && warning.message) { + message += warning.message; + } else if (warning) { + message += warning; + } + super(message); + this.name = "ModuleWarning"; + this.module = module; + this.warning = warning; + this.details = + warning && typeof warning === "object" && warning.stack + ? cleanUp(warning.stack, this.message) + : undefined; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = ModuleWarning; diff --git a/node_modules/webpack/lib/MultiCompiler.js b/node_modules/webpack/lib/MultiCompiler.js new file mode 100644 index 0000000..e9c3005 --- /dev/null +++ b/node_modules/webpack/lib/MultiCompiler.js @@ -0,0 +1,290 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { Tapable, SyncHook, MultiHook } = require("tapable"); +const asyncLib = require("neo-async"); +const MultiWatching = require("./MultiWatching"); +const MultiStats = require("./MultiStats"); +const ConcurrentCompilationError = require("./ConcurrentCompilationError"); + +module.exports = class MultiCompiler extends Tapable { + constructor(compilers) { + super(); + this.hooks = { + done: new SyncHook(["stats"]), + invalid: new MultiHook(compilers.map(c => c.hooks.invalid)), + run: new MultiHook(compilers.map(c => c.hooks.run)), + watchClose: new SyncHook([]), + watchRun: new MultiHook(compilers.map(c => c.hooks.watchRun)), + infrastructureLog: new MultiHook( + compilers.map(c => c.hooks.infrastructureLog) + ) + }; + if (!Array.isArray(compilers)) { + compilers = Object.keys(compilers).map(name => { + compilers[name].name = name; + return compilers[name]; + }); + } + this.compilers = compilers; + let doneCompilers = 0; + let compilerStats = []; + let index = 0; + for (const compiler of this.compilers) { + let compilerDone = false; + const compilerIndex = index++; + // eslint-disable-next-line no-loop-func + compiler.hooks.done.tap("MultiCompiler", stats => { + if (!compilerDone) { + compilerDone = true; + doneCompilers++; + } + compilerStats[compilerIndex] = stats; + if (doneCompilers === this.compilers.length) { + this.hooks.done.call(new MultiStats(compilerStats)); + } + }); + // eslint-disable-next-line no-loop-func + compiler.hooks.invalid.tap("MultiCompiler", () => { + if (compilerDone) { + compilerDone = false; + doneCompilers--; + } + }); + } + this.running = false; + } + + get outputPath() { + let commonPath = this.compilers[0].outputPath; + for (const compiler of this.compilers) { + while ( + compiler.outputPath.indexOf(commonPath) !== 0 && + /[/\\]/.test(commonPath) + ) { + commonPath = commonPath.replace(/[/\\][^/\\]*$/, ""); + } + } + + if (!commonPath && this.compilers[0].outputPath[0] === "/") return "/"; + return commonPath; + } + + get inputFileSystem() { + throw new Error("Cannot read inputFileSystem of a MultiCompiler"); + } + + get outputFileSystem() { + throw new Error("Cannot read outputFileSystem of a MultiCompiler"); + } + + set inputFileSystem(value) { + for (const compiler of this.compilers) { + compiler.inputFileSystem = value; + } + } + + set outputFileSystem(value) { + for (const compiler of this.compilers) { + compiler.outputFileSystem = value; + } + } + + getInfrastructureLogger(name) { + return this.compilers[0].getInfrastructureLogger(name); + } + + validateDependencies(callback) { + const edges = new Set(); + const missing = []; + const targetFound = compiler => { + for (const edge of edges) { + if (edge.target === compiler) { + return true; + } + } + return false; + }; + const sortEdges = (e1, e2) => { + return ( + e1.source.name.localeCompare(e2.source.name) || + e1.target.name.localeCompare(e2.target.name) + ); + }; + for (const source of this.compilers) { + if (source.dependencies) { + for (const dep of source.dependencies) { + const target = this.compilers.find(c => c.name === dep); + if (!target) { + missing.push(dep); + } else { + edges.add({ + source, + target + }); + } + } + } + } + const errors = missing.map(m => `Compiler dependency \`${m}\` not found.`); + const stack = this.compilers.filter(c => !targetFound(c)); + while (stack.length > 0) { + const current = stack.pop(); + for (const edge of edges) { + if (edge.source === current) { + edges.delete(edge); + const target = edge.target; + if (!targetFound(target)) { + stack.push(target); + } + } + } + } + if (edges.size > 0) { + const lines = Array.from(edges) + .sort(sortEdges) + .map(edge => `${edge.source.name} -> ${edge.target.name}`); + lines.unshift("Circular dependency found in compiler dependencies."); + errors.unshift(lines.join("\n")); + } + if (errors.length > 0) { + const message = errors.join("\n"); + callback(new Error(message)); + return false; + } + return true; + } + + runWithDependencies(compilers, fn, callback) { + const fulfilledNames = new Set(); + let remainingCompilers = compilers; + const isDependencyFulfilled = d => fulfilledNames.has(d); + const getReadyCompilers = () => { + let readyCompilers = []; + let list = remainingCompilers; + remainingCompilers = []; + for (const c of list) { + const ready = + !c.dependencies || c.dependencies.every(isDependencyFulfilled); + if (ready) { + readyCompilers.push(c); + } else { + remainingCompilers.push(c); + } + } + return readyCompilers; + }; + const runCompilers = callback => { + if (remainingCompilers.length === 0) return callback(); + asyncLib.map( + getReadyCompilers(), + (compiler, callback) => { + fn(compiler, err => { + if (err) return callback(err); + fulfilledNames.add(compiler.name); + runCompilers(callback); + }); + }, + callback + ); + }; + runCompilers(callback); + } + + watch(watchOptions, handler) { + if (this.running) return handler(new ConcurrentCompilationError()); + + let watchings = []; + let allStats = this.compilers.map(() => null); + let compilerStatus = this.compilers.map(() => false); + if (this.validateDependencies(handler)) { + this.running = true; + this.runWithDependencies( + this.compilers, + (compiler, callback) => { + const compilerIdx = this.compilers.indexOf(compiler); + let firstRun = true; + let watching = compiler.watch( + Array.isArray(watchOptions) + ? watchOptions[compilerIdx] + : watchOptions, + (err, stats) => { + if (err) handler(err); + if (stats) { + allStats[compilerIdx] = stats; + compilerStatus[compilerIdx] = "new"; + if (compilerStatus.every(Boolean)) { + const freshStats = allStats.filter((s, idx) => { + return compilerStatus[idx] === "new"; + }); + compilerStatus.fill(true); + const multiStats = new MultiStats(freshStats); + handler(null, multiStats); + } + } + if (firstRun && !err) { + firstRun = false; + callback(); + } + } + ); + watchings.push(watching); + }, + () => { + // ignore + } + ); + } + + return new MultiWatching(watchings, this); + } + + run(callback) { + if (this.running) { + return callback(new ConcurrentCompilationError()); + } + + const finalCallback = (err, stats) => { + this.running = false; + + if (callback !== undefined) { + return callback(err, stats); + } + }; + + const allStats = this.compilers.map(() => null); + if (this.validateDependencies(callback)) { + this.running = true; + this.runWithDependencies( + this.compilers, + (compiler, callback) => { + const compilerIdx = this.compilers.indexOf(compiler); + compiler.run((err, stats) => { + if (err) { + return callback(err); + } + allStats[compilerIdx] = stats; + callback(); + }); + }, + err => { + if (err) { + return finalCallback(err); + } + finalCallback(null, new MultiStats(allStats)); + } + ); + } + } + + purgeInputFileSystem() { + for (const compiler of this.compilers) { + if (compiler.inputFileSystem && compiler.inputFileSystem.purge) { + compiler.inputFileSystem.purge(); + } + } + } +}; diff --git a/node_modules/webpack/lib/MultiEntryPlugin.js b/node_modules/webpack/lib/MultiEntryPlugin.js new file mode 100644 index 0000000..b38a823 --- /dev/null +++ b/node_modules/webpack/lib/MultiEntryPlugin.js @@ -0,0 +1,80 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const MultiEntryDependency = require("./dependencies/MultiEntryDependency"); +const SingleEntryDependency = require("./dependencies/SingleEntryDependency"); +const MultiModuleFactory = require("./MultiModuleFactory"); + +/** @typedef {import("./Compiler")} Compiler */ + +class MultiEntryPlugin { + /** + * The MultiEntryPlugin is invoked whenever this.options.entry value is an array of paths + * @param {string} context context path + * @param {string[]} entries array of entry paths + * @param {string} name entry key name + */ + constructor(context, entries, name) { + this.context = context; + this.entries = entries; + this.name = name; + } + + /** + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "MultiEntryPlugin", + (compilation, { normalModuleFactory }) => { + const multiModuleFactory = new MultiModuleFactory(); + + compilation.dependencyFactories.set( + MultiEntryDependency, + multiModuleFactory + ); + compilation.dependencyFactories.set( + SingleEntryDependency, + normalModuleFactory + ); + } + ); + + compiler.hooks.make.tapAsync( + "MultiEntryPlugin", + (compilation, callback) => { + const { context, entries, name } = this; + + const dep = MultiEntryPlugin.createDependency(entries, name); + compilation.addEntry(context, dep, name, callback); + } + ); + } + + /** + * @param {string[]} entries each entry path string + * @param {string} name name of the entry + * @returns {MultiEntryDependency} returns a constructed Dependency + */ + static createDependency(entries, name) { + return new MultiEntryDependency( + entries.map((e, idx) => { + const dep = new SingleEntryDependency(e); + // Because entrypoints are not dependencies found in an + // existing module, we give it a synthetic id + dep.loc = { + name, + index: idx + }; + return dep; + }), + name + ); + } +} + +module.exports = MultiEntryPlugin; diff --git a/node_modules/webpack/lib/MultiModule.js b/node_modules/webpack/lib/MultiModule.js new file mode 100644 index 0000000..c8e5d57 --- /dev/null +++ b/node_modules/webpack/lib/MultiModule.js @@ -0,0 +1,87 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Module = require("./Module"); +const Template = require("./Template"); +const { RawSource } = require("webpack-sources"); + +/** @typedef {import("./util/createHash").Hash} Hash */ + +class MultiModule extends Module { + constructor(context, dependencies, name) { + super("javascript/dynamic", context); + + // Info from Factory + this.dependencies = dependencies; + this.name = name; + this._identifier = `multi ${this.dependencies + .map(d => d.request) + .join(" ")}`; + } + + identifier() { + return this._identifier; + } + + readableIdentifier(requestShortener) { + return `multi ${this.dependencies + .map(d => requestShortener.shorten(d.request)) + .join(" ")}`; + } + + build(options, compilation, resolver, fs, callback) { + this.built = true; + this.buildMeta = {}; + this.buildInfo = {}; + return callback(); + } + + needRebuild() { + return false; + } + + size() { + return 16 + this.dependencies.length * 12; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update("multi module"); + hash.update(this.name || ""); + super.updateHash(hash); + } + + source(dependencyTemplates, runtimeTemplate) { + const str = []; + let idx = 0; + for (const dep of this.dependencies) { + if (dep.module) { + if (idx === this.dependencies.length - 1) { + str.push("module.exports = "); + } + str.push("__webpack_require__("); + if (runtimeTemplate.outputOptions.pathinfo) { + str.push(Template.toComment(dep.request)); + } + str.push(`${JSON.stringify(dep.module.id)}`); + str.push(")"); + } else { + const content = require("./dependencies/WebpackMissingModule").module( + dep.request + ); + str.push(content); + } + str.push(";\n"); + idx++; + } + return new RawSource(str.join("")); + } +} + +module.exports = MultiModule; diff --git a/node_modules/webpack/lib/MultiModuleFactory.js b/node_modules/webpack/lib/MultiModuleFactory.js new file mode 100644 index 0000000..5d29b20 --- /dev/null +++ b/node_modules/webpack/lib/MultiModuleFactory.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { Tapable } = require("tapable"); +const MultiModule = require("./MultiModule"); + +module.exports = class MultiModuleFactory extends Tapable { + constructor() { + super(); + this.hooks = {}; + } + + create(data, callback) { + const dependency = data.dependencies[0]; + callback( + null, + new MultiModule(data.context, dependency.dependencies, dependency.name) + ); + } +}; diff --git a/node_modules/webpack/lib/MultiStats.js b/node_modules/webpack/lib/MultiStats.js new file mode 100644 index 0000000..1a5fcf2 --- /dev/null +++ b/node_modules/webpack/lib/MultiStats.js @@ -0,0 +1,92 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Stats = require("./Stats"); + +const optionOrFallback = (optionValue, fallbackValue) => + optionValue !== undefined ? optionValue : fallbackValue; + +class MultiStats { + constructor(stats) { + this.stats = stats; + this.hash = stats.map(stat => stat.hash).join(""); + } + + hasErrors() { + return this.stats + .map(stat => stat.hasErrors()) + .reduce((a, b) => a || b, false); + } + + hasWarnings() { + return this.stats + .map(stat => stat.hasWarnings()) + .reduce((a, b) => a || b, false); + } + + toJson(options, forToString) { + if (typeof options === "boolean" || typeof options === "string") { + options = Stats.presetToOptions(options); + } else if (!options) { + options = {}; + } + const jsons = this.stats.map((stat, idx) => { + const childOptions = Stats.getChildOptions(options, idx); + const obj = stat.toJson(childOptions, forToString); + obj.name = stat.compilation && stat.compilation.name; + return obj; + }); + const showVersion = + options.version === undefined + ? jsons.every(j => j.version) + : options.version !== false; + const showHash = + options.hash === undefined + ? jsons.every(j => j.hash) + : options.hash !== false; + if (showVersion) { + for (const j of jsons) { + delete j.version; + } + } + const obj = { + errors: jsons.reduce((arr, j) => { + return arr.concat( + j.errors.map(msg => { + return `(${j.name}) ${msg}`; + }) + ); + }, []), + warnings: jsons.reduce((arr, j) => { + return arr.concat( + j.warnings.map(msg => { + return `(${j.name}) ${msg}`; + }) + ); + }, []) + }; + if (showVersion) obj.version = require("../package.json").version; + if (showHash) obj.hash = this.hash; + if (options.children !== false) obj.children = jsons; + return obj; + } + + toString(options) { + if (typeof options === "boolean" || typeof options === "string") { + options = Stats.presetToOptions(options); + } else if (!options) { + options = {}; + } + + const useColors = optionOrFallback(options.colors, false); + + const obj = this.toJson(options, true); + + return Stats.jsonToString(obj, useColors); + } +} + +module.exports = MultiStats; diff --git a/node_modules/webpack/lib/MultiWatching.js b/node_modules/webpack/lib/MultiWatching.js new file mode 100644 index 0000000..c16d3af --- /dev/null +++ b/node_modules/webpack/lib/MultiWatching.js @@ -0,0 +1,50 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const asyncLib = require("neo-async"); + +class MultiWatching { + constructor(watchings, compiler) { + this.watchings = watchings; + this.compiler = compiler; + } + + invalidate() { + for (const watching of this.watchings) { + watching.invalidate(); + } + } + + suspend() { + for (const watching of this.watchings) { + watching.suspend(); + } + } + + resume() { + for (const watching of this.watchings) { + watching.resume(); + } + } + + close(callback) { + asyncLib.forEach( + this.watchings, + (watching, finishedCallback) => { + watching.close(finishedCallback); + }, + err => { + this.compiler.hooks.watchClose.call(); + if (typeof callback === "function") { + this.compiler.running = false; + callback(err); + } + } + ); + } +} + +module.exports = MultiWatching; diff --git a/node_modules/webpack/lib/NamedChunksPlugin.js b/node_modules/webpack/lib/NamedChunksPlugin.js new file mode 100644 index 0000000..0cb5b6b --- /dev/null +++ b/node_modules/webpack/lib/NamedChunksPlugin.js @@ -0,0 +1,29 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class NamedChunksPlugin { + static defaultNameResolver(chunk) { + return chunk.name || null; + } + + constructor(nameResolver) { + this.nameResolver = nameResolver || NamedChunksPlugin.defaultNameResolver; + } + + apply(compiler) { + compiler.hooks.compilation.tap("NamedChunksPlugin", compilation => { + compilation.hooks.beforeChunkIds.tap("NamedChunksPlugin", chunks => { + for (const chunk of chunks) { + if (chunk.id === null) { + chunk.id = this.nameResolver(chunk); + } + } + }); + }); + } +} + +module.exports = NamedChunksPlugin; diff --git a/node_modules/webpack/lib/NamedModulesPlugin.js b/node_modules/webpack/lib/NamedModulesPlugin.js new file mode 100644 index 0000000..2d84aaf --- /dev/null +++ b/node_modules/webpack/lib/NamedModulesPlugin.js @@ -0,0 +1,58 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const createHash = require("./util/createHash"); +const RequestShortener = require("./RequestShortener"); + +const getHash = str => { + const hash = createHash("md4"); + hash.update(str); + const digest = /** @type {string} */ (hash.digest("hex")); + return digest.substr(0, 4); +}; + +class NamedModulesPlugin { + constructor(options) { + this.options = options || {}; + } + + apply(compiler) { + compiler.hooks.compilation.tap("NamedModulesPlugin", compilation => { + compilation.hooks.beforeModuleIds.tap("NamedModulesPlugin", modules => { + const namedModules = new Map(); + const context = this.options.context || compiler.options.context; + + for (const module of modules) { + if (module.id === null && module.libIdent) { + module.id = module.libIdent({ context }); + } + + if (module.id !== null) { + const namedModule = namedModules.get(module.id); + if (namedModule !== undefined) { + namedModule.push(module); + } else { + namedModules.set(module.id, [module]); + } + } + } + + for (const namedModule of namedModules.values()) { + if (namedModule.length > 1) { + for (const module of namedModule) { + const requestShortener = new RequestShortener(context); + module.id = `${module.id}?${getHash( + requestShortener.shorten(module.identifier()) + )}`; + } + } + } + }); + }); + } +} + +module.exports = NamedModulesPlugin; diff --git a/node_modules/webpack/lib/NoEmitOnErrorsPlugin.js b/node_modules/webpack/lib/NoEmitOnErrorsPlugin.js new file mode 100644 index 0000000..2c37c49 --- /dev/null +++ b/node_modules/webpack/lib/NoEmitOnErrorsPlugin.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class NoEmitOnErrorsPlugin { + apply(compiler) { + compiler.hooks.shouldEmit.tap("NoEmitOnErrorsPlugin", compilation => { + if (compilation.getStats().hasErrors()) return false; + }); + compiler.hooks.compilation.tap("NoEmitOnErrorsPlugin", compilation => { + compilation.hooks.shouldRecord.tap("NoEmitOnErrorsPlugin", () => { + if (compilation.getStats().hasErrors()) return false; + }); + }); + } +} + +module.exports = NoEmitOnErrorsPlugin; diff --git a/node_modules/webpack/lib/NoModeWarning.js b/node_modules/webpack/lib/NoModeWarning.js new file mode 100644 index 0000000..4bd3c3f --- /dev/null +++ b/node_modules/webpack/lib/NoModeWarning.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +module.exports = class NoModeWarning extends WebpackError { + constructor(modules) { + super(); + + this.name = "NoModeWarning"; + this.message = + "configuration\n" + + "The 'mode' option has not been set, webpack will fallback to 'production' for this value. " + + "Set 'mode' option to 'development' or 'production' to enable defaults for each environment.\n" + + "You can also set it to 'none' to disable any default behavior. " + + "Learn more: https://webpack.js.org/configuration/mode/"; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/NodeStuffPlugin.js b/node_modules/webpack/lib/NodeStuffPlugin.js new file mode 100644 index 0000000..5b38268 --- /dev/null +++ b/node_modules/webpack/lib/NodeStuffPlugin.js @@ -0,0 +1,118 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const ParserHelpers = require("./ParserHelpers"); +const ConstDependency = require("./dependencies/ConstDependency"); + +const NullFactory = require("./NullFactory"); + +class NodeStuffPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap( + "NodeStuffPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if (parserOptions.node === false) return; + + let localOptions = options; + if (parserOptions.node) { + localOptions = Object.assign({}, localOptions, parserOptions.node); + } + + const setConstant = (expressionName, value) => { + parser.hooks.expression + .for(expressionName) + .tap("NodeStuffPlugin", () => { + parser.state.current.addVariable( + expressionName, + JSON.stringify(value) + ); + return true; + }); + }; + + const setModuleConstant = (expressionName, fn) => { + parser.hooks.expression + .for(expressionName) + .tap("NodeStuffPlugin", () => { + parser.state.current.addVariable( + expressionName, + JSON.stringify(fn(parser.state.module)) + ); + return true; + }); + }; + const context = compiler.context; + if (localOptions.__filename) { + if (localOptions.__filename === "mock") { + setConstant("__filename", "/index.js"); + } else { + setModuleConstant("__filename", module => + path.relative(context, module.resource) + ); + } + parser.hooks.evaluateIdentifier + .for("__filename") + .tap("NodeStuffPlugin", expr => { + if (!parser.state.module) return; + const resource = parser.state.module.resource; + const i = resource.indexOf("?"); + return ParserHelpers.evaluateToString( + i < 0 ? resource : resource.substr(0, i) + )(expr); + }); + } + if (localOptions.__dirname) { + if (localOptions.__dirname === "mock") { + setConstant("__dirname", "/"); + } else { + setModuleConstant("__dirname", module => + path.relative(context, module.context) + ); + } + parser.hooks.evaluateIdentifier + .for("__dirname") + .tap("NodeStuffPlugin", expr => { + if (!parser.state.module) return; + return ParserHelpers.evaluateToString( + parser.state.module.context + )(expr); + }); + } + parser.hooks.expression + .for("require.extensions") + .tap( + "NodeStuffPlugin", + ParserHelpers.expressionIsUnsupported( + parser, + "require.extensions is not supported by webpack. Use a loader instead." + ) + ); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("NodeStuffPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("NodeStuffPlugin", handler); + } + ); + } +} +module.exports = NodeStuffPlugin; diff --git a/node_modules/webpack/lib/NormalModule.js b/node_modules/webpack/lib/NormalModule.js new file mode 100644 index 0000000..76aa1bd --- /dev/null +++ b/node_modules/webpack/lib/NormalModule.js @@ -0,0 +1,582 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const NativeModule = require("module"); + +const { + CachedSource, + LineToLineMappedSource, + OriginalSource, + RawSource, + SourceMapSource +} = require("webpack-sources"); +const { getContext, runLoaders } = require("loader-runner"); + +const WebpackError = require("./WebpackError"); +const Module = require("./Module"); +const ModuleParseError = require("./ModuleParseError"); +const ModuleBuildError = require("./ModuleBuildError"); +const ModuleError = require("./ModuleError"); +const ModuleWarning = require("./ModuleWarning"); +const createHash = require("./util/createHash"); +const contextify = require("./util/identifier").contextify; + +/** @typedef {import("./util/createHash").Hash} Hash */ + +const asString = buf => { + if (Buffer.isBuffer(buf)) { + return buf.toString("utf-8"); + } + return buf; +}; + +const asBuffer = str => { + if (!Buffer.isBuffer(str)) { + return Buffer.from(str, "utf-8"); + } + return str; +}; + +class NonErrorEmittedError extends WebpackError { + constructor(error) { + super(); + + this.name = "NonErrorEmittedError"; + this.message = "(Emitted value instead of an instance of Error) " + error; + + Error.captureStackTrace(this, this.constructor); + } +} + +/** + * @typedef {Object} CachedSourceEntry + * @property {TODO} source the generated source + * @property {string} hash the hash value + */ + +class NormalModule extends Module { + constructor({ + type, + request, + userRequest, + rawRequest, + loaders, + resource, + matchResource, + parser, + generator, + resolveOptions + }) { + super(type, getContext(resource)); + + // Info from Factory + this.request = request; + this.userRequest = userRequest; + this.rawRequest = rawRequest; + this.binary = type.startsWith("webassembly"); + this.parser = parser; + this.generator = generator; + this.resource = resource; + this.matchResource = matchResource; + this.loaders = loaders; + if (resolveOptions !== undefined) this.resolveOptions = resolveOptions; + + // Info from Build + this.error = null; + this._source = null; + this._sourceSize = null; + this._buildHash = ""; + this.buildTimestamp = undefined; + /** @private @type {Map<string, CachedSourceEntry>} */ + this._cachedSources = new Map(); + + // Options for the NormalModule set by plugins + // TODO refactor this -> options object filled from Factory + this.useSourceMap = false; + this.lineToLine = false; + + // Cache + this._lastSuccessfulBuildMeta = {}; + } + + identifier() { + return this.request; + } + + readableIdentifier(requestShortener) { + return requestShortener.shorten(this.userRequest); + } + + libIdent(options) { + return contextify(options.context, this.userRequest); + } + + nameForCondition() { + const resource = this.matchResource || this.resource; + const idx = resource.indexOf("?"); + if (idx >= 0) return resource.substr(0, idx); + return resource; + } + + updateCacheModule(module) { + this.type = module.type; + this.request = module.request; + this.userRequest = module.userRequest; + this.rawRequest = module.rawRequest; + this.parser = module.parser; + this.generator = module.generator; + this.resource = module.resource; + this.matchResource = module.matchResource; + this.loaders = module.loaders; + this.resolveOptions = module.resolveOptions; + } + + createSourceForAsset(name, content, sourceMap) { + if (!sourceMap) { + return new RawSource(content); + } + + if (typeof sourceMap === "string") { + return new OriginalSource(content, sourceMap); + } + + return new SourceMapSource(content, name, sourceMap); + } + + createLoaderContext(resolver, options, compilation, fs) { + const requestShortener = compilation.runtimeTemplate.requestShortener; + const getCurrentLoaderName = () => { + const currentLoader = this.getCurrentLoader(loaderContext); + if (!currentLoader) return "(not in loader scope)"; + return requestShortener.shorten(currentLoader.loader); + }; + const loaderContext = { + version: 2, + emitWarning: warning => { + if (!(warning instanceof Error)) { + warning = new NonErrorEmittedError(warning); + } + this.warnings.push( + new ModuleWarning(this, warning, { + from: getCurrentLoaderName() + }) + ); + }, + emitError: error => { + if (!(error instanceof Error)) { + error = new NonErrorEmittedError(error); + } + this.errors.push( + new ModuleError(this, error, { + from: getCurrentLoaderName() + }) + ); + }, + getLogger: name => { + const currentLoader = this.getCurrentLoader(loaderContext); + return compilation.getLogger(() => + [currentLoader && currentLoader.loader, name, this.identifier()] + .filter(Boolean) + .join("|") + ); + }, + // TODO remove in webpack 5 + exec: (code, filename) => { + // @ts-ignore Argument of type 'this' is not assignable to parameter of type 'Module'. + const module = new NativeModule(filename, this); + // @ts-ignore _nodeModulePaths is deprecated and undocumented Node.js API + module.paths = NativeModule._nodeModulePaths(this.context); + module.filename = filename; + module._compile(code, filename); + return module.exports; + }, + resolve(context, request, callback) { + resolver.resolve({}, context, request, {}, callback); + }, + getResolve(options) { + const child = options ? resolver.withOptions(options) : resolver; + return (context, request, callback) => { + if (callback) { + child.resolve({}, context, request, {}, callback); + } else { + return new Promise((resolve, reject) => { + child.resolve({}, context, request, {}, (err, result) => { + if (err) reject(err); + else resolve(result); + }); + }); + } + }; + }, + emitFile: (name, content, sourceMap, assetInfo) => { + if (!this.buildInfo.assets) { + this.buildInfo.assets = Object.create(null); + this.buildInfo.assetsInfo = new Map(); + } + this.buildInfo.assets[name] = this.createSourceForAsset( + name, + content, + sourceMap + ); + this.buildInfo.assetsInfo.set(name, assetInfo); + }, + rootContext: options.context, + webpack: true, + sourceMap: !!this.useSourceMap, + mode: options.mode || "production", + _module: this, + _compilation: compilation, + _compiler: compilation.compiler, + fs: fs + }; + + compilation.hooks.normalModuleLoader.call(loaderContext, this); + if (options.loader) { + Object.assign(loaderContext, options.loader); + } + + return loaderContext; + } + + getCurrentLoader(loaderContext, index = loaderContext.loaderIndex) { + if ( + this.loaders && + this.loaders.length && + index < this.loaders.length && + index >= 0 && + this.loaders[index] + ) { + return this.loaders[index]; + } + return null; + } + + createSource(source, resourceBuffer, sourceMap) { + // if there is no identifier return raw source + if (!this.identifier) { + return new RawSource(source); + } + + // from here on we assume we have an identifier + const identifier = this.identifier(); + + if (this.lineToLine && resourceBuffer) { + return new LineToLineMappedSource( + source, + identifier, + asString(resourceBuffer) + ); + } + + if (this.useSourceMap && sourceMap) { + return new SourceMapSource(source, identifier, sourceMap); + } + + if (Buffer.isBuffer(source)) { + // @ts-ignore + // TODO We need to fix @types/webpack-sources to allow RawSource to take a Buffer | string + return new RawSource(source); + } + + return new OriginalSource(source, identifier); + } + + doBuild(options, compilation, resolver, fs, callback) { + const loaderContext = this.createLoaderContext( + resolver, + options, + compilation, + fs + ); + + runLoaders( + { + resource: this.resource, + loaders: this.loaders, + context: loaderContext, + readResource: fs.readFile.bind(fs) + }, + (err, result) => { + if (result) { + this.buildInfo.cacheable = result.cacheable; + this.buildInfo.fileDependencies = new Set(result.fileDependencies); + this.buildInfo.contextDependencies = new Set( + result.contextDependencies + ); + } + + if (err) { + if (!(err instanceof Error)) { + err = new NonErrorEmittedError(err); + } + const currentLoader = this.getCurrentLoader(loaderContext); + const error = new ModuleBuildError(this, err, { + from: + currentLoader && + compilation.runtimeTemplate.requestShortener.shorten( + currentLoader.loader + ) + }); + return callback(error); + } + + const resourceBuffer = result.resourceBuffer; + const source = result.result[0]; + const sourceMap = result.result.length >= 1 ? result.result[1] : null; + const extraInfo = result.result.length >= 2 ? result.result[2] : null; + + if (!Buffer.isBuffer(source) && typeof source !== "string") { + const currentLoader = this.getCurrentLoader(loaderContext, 0); + const err = new Error( + `Final loader (${ + currentLoader + ? compilation.runtimeTemplate.requestShortener.shorten( + currentLoader.loader + ) + : "unknown" + }) didn't return a Buffer or String` + ); + const error = new ModuleBuildError(this, err); + return callback(error); + } + + this._source = this.createSource( + this.binary ? asBuffer(source) : asString(source), + resourceBuffer, + sourceMap + ); + this._sourceSize = null; + this._ast = + typeof extraInfo === "object" && + extraInfo !== null && + extraInfo.webpackAST !== undefined + ? extraInfo.webpackAST + : null; + return callback(); + } + ); + } + + markModuleAsErrored(error) { + // Restore build meta from successful build to keep importing state + this.buildMeta = Object.assign({}, this._lastSuccessfulBuildMeta); + this.error = error; + this.errors.push(this.error); + this._source = new RawSource( + "throw new Error(" + JSON.stringify(this.error.message) + ");" + ); + this._sourceSize = null; + this._ast = null; + } + + applyNoParseRule(rule, content) { + // must start with "rule" if rule is a string + if (typeof rule === "string") { + return content.indexOf(rule) === 0; + } + + if (typeof rule === "function") { + return rule(content); + } + // we assume rule is a regexp + return rule.test(content); + } + + // check if module should not be parsed + // returns "true" if the module should !not! be parsed + // returns "false" if the module !must! be parsed + shouldPreventParsing(noParseRule, request) { + // if no noParseRule exists, return false + // the module !must! be parsed. + if (!noParseRule) { + return false; + } + + // we only have one rule to check + if (!Array.isArray(noParseRule)) { + // returns "true" if the module is !not! to be parsed + return this.applyNoParseRule(noParseRule, request); + } + + for (let i = 0; i < noParseRule.length; i++) { + const rule = noParseRule[i]; + // early exit on first truthy match + // this module is !not! to be parsed + if (this.applyNoParseRule(rule, request)) { + return true; + } + } + // no match found, so this module !should! be parsed + return false; + } + + _initBuildHash(compilation) { + const hash = createHash(compilation.outputOptions.hashFunction); + if (this._source) { + hash.update("source"); + this._source.updateHash(hash); + } + hash.update("meta"); + hash.update(JSON.stringify(this.buildMeta)); + this._buildHash = /** @type {string} */ (hash.digest("hex")); + } + + build(options, compilation, resolver, fs, callback) { + this.buildTimestamp = Date.now(); + this.built = true; + this._source = null; + this._sourceSize = null; + this._ast = null; + this._buildHash = ""; + this.error = null; + this.errors.length = 0; + this.warnings.length = 0; + this.buildMeta = {}; + this.buildInfo = { + cacheable: false, + fileDependencies: new Set(), + contextDependencies: new Set(), + assets: undefined, + assetsInfo: undefined + }; + + return this.doBuild(options, compilation, resolver, fs, err => { + this._cachedSources.clear(); + + // if we have an error mark module as failed and exit + if (err) { + this.markModuleAsErrored(err); + this._initBuildHash(compilation); + return callback(); + } + + // check if this module should !not! be parsed. + // if so, exit here; + const noParseRule = options.module && options.module.noParse; + if (this.shouldPreventParsing(noParseRule, this.request)) { + this._initBuildHash(compilation); + return callback(); + } + + const handleParseError = e => { + const source = this._source.source(); + const loaders = this.loaders.map(item => + contextify(options.context, item.loader) + ); + const error = new ModuleParseError(this, source, e, loaders); + this.markModuleAsErrored(error); + this._initBuildHash(compilation); + return callback(); + }; + + const handleParseResult = result => { + this._lastSuccessfulBuildMeta = this.buildMeta; + this._initBuildHash(compilation); + return callback(); + }; + + try { + const result = this.parser.parse( + this._ast || this._source.source(), + { + current: this, + module: this, + compilation: compilation, + options: options + }, + (err, result) => { + if (err) { + handleParseError(err); + } else { + handleParseResult(result); + } + } + ); + if (result !== undefined) { + // parse is sync + handleParseResult(result); + } + } catch (e) { + handleParseError(e); + } + }); + } + + getHashDigest(dependencyTemplates) { + // TODO webpack 5 refactor + let dtHash = dependencyTemplates.get("hash"); + return `${this.hash}-${dtHash}`; + } + + source(dependencyTemplates, runtimeTemplate, type = "javascript") { + const hashDigest = this.getHashDigest(dependencyTemplates); + const cacheEntry = this._cachedSources.get(type); + if (cacheEntry !== undefined && cacheEntry.hash === hashDigest) { + // We can reuse the cached source + return cacheEntry.source; + } + + const source = this.generator.generate( + this, + dependencyTemplates, + runtimeTemplate, + type + ); + + const cachedSource = new CachedSource(source); + this._cachedSources.set(type, { + source: cachedSource, + hash: hashDigest + }); + return cachedSource; + } + + originalSource() { + return this._source; + } + + needRebuild(fileTimestamps, contextTimestamps) { + // always try to rebuild in case of an error + if (this.error) return true; + + // always rebuild when module is not cacheable + if (!this.buildInfo.cacheable) return true; + + // Check timestamps of all dependencies + // Missing timestamp -> need rebuild + // Timestamp bigger than buildTimestamp -> need rebuild + for (const file of this.buildInfo.fileDependencies) { + const timestamp = fileTimestamps.get(file); + if (!timestamp) return true; + if (timestamp >= this.buildTimestamp) return true; + } + for (const file of this.buildInfo.contextDependencies) { + const timestamp = contextTimestamps.get(file); + if (!timestamp) return true; + if (timestamp >= this.buildTimestamp) return true; + } + // elsewise -> no rebuild needed + return false; + } + + size() { + if (this._sourceSize === null) { + this._sourceSize = this._source ? this._source.size() : -1; + } + return this._sourceSize; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + hash.update(this._buildHash); + super.updateHash(hash); + } +} + +module.exports = NormalModule; diff --git a/node_modules/webpack/lib/NormalModuleFactory.js b/node_modules/webpack/lib/NormalModuleFactory.js new file mode 100644 index 0000000..e6a4109 --- /dev/null +++ b/node_modules/webpack/lib/NormalModuleFactory.js @@ -0,0 +1,528 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const path = require("path"); +const asyncLib = require("neo-async"); +const { + Tapable, + AsyncSeriesWaterfallHook, + SyncWaterfallHook, + SyncBailHook, + SyncHook, + HookMap +} = require("tapable"); +const NormalModule = require("./NormalModule"); +const RawModule = require("./RawModule"); +const RuleSet = require("./RuleSet"); +const { cachedCleverMerge } = require("./util/cleverMerge"); + +const EMPTY_RESOLVE_OPTIONS = {}; + +const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/; + +const loaderToIdent = data => { + if (!data.options) { + return data.loader; + } + if (typeof data.options === "string") { + return data.loader + "?" + data.options; + } + if (typeof data.options !== "object") { + throw new Error("loader options must be string or object"); + } + if (data.ident) { + return data.loader + "??" + data.ident; + } + return data.loader + "?" + JSON.stringify(data.options); +}; + +const identToLoaderRequest = resultString => { + const idx = resultString.indexOf("?"); + if (idx >= 0) { + const loader = resultString.substr(0, idx); + const options = resultString.substr(idx + 1); + return { + loader, + options + }; + } else { + return { + loader: resultString, + options: undefined + }; + } +}; + +const dependencyCache = new WeakMap(); + +class NormalModuleFactory extends Tapable { + constructor(context, resolverFactory, options) { + super(); + this.hooks = { + resolver: new SyncWaterfallHook(["resolver"]), + factory: new SyncWaterfallHook(["factory"]), + beforeResolve: new AsyncSeriesWaterfallHook(["data"]), + afterResolve: new AsyncSeriesWaterfallHook(["data"]), + createModule: new SyncBailHook(["data"]), + module: new SyncWaterfallHook(["module", "data"]), + createParser: new HookMap(() => new SyncBailHook(["parserOptions"])), + parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])), + createGenerator: new HookMap( + () => new SyncBailHook(["generatorOptions"]) + ), + generator: new HookMap( + () => new SyncHook(["generator", "generatorOptions"]) + ) + }; + this._pluginCompat.tap("NormalModuleFactory", options => { + switch (options.name) { + case "before-resolve": + case "after-resolve": + options.async = true; + break; + case "parser": + this.hooks.parser + .for("javascript/auto") + .tap(options.fn.name || "unnamed compat plugin", options.fn); + return true; + } + let match; + match = /^parser (.+)$/.exec(options.name); + if (match) { + this.hooks.parser + .for(match[1]) + .tap( + options.fn.name || "unnamed compat plugin", + options.fn.bind(this) + ); + return true; + } + match = /^create-parser (.+)$/.exec(options.name); + if (match) { + this.hooks.createParser + .for(match[1]) + .tap( + options.fn.name || "unnamed compat plugin", + options.fn.bind(this) + ); + return true; + } + }); + this.resolverFactory = resolverFactory; + this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules)); + this.cachePredicate = + typeof options.unsafeCache === "function" + ? options.unsafeCache + : Boolean.bind(null, options.unsafeCache); + this.context = context || ""; + this.parserCache = Object.create(null); + this.generatorCache = Object.create(null); + this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => { + let resolver = this.hooks.resolver.call(null); + + // Ignored + if (!resolver) return callback(); + + resolver(result, (err, data) => { + if (err) return callback(err); + + // Ignored + if (!data) return callback(); + + // direct module + if (typeof data.source === "function") return callback(null, data); + + this.hooks.afterResolve.callAsync(data, (err, result) => { + if (err) return callback(err); + + // Ignored + if (!result) return callback(); + + let createdModule = this.hooks.createModule.call(result); + if (!createdModule) { + if (!result.request) { + return callback(new Error("Empty dependency (no request)")); + } + + createdModule = new NormalModule(result); + } + + createdModule = this.hooks.module.call(createdModule, result); + + return callback(null, createdModule); + }); + }); + }); + this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => { + const contextInfo = data.contextInfo; + const context = data.context; + const request = data.request; + + const loaderResolver = this.getResolver("loader"); + const normalResolver = this.getResolver("normal", data.resolveOptions); + + let matchResource = undefined; + let requestWithoutMatchResource = request; + const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request); + if (matchResourceMatch) { + matchResource = matchResourceMatch[1]; + if (/^\.\.?\//.test(matchResource)) { + matchResource = path.join(context, matchResource); + } + requestWithoutMatchResource = request.substr( + matchResourceMatch[0].length + ); + } + + const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!"); + const noAutoLoaders = + noPreAutoLoaders || requestWithoutMatchResource.startsWith("!"); + const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith("!!"); + let elements = requestWithoutMatchResource + .replace(/^-?!+/, "") + .replace(/!!+/g, "!") + .split("!"); + let resource = elements.pop(); + elements = elements.map(identToLoaderRequest); + + asyncLib.parallel( + [ + callback => + this.resolveRequestArray( + contextInfo, + context, + elements, + loaderResolver, + callback + ), + callback => { + if (resource === "" || resource[0] === "?") { + return callback(null, { + resource + }); + } + + normalResolver.resolve( + contextInfo, + context, + resource, + {}, + (err, resource, resourceResolveData) => { + if (err) return callback(err); + callback(null, { + resourceResolveData, + resource + }); + } + ); + } + ], + (err, results) => { + if (err) return callback(err); + let loaders = results[0]; + const resourceResolveData = results[1].resourceResolveData; + resource = results[1].resource; + + // translate option idents + try { + for (const item of loaders) { + if (typeof item.options === "string" && item.options[0] === "?") { + const ident = item.options.substr(1); + item.options = this.ruleSet.findOptionsByIdent(ident); + item.ident = ident; + } + } + } catch (e) { + return callback(e); + } + + if (resource === false) { + // ignored + return callback( + null, + new RawModule( + "/* (ignored) */", + `ignored ${context} ${request}`, + `${request} (ignored)` + ) + ); + } + + const userRequest = + (matchResource !== undefined ? `${matchResource}!=!` : "") + + loaders + .map(loaderToIdent) + .concat([resource]) + .join("!"); + + let resourcePath = + matchResource !== undefined ? matchResource : resource; + let resourceQuery = ""; + const queryIndex = resourcePath.indexOf("?"); + if (queryIndex >= 0) { + resourceQuery = resourcePath.substr(queryIndex); + resourcePath = resourcePath.substr(0, queryIndex); + } + + const result = this.ruleSet.exec({ + resource: resourcePath, + realResource: + matchResource !== undefined + ? resource.replace(/\?.*/, "") + : resourcePath, + resourceQuery, + issuer: contextInfo.issuer, + compiler: contextInfo.compiler + }); + const settings = {}; + const useLoadersPost = []; + const useLoaders = []; + const useLoadersPre = []; + for (const r of result) { + if (r.type === "use") { + if (r.enforce === "post" && !noPrePostAutoLoaders) { + useLoadersPost.push(r.value); + } else if ( + r.enforce === "pre" && + !noPreAutoLoaders && + !noPrePostAutoLoaders + ) { + useLoadersPre.push(r.value); + } else if ( + !r.enforce && + !noAutoLoaders && + !noPrePostAutoLoaders + ) { + useLoaders.push(r.value); + } + } else if ( + typeof r.value === "object" && + r.value !== null && + typeof settings[r.type] === "object" && + settings[r.type] !== null + ) { + settings[r.type] = cachedCleverMerge(settings[r.type], r.value); + } else { + settings[r.type] = r.value; + } + } + asyncLib.parallel( + [ + this.resolveRequestArray.bind( + this, + contextInfo, + this.context, + useLoadersPost, + loaderResolver + ), + this.resolveRequestArray.bind( + this, + contextInfo, + this.context, + useLoaders, + loaderResolver + ), + this.resolveRequestArray.bind( + this, + contextInfo, + this.context, + useLoadersPre, + loaderResolver + ) + ], + (err, results) => { + if (err) return callback(err); + if (matchResource === undefined) { + loaders = results[0].concat(loaders, results[1], results[2]); + } else { + loaders = results[0].concat(results[1], loaders, results[2]); + } + process.nextTick(() => { + const type = settings.type; + const resolveOptions = settings.resolve; + callback(null, { + context: context, + request: loaders + .map(loaderToIdent) + .concat([resource]) + .join("!"), + dependencies: data.dependencies, + userRequest, + rawRequest: request, + loaders, + resource, + matchResource, + resourceResolveData, + settings, + type, + parser: this.getParser(type, settings.parser), + generator: this.getGenerator(type, settings.generator), + resolveOptions + }); + }); + } + ); + } + ); + }); + } + + create(data, callback) { + const dependencies = data.dependencies; + const cacheEntry = dependencyCache.get(dependencies[0]); + if (cacheEntry) return callback(null, cacheEntry); + const context = data.context || this.context; + const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS; + const request = dependencies[0].request; + const contextInfo = data.contextInfo || {}; + this.hooks.beforeResolve.callAsync( + { + contextInfo, + resolveOptions, + context, + request, + dependencies + }, + (err, result) => { + if (err) return callback(err); + + // Ignored + if (!result) return callback(); + + const factory = this.hooks.factory.call(null); + + // Ignored + if (!factory) return callback(); + + factory(result, (err, module) => { + if (err) return callback(err); + + if (module && this.cachePredicate(module)) { + for (const d of dependencies) { + dependencyCache.set(d, module); + } + } + + callback(null, module); + }); + } + ); + } + + resolveRequestArray(contextInfo, context, array, resolver, callback) { + if (array.length === 0) return callback(null, []); + asyncLib.map( + array, + (item, callback) => { + resolver.resolve( + contextInfo, + context, + item.loader, + {}, + (err, result) => { + if ( + err && + /^[^/]*$/.test(item.loader) && + !/-loader$/.test(item.loader) + ) { + return resolver.resolve( + contextInfo, + context, + item.loader + "-loader", + {}, + err2 => { + if (!err2) { + err.message = + err.message + + "\n" + + "BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" + + ` You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` + + " see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed"; + } + callback(err); + } + ); + } + if (err) return callback(err); + + const optionsOnly = item.options + ? { + options: item.options + } + : undefined; + return callback( + null, + Object.assign({}, item, identToLoaderRequest(result), optionsOnly) + ); + } + ); + }, + callback + ); + } + + getParser(type, parserOptions) { + let ident = type; + if (parserOptions) { + if (parserOptions.ident) { + ident = `${type}|${parserOptions.ident}`; + } else { + ident = JSON.stringify([type, parserOptions]); + } + } + if (ident in this.parserCache) { + return this.parserCache[ident]; + } + return (this.parserCache[ident] = this.createParser(type, parserOptions)); + } + + createParser(type, parserOptions = {}) { + const parser = this.hooks.createParser.for(type).call(parserOptions); + if (!parser) { + throw new Error(`No parser registered for ${type}`); + } + this.hooks.parser.for(type).call(parser, parserOptions); + return parser; + } + + getGenerator(type, generatorOptions) { + let ident = type; + if (generatorOptions) { + if (generatorOptions.ident) { + ident = `${type}|${generatorOptions.ident}`; + } else { + ident = JSON.stringify([type, generatorOptions]); + } + } + if (ident in this.generatorCache) { + return this.generatorCache[ident]; + } + return (this.generatorCache[ident] = this.createGenerator( + type, + generatorOptions + )); + } + + createGenerator(type, generatorOptions = {}) { + const generator = this.hooks.createGenerator + .for(type) + .call(generatorOptions); + if (!generator) { + throw new Error(`No generator registered for ${type}`); + } + this.hooks.generator.for(type).call(generator, generatorOptions); + return generator; + } + + getResolver(type, resolveOptions) { + return this.resolverFactory.get( + type, + resolveOptions || EMPTY_RESOLVE_OPTIONS + ); + } +} + +module.exports = NormalModuleFactory; diff --git a/node_modules/webpack/lib/NormalModuleReplacementPlugin.js b/node_modules/webpack/lib/NormalModuleReplacementPlugin.js new file mode 100644 index 0000000..d4f23a5 --- /dev/null +++ b/node_modules/webpack/lib/NormalModuleReplacementPlugin.js @@ -0,0 +1,51 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); + +class NormalModuleReplacementPlugin { + constructor(resourceRegExp, newResource) { + this.resourceRegExp = resourceRegExp; + this.newResource = newResource; + } + + apply(compiler) { + const resourceRegExp = this.resourceRegExp; + const newResource = this.newResource; + compiler.hooks.normalModuleFactory.tap( + "NormalModuleReplacementPlugin", + nmf => { + nmf.hooks.beforeResolve.tap("NormalModuleReplacementPlugin", result => { + if (!result) return; + if (resourceRegExp.test(result.request)) { + if (typeof newResource === "function") { + newResource(result); + } else { + result.request = newResource; + } + } + return result; + }); + nmf.hooks.afterResolve.tap("NormalModuleReplacementPlugin", result => { + if (!result) return; + if (resourceRegExp.test(result.resource)) { + if (typeof newResource === "function") { + newResource(result); + } else { + result.resource = path.resolve( + path.dirname(result.resource), + newResource + ); + } + } + return result; + }); + } + ); + } +} + +module.exports = NormalModuleReplacementPlugin; diff --git a/node_modules/webpack/lib/NullFactory.js b/node_modules/webpack/lib/NullFactory.js new file mode 100644 index 0000000..90ede1f --- /dev/null +++ b/node_modules/webpack/lib/NullFactory.js @@ -0,0 +1,12 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class NullFactory { + create(data, callback) { + return callback(); + } +} +module.exports = NullFactory; diff --git a/node_modules/webpack/lib/OptionsApply.js b/node_modules/webpack/lib/OptionsApply.js new file mode 100644 index 0000000..3b1ec31 --- /dev/null +++ b/node_modules/webpack/lib/OptionsApply.js @@ -0,0 +1,10 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class OptionsApply { + process(options, compiler) {} +} +module.exports = OptionsApply; diff --git a/node_modules/webpack/lib/OptionsDefaulter.js b/node_modules/webpack/lib/OptionsDefaulter.js new file mode 100644 index 0000000..90fc895 --- /dev/null +++ b/node_modules/webpack/lib/OptionsDefaulter.js @@ -0,0 +1,141 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** + * Gets the value at path of object + * @param {object} obj object to query + * @param {string} path query path + * @returns {any} - if {@param path} requests element from array, then `undefined` will be returned + */ +const getProperty = (obj, path) => { + let name = path.split("."); + for (let i = 0; i < name.length - 1; i++) { + obj = obj[name[i]]; + if (typeof obj !== "object" || !obj || Array.isArray(obj)) return; + } + return obj[name.pop()]; +}; + +/** + * Sets the value at path of object. Stops execution, if {@param path} requests element from array to be set + * @param {object} obj object to query + * @param {string} path query path + * @param {any} value value to be set + * @returns {void} + */ +const setProperty = (obj, path, value) => { + let name = path.split("."); + for (let i = 0; i < name.length - 1; i++) { + if (typeof obj[name[i]] !== "object" && obj[name[i]] !== undefined) return; + if (Array.isArray(obj[name[i]])) return; + if (!obj[name[i]]) obj[name[i]] = {}; + obj = obj[name[i]]; + } + obj[name.pop()] = value; +}; + +/** + * @typedef {'call' | 'make' | 'append'} ConfigType + */ +/** + * @typedef {(options: object) => any} MakeConfigHandler + */ +/** + * @typedef {(value: any, options: object) => any} CallConfigHandler + */ +/** + * @typedef {any[]} AppendConfigValues + */ + +class OptionsDefaulter { + constructor() { + /** + * Stores default options settings or functions for computing them + */ + this.defaults = {}; + /** + * Stores configuration for options + * @type {{[key: string]: ConfigType}} + */ + this.config = {}; + } + + /** + * Enhancing {@param options} with default values + * @param {object} options provided options + * @returns {object} - enhanced options + * @throws {Error} - will throw error, if configuration value is other then `undefined` or {@link ConfigType} + */ + process(options) { + options = Object.assign({}, options); + for (let name in this.defaults) { + switch (this.config[name]) { + /** + * If {@link ConfigType} doesn't specified and current value is `undefined`, then default value will be assigned + */ + case undefined: + if (getProperty(options, name) === undefined) { + setProperty(options, name, this.defaults[name]); + } + break; + /** + * Assign result of {@link CallConfigHandler} + */ + case "call": + setProperty( + options, + name, + this.defaults[name].call(this, getProperty(options, name), options) + ); + break; + /** + * Assign result of {@link MakeConfigHandler}, if current value is `undefined` + */ + case "make": + if (getProperty(options, name) === undefined) { + setProperty(options, name, this.defaults[name].call(this, options)); + } + break; + /** + * Adding {@link AppendConfigValues} at the end of the current array + */ + case "append": { + let oldValue = getProperty(options, name); + if (!Array.isArray(oldValue)) { + oldValue = []; + } + oldValue.push(...this.defaults[name]); + setProperty(options, name, oldValue); + break; + } + default: + throw new Error( + "OptionsDefaulter cannot process " + this.config[name] + ); + } + } + return options; + } + + /** + * Builds up default values + * @param {string} name option path + * @param {ConfigType | any} config if {@param def} is provided, then only {@link ConfigType} is allowed + * @param {MakeConfigHandler | CallConfigHandler | AppendConfigValues} [def] defaults + * @returns {void} + */ + set(name, config, def) { + if (def !== undefined) { + this.defaults[name] = def; + this.config[name] = config; + } else { + this.defaults[name] = config; + delete this.config[name]; + } + } +} + +module.exports = OptionsDefaulter; diff --git a/node_modules/webpack/lib/Parser.js b/node_modules/webpack/lib/Parser.js new file mode 100644 index 0000000..b496845 --- /dev/null +++ b/node_modules/webpack/lib/Parser.js @@ -0,0 +1,2454 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API + +const acorn = require("acorn"); +const { Tapable, SyncBailHook, HookMap } = require("tapable"); +const util = require("util"); +const vm = require("vm"); +const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); +const StackedSetMap = require("./util/StackedSetMap"); + +const acornParser = acorn.Parser; + +const joinRanges = (startRange, endRange) => { + if (!endRange) return startRange; + if (!startRange) return endRange; + return [startRange[0], endRange[1]]; +}; + +const defaultParserOptions = { + ranges: true, + locations: true, + ecmaVersion: 11, + sourceType: "module", + 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 Parser extends Tapable { + constructor(options, sourceType = "auto") { + super(); + this.hooks = { + evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])), + evaluate: new HookMap(() => new SyncBailHook(["expression"])), + evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])), + evaluateDefinedIdentifier: new HookMap( + () => new SyncBailHook(["expression"]) + ), + evaluateCallExpressionMember: new HookMap( + () => new SyncBailHook(["expression", "param"]) + ), + statement: new SyncBailHook(["statement"]), + statementIf: new SyncBailHook(["statement"]), + label: new HookMap(() => new SyncBailHook(["statement"])), + import: new SyncBailHook(["statement", "source"]), + importSpecifier: new SyncBailHook([ + "statement", + "source", + "exportName", + "identifierName" + ]), + export: new SyncBailHook(["statement"]), + exportImport: new SyncBailHook(["statement", "source"]), + exportDeclaration: new SyncBailHook(["statement", "declaration"]), + exportExpression: new SyncBailHook(["statement", "declaration"]), + exportSpecifier: new SyncBailHook([ + "statement", + "identifierName", + "exportName", + "index" + ]), + exportImportSpecifier: new SyncBailHook([ + "statement", + "source", + "identifierName", + "exportName", + "index" + ]), + varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])), + varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])), + varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])), + varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])), + canRename: new HookMap(() => new SyncBailHook(["initExpression"])), + rename: new HookMap(() => new SyncBailHook(["initExpression"])), + assigned: new HookMap(() => new SyncBailHook(["expression"])), + assign: new HookMap(() => new SyncBailHook(["expression"])), + typeof: new HookMap(() => new SyncBailHook(["expression"])), + importCall: new SyncBailHook(["expression"]), + call: new HookMap(() => new SyncBailHook(["expression"])), + callAnyMember: new HookMap(() => new SyncBailHook(["expression"])), + new: new HookMap(() => new SyncBailHook(["expression"])), + expression: new HookMap(() => new SyncBailHook(["expression"])), + expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])), + expressionConditionalOperator: new SyncBailHook(["expression"]), + expressionLogicalOperator: new SyncBailHook(["expression"]), + program: new SyncBailHook(["ast", "comments"]) + }; + const HOOK_MAP_COMPAT_CONFIG = { + evaluateTypeof: /^evaluate typeof (.+)$/, + evaluateIdentifier: /^evaluate Identifier (.+)$/, + evaluateDefinedIdentifier: /^evaluate defined Identifier (.+)$/, + evaluateCallExpressionMember: /^evaluate CallExpression .(.+)$/, + evaluate: /^evaluate (.+)$/, + label: /^label (.+)$/, + varDeclarationLet: /^var-let (.+)$/, + varDeclarationConst: /^var-const (.+)$/, + varDeclarationVar: /^var-var (.+)$/, + varDeclaration: /^var (.+)$/, + canRename: /^can-rename (.+)$/, + rename: /^rename (.+)$/, + typeof: /^typeof (.+)$/, + assigned: /^assigned (.+)$/, + assign: /^assign (.+)$/, + callAnyMember: /^call (.+)\.\*$/, + call: /^call (.+)$/, + new: /^new (.+)$/, + expressionConditionalOperator: /^expression \?:$/, + expressionAnyMember: /^expression (.+)\.\*$/, + expression: /^expression (.+)$/ + }; + this._pluginCompat.tap("Parser", options => { + for (const name of Object.keys(HOOK_MAP_COMPAT_CONFIG)) { + const regexp = HOOK_MAP_COMPAT_CONFIG[name]; + const match = regexp.exec(options.name); + if (match) { + if (match[1]) { + this.hooks[name].tap( + match[1], + options.fn.name || "unnamed compat plugin", + options.fn.bind(this) + ); + } else { + this.hooks[name].tap( + options.fn.name || "unnamed compat plugin", + options.fn.bind(this) + ); + } + return true; + } + } + }); + this.options = options; + this.sourceType = sourceType; + this.scope = undefined; + this.state = undefined; + this.comments = undefined; + this.initializeEvaluating(); + } + + initializeEvaluating() { + this.hooks.evaluate.for("Literal").tap("Parser", expr => { + switch (typeof expr.value) { + case "number": + return new BasicEvaluatedExpression() + .setNumber(expr.value) + .setRange(expr.range); + case "string": + return new BasicEvaluatedExpression() + .setString(expr.value) + .setRange(expr.range); + case "boolean": + return new BasicEvaluatedExpression() + .setBoolean(expr.value) + .setRange(expr.range); + } + if (expr.value === null) { + return new BasicEvaluatedExpression().setNull().setRange(expr.range); + } + if (expr.value instanceof RegExp) { + return new BasicEvaluatedExpression() + .setRegExp(expr.value) + .setRange(expr.range); + } + }); + this.hooks.evaluate.for("LogicalExpression").tap("Parser", expr => { + let left; + let leftAsBool; + let right; + if (expr.operator === "&&") { + left = this.evaluateExpression(expr.left); + leftAsBool = left && left.asBool(); + if (leftAsBool === false) return left.setRange(expr.range); + if (leftAsBool !== true) return; + right = this.evaluateExpression(expr.right); + return right.setRange(expr.range); + } else if (expr.operator === "||") { + left = this.evaluateExpression(expr.left); + leftAsBool = left && left.asBool(); + if (leftAsBool === true) return left.setRange(expr.range); + if (leftAsBool !== false) return; + right = this.evaluateExpression(expr.right); + return right.setRange(expr.range); + } + }); + this.hooks.evaluate.for("BinaryExpression").tap("Parser", expr => { + let left; + let right; + let res; + if (expr.operator === "+") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + 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.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; + } + } + res.setRange(expr.range); + return res; + } else if (expr.operator === "-") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number - right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "*") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number * right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "/") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number / right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "**") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(Math.pow(left.number, right.number)); + res.setRange(expr.range); + return res; + } else if (expr.operator === "==" || expr.operator === "===") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + res = new BasicEvaluatedExpression(); + res.setRange(expr.range); + if (left.isString() && right.isString()) { + return res.setBoolean(left.string === right.string); + } else if (left.isNumber() && right.isNumber()) { + return res.setBoolean(left.number === right.number); + } else if (left.isBoolean() && right.isBoolean()) { + return res.setBoolean(left.bool === right.bool); + } + } else if (expr.operator === "!=" || expr.operator === "!==") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + res = new BasicEvaluatedExpression(); + res.setRange(expr.range); + if (left.isString() && right.isString()) { + return res.setBoolean(left.string !== right.string); + } else if (left.isNumber() && right.isNumber()) { + return res.setBoolean(left.number !== right.number); + } else if (left.isBoolean() && right.isBoolean()) { + return res.setBoolean(left.bool !== right.bool); + } + } else if (expr.operator === "&") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number & right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "|") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number | right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "^") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number ^ right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === ">>>") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number >>> right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === ">>") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number >> right.number); + res.setRange(expr.range); + return res; + } else if (expr.operator === "<<") { + left = this.evaluateExpression(expr.left); + right = this.evaluateExpression(expr.right); + if (!left || !right) return; + if (!left.isNumber() || !right.isNumber()) return; + res = new BasicEvaluatedExpression(); + res.setNumber(left.number << right.number); + res.setRange(expr.range); + return res; + } + }); + this.hooks.evaluate.for("UnaryExpression").tap("Parser", expr => { + if (expr.operator === "typeof") { + let res; + let name; + if (expr.argument.type === "Identifier") { + name = + this.scope.renames.get(expr.argument.name) || expr.argument.name; + if (!this.scope.definitions.has(name)) { + const hook = this.hooks.evaluateTypeof.get(name); + if (hook !== undefined) { + res = hook.call(expr); + if (res !== undefined) return res; + } + } + } + if (expr.argument.type === "MemberExpression") { + const exprName = this.getNameForExpression(expr.argument); + if (exprName && exprName.free) { + const hook = this.hooks.evaluateTypeof.get(exprName.name); + if (hook !== undefined) { + res = hook.call(expr); + if (res !== undefined) return res; + } + } + } + if (expr.argument.type === "FunctionExpression") { + return new BasicEvaluatedExpression() + .setString("function") + .setRange(expr.range); + } + const arg = this.evaluateExpression(expr.argument); + if (arg.isString() || arg.isWrapped()) { + return new BasicEvaluatedExpression() + .setString("string") + .setRange(expr.range); + } + if (arg.isNumber()) { + return new BasicEvaluatedExpression() + .setString("number") + .setRange(expr.range); + } + if (arg.isBoolean()) { + return new BasicEvaluatedExpression() + .setString("boolean") + .setRange(expr.range); + } + if (arg.isArray() || arg.isConstArray() || arg.isRegExp()) { + return new BasicEvaluatedExpression() + .setString("object") + .setRange(expr.range); + } + } else if (expr.operator === "!") { + const argument = this.evaluateExpression(expr.argument); + if (!argument) return; + if (argument.isBoolean()) { + return new BasicEvaluatedExpression() + .setBoolean(!argument.bool) + .setRange(expr.range); + } + if (argument.isTruthy()) { + return new BasicEvaluatedExpression() + .setBoolean(false) + .setRange(expr.range); + } + if (argument.isFalsy()) { + return new BasicEvaluatedExpression() + .setBoolean(true) + .setRange(expr.range); + } + if (argument.isString()) { + return new BasicEvaluatedExpression() + .setBoolean(!argument.string) + .setRange(expr.range); + } + if (argument.isNumber()) { + return new BasicEvaluatedExpression() + .setBoolean(!argument.number) + .setRange(expr.range); + } + } else if (expr.operator === "~") { + const argument = this.evaluateExpression(expr.argument); + if (!argument) return; + if (!argument.isNumber()) return; + const res = new BasicEvaluatedExpression(); + res.setNumber(~argument.number); + res.setRange(expr.range); + return res; + } + }); + this.hooks.evaluateTypeof.for("undefined").tap("Parser", expr => { + return new BasicEvaluatedExpression() + .setString("undefined") + .setRange(expr.range); + }); + this.hooks.evaluate.for("Identifier").tap("Parser", expr => { + const name = this.scope.renames.get(expr.name) || expr.name; + if (!this.scope.definitions.has(expr.name)) { + const hook = this.hooks.evaluateIdentifier.get(name); + if (hook !== undefined) { + const result = hook.call(expr); + if (result) return result; + } + return new BasicEvaluatedExpression() + .setIdentifier(name) + .setRange(expr.range); + } else { + const hook = this.hooks.evaluateDefinedIdentifier.get(name); + if (hook !== undefined) { + return hook.call(expr); + } + } + }); + this.hooks.evaluate.for("ThisExpression").tap("Parser", expr => { + const name = this.scope.renames.get("this"); + if (name) { + const hook = this.hooks.evaluateIdentifier.get(name); + if (hook !== undefined) { + const result = hook.call(expr); + if (result) return result; + } + return new BasicEvaluatedExpression() + .setIdentifier(name) + .setRange(expr.range); + } + }); + this.hooks.evaluate.for("MemberExpression").tap("Parser", expression => { + let exprName = this.getNameForExpression(expression); + if (exprName) { + if (exprName.free) { + const hook = this.hooks.evaluateIdentifier.get(exprName.name); + if (hook !== undefined) { + const result = hook.call(expression); + if (result) return result; + } + return new BasicEvaluatedExpression() + .setIdentifier(exprName.name) + .setRange(expression.range); + } else { + const hook = this.hooks.evaluateDefinedIdentifier.get(exprName.name); + if (hook !== undefined) { + return hook.call(expression); + } + } + } + }); + this.hooks.evaluate.for("CallExpression").tap("Parser", expr => { + if (expr.callee.type !== "MemberExpression") return; + if ( + expr.callee.property.type !== + (expr.callee.computed ? "Literal" : "Identifier") + ) + return; + const param = this.evaluateExpression(expr.callee.object); + if (!param) return; + const property = expr.callee.property.name || expr.callee.property.value; + const hook = this.hooks.evaluateCallExpressionMember.get(property); + if (hook !== undefined) { + return hook.call(expr, param); + } + }); + this.hooks.evaluateCallExpressionMember + .for("replace") + .tap("Parser", (expr, param) => { + if (!param.isString()) return; + if (expr.arguments.length !== 2) return; + let arg1 = this.evaluateExpression(expr.arguments[0]); + let arg2 = this.evaluateExpression(expr.arguments[1]); + if (!arg1.isString() && !arg1.isRegExp()) return; + arg1 = arg1.regExp || arg1.string; + if (!arg2.isString()) return; + arg2 = arg2.string; + return new BasicEvaluatedExpression() + .setString(param.string.replace(arg1, arg2)) + .setRange(expr.range); + }); + ["substr", "substring"].forEach(fn => { + this.hooks.evaluateCallExpressionMember + .for(fn) + .tap("Parser", (expr, param) => { + if (!param.isString()) return; + let arg1; + let result, + str = param.string; + switch (expr.arguments.length) { + case 1: + arg1 = this.evaluateExpression(expr.arguments[0]); + if (!arg1.isNumber()) return; + result = str[fn](arg1.number); + break; + case 2: { + 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) + .setRange(expr.range); + }); + }); + + /** + * @param {string} kind "cooked" | "raw" + * @param {TODO} templateLiteralExpr TemplateLiteral expr + * @returns {{quasis: BasicEvaluatedExpression[], parts: BasicEvaluatedExpression[]}} Simplified template + */ + const getSimplifiedTemplateResult = (kind, templateLiteralExpr) => { + const quasis = []; + 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") { + // 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(quasiExpr.range) + .setExpression(quasiExpr); + quasis.push(part); + parts.push(part); + } + return { + quasis, + parts + }; + }; + + this.hooks.evaluate.for("TemplateLiteral").tap("Parser", node => { + const { quasis, parts } = getSimplifiedTemplateResult("cooked", node); + if (parts.length === 1) { + return parts[0].setRange(node.range); + } + return new BasicEvaluatedExpression() + .setTemplateString(quasis, parts, "cooked") + .setRange(node.range); + }); + this.hooks.evaluate.for("TaggedTemplateExpression").tap("Parser", node => { + if (this.evaluateExpression(node.tag).identifier !== "String.raw") return; + const { quasis, parts } = getSimplifiedTemplateResult("raw", node.quasi); + if (parts.length === 1) { + return parts[0].setRange(node.range); + } + return new BasicEvaluatedExpression() + .setTemplateString(quasis, parts, "raw") + .setRange(node.range); + }); + + this.hooks.evaluateCallExpressionMember + .for("concat") + .tap("Parser", (expr, param) => { + if (!param.isString() && !param.isWrapped()) return; + + let stringSuffix = null; + let hasUnknownParams = false; + for (let i = expr.arguments.length - 1; i >= 0; i--) { + const argExpr = this.evaluateExpression(expr.arguments[i]); + if (!argExpr.isString() && !argExpr.isNumber()) { + hasUnknownParams = true; + break; + } + + const value = argExpr.isString() + ? argExpr.string + : "" + argExpr.number; + + const newString = value + (stringSuffix ? stringSuffix.string : ""); + const newRange = [ + argExpr.range[0], + (stringSuffix || argExpr).range[1] + ]; + stringSuffix = new BasicEvaluatedExpression() + .setString(newString) + .setRange(newRange); + } + + if (hasUnknownParams) { + const prefix = param.isString() ? param : param.prefix; + return new BasicEvaluatedExpression() + .setWrapped(prefix, stringSuffix) + .setRange(expr.range); + } else if (param.isWrapped()) { + const postfix = stringSuffix || param.postfix; + return new BasicEvaluatedExpression() + .setWrapped(param.prefix, postfix) + .setRange(expr.range); + } else { + const newString = + param.string + (stringSuffix ? stringSuffix.string : ""); + return new BasicEvaluatedExpression() + .setString(newString) + .setRange(expr.range); + } + }); + this.hooks.evaluateCallExpressionMember + .for("split") + .tap("Parser", (expr, param) => { + if (!param.isString()) return; + if (expr.arguments.length !== 1) 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) + .setRange(expr.range); + }); + this.hooks.evaluate.for("ConditionalExpression").tap("Parser", 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); + if (!consequent || !alternate) return; + res = new BasicEvaluatedExpression(); + if (consequent.isConditional()) { + res.setOptions(consequent.options); + } else { + res.setOptions([consequent]); + } + if (alternate.isConditional()) { + res.addOptions(alternate.options); + } else { + res.addOptions([alternate]); + } + } else { + res = this.evaluateExpression( + conditionValue ? expr.consequent : expr.alternate + ); + } + res.setRange(expr.range); + return res; + }); + this.hooks.evaluate.for("ArrayExpression").tap("Parser", expr => { + const items = expr.elements.map(element => { + return element !== null && this.evaluateExpression(element); + }); + if (!items.every(Boolean)) return; + return new BasicEvaluatedExpression() + .setItems(items) + .setRange(expr.range); + }); + } + + getRenameIdentifier(expr) { + const result = this.evaluateExpression(expr); + if (result && result.isIdentifier()) { + return result.identifier; + } + } + + walkClass(classy) { + if (classy.superClass) this.walkExpression(classy.superClass); + if (classy.body && classy.body.type === "ClassBody") { + const wasTopLevel = this.scope.topLevelScope; + this.scope.topLevelScope = false; + for (const methodDefinition of classy.body.body) { + if (methodDefinition.type === "MethodDefinition") { + this.walkMethodDefinition(methodDefinition); + } + } + this.scope.topLevelScope = wasTopLevel; + } + } + + walkMethodDefinition(methodDefinition) { + if (methodDefinition.computed && methodDefinition.key) { + this.walkExpression(methodDefinition.key); + } + if (methodDefinition.value) { + this.walkExpression(methodDefinition.value); + } + } + + // Prewalking iterates the scope for variable declarations + prewalkStatements(statements) { + for (let index = 0, len = statements.length; index < len; index++) { + const statement = statements[index]; + this.prewalkStatement(statement); + } + } + + // Block-Prewalking iterates the scope for block variable declarations + 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 + walkStatements(statements) { + for (let index = 0, len = statements.length; index < len; index++) { + const statement = statements[index]; + this.walkStatement(statement); + } + } + + prewalkStatement(statement) { + switch (statement.type) { + case "BlockStatement": + this.prewalkBlockStatement(statement); + break; + case "DoWhileStatement": + this.prewalkDoWhileStatement(statement); + break; + case "ExportAllDeclaration": + this.prewalkExportAllDeclaration(statement); + break; + case "ExportDefaultDeclaration": + this.prewalkExportDefaultDeclaration(statement); + break; + case "ExportNamedDeclaration": + this.prewalkExportNamedDeclaration(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 "ImportDeclaration": + this.prewalkImportDeclaration(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; + } + } + + blockPrewalkStatement(statement) { + switch (statement.type) { + case "VariableDeclaration": + this.blockPrewalkVariableDeclaration(statement); + break; + case "ExportDefaultDeclaration": + this.blockPrewalkExportDefaultDeclaration(statement); + break; + case "ExportNamedDeclaration": + this.blockPrewalkExportNamedDeclaration(statement); + break; + case "ClassDeclaration": + this.blockPrewalkClassDeclaration(statement); + break; + } + } + + walkStatement(statement) { + if (this.hooks.statement.call(statement) !== undefined) 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; + } + } + + // Real Statements + prewalkBlockStatement(statement) { + this.prewalkStatements(statement.body); + } + + walkBlockStatement(statement) { + this.inBlockScope(() => { + const body = statement.body; + this.blockPrewalkStatements(body); + this.walkStatements(body); + }); + } + + walkExpressionStatement(statement) { + this.walkExpression(statement.expression); + } + + prewalkIfStatement(statement) { + this.prewalkStatement(statement.consequent); + if (statement.alternate) { + this.prewalkStatement(statement.alternate); + } + } + + walkIfStatement(statement) { + const result = this.hooks.statementIf.call(statement); + if (result === undefined) { + this.walkExpression(statement.test); + this.walkStatement(statement.consequent); + if (statement.alternate) { + this.walkStatement(statement.alternate); + } + } else { + if (result) { + this.walkStatement(statement.consequent); + } else if (statement.alternate) { + this.walkStatement(statement.alternate); + } + } + } + + prewalkLabeledStatement(statement) { + this.prewalkStatement(statement.body); + } + + walkLabeledStatement(statement) { + const hook = this.hooks.label.get(statement.label.name); + if (hook !== undefined) { + const result = hook.call(statement); + if (result === true) return; + } + this.walkStatement(statement.body); + } + + prewalkWithStatement(statement) { + this.prewalkStatement(statement.body); + } + + walkWithStatement(statement) { + this.walkExpression(statement.object); + this.walkStatement(statement.body); + } + + prewalkSwitchStatement(statement) { + this.prewalkSwitchCases(statement.cases); + } + + walkSwitchStatement(statement) { + this.walkExpression(statement.discriminant); + this.walkSwitchCases(statement.cases); + } + + walkTerminatingStatement(statement) { + if (statement.argument) this.walkExpression(statement.argument); + } + + walkReturnStatement(statement) { + this.walkTerminatingStatement(statement); + } + + walkThrowStatement(statement) { + this.walkTerminatingStatement(statement); + } + + prewalkTryStatement(statement) { + this.prewalkStatement(statement.block); + } + + 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); + } + + prewalkWhileStatement(statement) { + this.prewalkStatement(statement.body); + } + + walkWhileStatement(statement) { + this.walkExpression(statement.test); + this.walkStatement(statement.body); + } + + prewalkDoWhileStatement(statement) { + this.prewalkStatement(statement.body); + } + + walkDoWhileStatement(statement) { + this.walkStatement(statement.body); + this.walkExpression(statement.test); + } + + prewalkForStatement(statement) { + if (statement.init) { + if (statement.init.type === "VariableDeclaration") { + this.prewalkStatement(statement.init); + } + } + this.prewalkStatement(statement.body); + } + + walkForStatement(statement) { + this.inBlockScope(() => { + if (statement.init) { + if (statement.init.type === "VariableDeclaration") { + this.blockPrewalkVariableDeclaration(statement.init); + 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 + this.blockPrewalkStatements(body.body); + this.walkStatements(body.body); + } else { + this.walkStatement(body); + } + }); + } + + prewalkForInStatement(statement) { + if (statement.left.type === "VariableDeclaration") { + this.prewalkVariableDeclaration(statement.left); + } + this.prewalkStatement(statement.body); + } + + 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 + this.blockPrewalkStatements(body.body); + this.walkStatements(body.body); + } else { + this.walkStatement(body); + } + }); + } + + prewalkForOfStatement(statement) { + if (statement.left.type === "VariableDeclaration") { + this.prewalkVariableDeclaration(statement.left); + } + this.prewalkStatement(statement.body); + } + + 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 + this.blockPrewalkStatements(body.body); + this.walkStatements(body.body); + } else { + this.walkStatement(body); + } + }); + } + + // Declarations + prewalkFunctionDeclaration(statement) { + if (statement.id) { + this.scope.renames.set(statement.id.name, null); + this.scope.definitions.add(statement.id.name); + } + } + + 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); + this.prewalkStatement(statement.body); + this.walkStatement(statement.body); + } else { + this.walkExpression(statement.body); + } + }); + this.scope.topLevelScope = wasTopLevel; + } + + prewalkImportDeclaration(statement) { + const source = statement.source.value; + this.hooks.import.call(statement, source); + for (const specifier of statement.specifiers) { + const name = specifier.local.name; + this.scope.renames.set(name, null); + this.scope.definitions.add(name); + switch (specifier.type) { + case "ImportDefaultSpecifier": + this.hooks.importSpecifier.call(statement, source, "default", name); + break; + case "ImportSpecifier": + this.hooks.importSpecifier.call( + statement, + source, + specifier.imported.name, + name + ); + break; + case "ImportNamespaceSpecifier": + this.hooks.importSpecifier.call(statement, source, null, name); + break; + } + } + } + + 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) { + if (statement.declaration) { + this.blockPrewalkStatement(statement.declaration); + } + } + + prewalkExportNamedDeclaration(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) + ) { + this.prewalkStatement(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; + 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; + } + } + } + } + } + + walkExportNamedDeclaration(statement) { + if (statement.declaration) { + this.walkStatement(statement.declaration); + } + } + + blockPrewalkExportDefaultDeclaration(statement) { + if (statement.declaration.type === "ClassDeclaration") { + this.blockPrewalkClassDeclaration(statement.declaration); + } + } + + prewalkExportDefaultDeclaration(statement) { + this.prewalkStatement(statement.declaration); + if ( + statement.declaration.id && + statement.declaration.type !== "FunctionExpression" && + statement.declaration.type !== "ClassExpression" + ) { + this.hooks.exportSpecifier.call( + statement, + statement.declaration.id.name, + "default" + ); + } + } + + 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") { + this.walkFunctionDeclaration(statement.declaration); + } else if (statement.declaration.type === "ClassDeclaration") { + this.walkClassDeclaration(statement.declaration); + } else { + this.walkExpression(statement.declaration); + } + if (!this.hooks.exportExpression.call(statement, statement.declaration)) { + this.hooks.exportSpecifier.call( + statement, + statement.declaration, + "default" + ); + } + } + } + + prewalkExportAllDeclaration(statement) { + const source = statement.source.value; + this.hooks.exportImport.call(statement, source); + this.hooks.exportImportSpecifier.call(statement, source, null, null, 0); + } + + prewalkVariableDeclaration(statement) { + if (statement.kind !== "var") return; + this._prewalkVariableDeclaration(statement, this.hooks.varDeclarationVar); + } + + blockPrewalkVariableDeclaration(statement) { + if (statement.kind === "var") return; + const hookMap = + statement.kind === "const" + ? this.hooks.varDeclarationConst + : this.hooks.varDeclarationLet; + this._prewalkVariableDeclaration(statement, hookMap); + } + + _prewalkVariableDeclaration(statement, hookMap) { + for (const declarator of statement.declarations) { + switch (declarator.type) { + case "VariableDeclarator": { + 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.scope.renames.set(name, null); + this.scope.definitions.add(name); + } + } + }); + break; + } + } + } + } + + 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.scope.renames.set( + declarator.id.name, + this.scope.renames.get(renameIdentifier) || renameIdentifier + ); + this.scope.definitions.delete(declarator.id.name); + } + break; + } + } + this.walkPattern(declarator.id); + if (declarator.init) this.walkExpression(declarator.init); + break; + } + } + } + } + + blockPrewalkClassDeclaration(statement) { + if (statement.id) { + this.scope.renames.set(statement.id.name, null); + this.scope.definitions.add(statement.id.name); + } + } + + walkClassDeclaration(statement) { + this.walkClass(statement); + } + + prewalkSwitchCases(switchCases) { + for (let index = 0, len = switchCases.length; index < len; index++) { + const switchCase = switchCases[index]; + this.prewalkStatements(switchCase.consequent); + } + } + + walkSwitchCases(switchCases) { + for (let index = 0, len = switchCases.length; index < len; index++) { + const switchCase = switchCases[index]; + + if (switchCase.test) { + this.walkExpression(switchCase.test); + } + this.walkStatements(switchCase.consequent); + } + } + + walkCatchClause(catchClause) { + this.inBlockScope(() => { + // Error binding is optional in catch clause since ECMAScript 2019 + if (catchClause.param !== null) { + this.enterPattern(catchClause.param, ident => { + this.scope.renames.set(ident, null); + this.scope.definitions.add(ident); + }); + this.walkPattern(catchClause.param); + } + this.prewalkStatement(catchClause.body); + this.walkStatement(catchClause.body); + }); + } + + 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; + } + } + + 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); + } + } + } + + walkArrayPattern(pattern) { + for (let i = 0, len = pattern.elements.length; i < len; i++) { + const element = pattern.elements[i]; + if (element) this.walkPattern(element); + } + } + + walkRestElement(pattern) { + this.walkPattern(pattern.argument); + } + + walkExpressions(expressions) { + for (const expression of expressions) { + if (expression) { + this.walkExpression(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 "ClassExpression": + this.walkClassExpression(expression); + break; + case "ConditionalExpression": + this.walkConditionalExpression(expression); + break; + case "FunctionExpression": + this.walkFunctionExpression(expression); + break; + case "Identifier": + this.walkIdentifier(expression); + break; + case "LogicalExpression": + this.walkLogicalExpression(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; + } + } + + walkAwaitExpression(expression) { + this.walkExpression(expression.argument); + } + + walkArrayExpression(expression) { + if (expression.elements) { + this.walkExpressions(expression.elements); + } + } + + walkSpreadElement(expression) { + if (expression.argument) { + this.walkExpression(expression.argument); + } + } + + walkObjectExpression(expression) { + for ( + let propIndex = 0, len = expression.properties.length; + propIndex < len; + propIndex++ + ) { + const prop = expression.properties[propIndex]; + if (prop.type === "SpreadElement") { + this.walkExpression(prop.argument); + continue; + } + if (prop.computed) { + this.walkExpression(prop.key); + } + if (prop.shorthand) { + this.scope.inShorthand = true; + } + this.walkExpression(prop.value); + if (prop.shorthand) { + this.scope.inShorthand = false; + } + } + } + + 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.name); + } + + this.inFunctionScope(true, scopeParams, () => { + for (const param of expression.params) { + this.walkPattern(param); + } + if (expression.body.type === "BlockStatement") { + this.detectMode(expression.body.body); + this.prewalkStatement(expression.body); + this.walkStatement(expression.body); + } else { + this.walkExpression(expression.body); + } + }); + this.scope.topLevelScope = wasTopLevel; + } + + walkArrowFunctionExpression(expression) { + this.inFunctionScope(false, expression.params, () => { + for (const param of expression.params) { + this.walkPattern(param); + } + if (expression.body.type === "BlockStatement") { + this.detectMode(expression.body.body); + this.prewalkStatement(expression.body); + this.walkStatement(expression.body); + } else { + this.walkExpression(expression.body); + } + }); + } + + walkSequenceExpression(expression) { + if (expression.expressions) this.walkExpressions(expression.expressions); + } + + walkUpdateExpression(expression) { + this.walkExpression(expression.argument); + } + + walkUnaryExpression(expression) { + if (expression.operator === "typeof") { + const exprName = this.getNameForExpression(expression.argument); + if (exprName && exprName.free) { + const hook = this.hooks.typeof.get(exprName.name); + if (hook !== undefined) { + const result = hook.call(expression); + if (result === true) return; + } + } + } + this.walkExpression(expression.argument); + } + + walkLeftRightExpression(expression) { + this.walkExpression(expression.left); + this.walkExpression(expression.right); + } + + walkBinaryExpression(expression) { + this.walkLeftRightExpression(expression); + } + + walkLogicalExpression(expression) { + const result = this.hooks.expressionLogicalOperator.call(expression); + if (result === undefined) { + this.walkLeftRightExpression(expression); + } else { + if (result) { + this.walkExpression(expression.right); + } + } + } + + walkAssignmentExpression(expression) { + const renameIdentifier = this.getRenameIdentifier(expression.right); + if (expression.left.type === "Identifier" && renameIdentifier) { + const hook = this.hooks.canRename.get(renameIdentifier); + if (hook !== undefined && hook.call(expression.right)) { + // renaming "a = b;" + const hook = this.hooks.rename.get(renameIdentifier); + if (hook === undefined || !hook.call(expression.right)) { + this.scope.renames.set(expression.left.name, renameIdentifier); + this.scope.definitions.delete(expression.left.name); + } + return; + } + } + if (expression.left.type === "Identifier") { + const assignedHook = this.hooks.assigned.get(expression.left.name); + if (assignedHook === undefined || !assignedHook.call(expression)) { + this.walkExpression(expression.right); + } + this.scope.renames.set(expression.left.name, null); + const assignHook = this.hooks.assign.get(expression.left.name); + if (assignHook === undefined || !assignHook.call(expression)) { + this.walkExpression(expression.left); + } + return; + } + this.walkExpression(expression.right); + this.walkPattern(expression.left); + this.enterPattern(expression.left, (name, decl) => { + this.scope.renames.set(name, null); + }); + } + + 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); + } + } + } + + walkNewExpression(expression) { + const callee = this.evaluateExpression(expression.callee); + if (callee.isIdentifier()) { + const hook = this.hooks.new.get(callee.identifier); + if (hook !== undefined) { + const result = hook.call(expression); + if (result === true) { + return; + } + } + } + + this.walkExpression(expression.callee); + if (expression.arguments) { + this.walkExpressions(expression.arguments); + } + } + + walkYieldExpression(expression) { + if (expression.argument) { + this.walkExpression(expression.argument); + } + } + + walkTemplateLiteral(expression) { + if (expression.expressions) { + this.walkExpressions(expression.expressions); + } + } + + walkTaggedTemplateExpression(expression) { + if (expression.tag) { + this.walkExpression(expression.tag); + } + if (expression.quasi && expression.quasi.expressions) { + this.walkExpressions(expression.quasi.expressions); + } + } + + walkClassExpression(expression) { + this.walkClass(expression); + } + + _walkIIFE(functionExpression, options, currentThis) { + const renameArgOrThis = argOrThis => { + const renameIdentifier = this.getRenameIdentifier(argOrThis); + if (renameIdentifier) { + const hook = this.hooks.canRename.get(renameIdentifier); + if (hook !== undefined && hook.call(argOrThis)) { + const hook = this.hooks.rename.get(renameIdentifier); + if (hook === undefined || !hook.call(argOrThis)) { + return renameIdentifier; + } + } + } + this.walkExpression(argOrThis); + }; + const params = functionExpression.params; + const renameThis = currentThis ? renameArgOrThis(currentThis) : null; + const args = options.map(renameArgOrThis); + const wasTopLevel = this.scope.topLevelScope; + this.scope.topLevelScope = false; + const scopeParams = params.filter((identifier, idx) => !args[idx]); + + // Add function name in scope for recursive calls + if (functionExpression.id) { + scopeParams.push(functionExpression.id.name); + } + + this.inFunctionScope(true, scopeParams, () => { + if (renameThis) { + this.scope.renames.set("this", renameThis); + } + for (let i = 0; i < args.length; i++) { + const param = args[i]; + if (!param) continue; + if (!params[i] || params[i].type !== "Identifier") continue; + this.scope.renames.set(params[i].name, param); + } + if (functionExpression.body.type === "BlockStatement") { + this.detectMode(functionExpression.body.body); + this.prewalkStatement(functionExpression.body); + this.walkStatement(functionExpression.body); + } else { + this.walkExpression(functionExpression.body); + } + }); + this.scope.topLevelScope = wasTopLevel; + } + + walkCallExpression(expression) { + if ( + expression.callee.type === "MemberExpression" && + expression.callee.object.type === "FunctionExpression" && + !expression.callee.computed && + (expression.callee.property.name === "call" || + expression.callee.property.name === "bind") && + expression.arguments.length > 0 + ) { + // (function(…) { }.call/bind(?, …)) + this._walkIIFE( + expression.callee.object, + expression.arguments.slice(1), + expression.arguments[0] + ); + } else if (expression.callee.type === "FunctionExpression") { + // (function(…) { }(…)) + this._walkIIFE(expression.callee, expression.arguments, null); + } else if (expression.callee.type === "Import") { + let result = this.hooks.importCall.call(expression); + if (result === true) return; + + if (expression.arguments) this.walkExpressions(expression.arguments); + } else { + const callee = this.evaluateExpression(expression.callee); + if (callee.isIdentifier()) { + const callHook = this.hooks.call.get(callee.identifier); + if (callHook !== undefined) { + let result = callHook.call(expression); + if (result === true) return; + } + let identifier = callee.identifier.replace(/\.[^.]+$/, ""); + if (identifier !== callee.identifier) { + const callAnyHook = this.hooks.callAnyMember.get(identifier); + if (callAnyHook !== undefined) { + let result = callAnyHook.call(expression); + if (result === true) return; + } + } + } + + if (expression.callee) this.walkExpression(expression.callee); + if (expression.arguments) this.walkExpressions(expression.arguments); + } + } + + walkMemberExpression(expression) { + const exprName = this.getNameForExpression(expression); + if (exprName && exprName.free) { + const expressionHook = this.hooks.expression.get(exprName.name); + if (expressionHook !== undefined) { + const result = expressionHook.call(expression); + if (result === true) return; + } + const expressionAnyMemberHook = this.hooks.expressionAnyMember.get( + exprName.nameGeneral + ); + if (expressionAnyMemberHook !== undefined) { + const result = expressionAnyMemberHook.call(expression); + if (result === true) return; + } + } + this.walkExpression(expression.object); + if (expression.computed === true) this.walkExpression(expression.property); + } + + walkThisExpression(expression) { + const expressionHook = this.hooks.expression.get("this"); + if (expressionHook !== undefined) { + expressionHook.call(expression); + } + } + + walkIdentifier(expression) { + if (!this.scope.definitions.has(expression.name)) { + const hook = this.hooks.expression.get( + this.scope.renames.get(expression.name) || expression.name + ); + if (hook !== undefined) { + const result = hook.call(expression); + if (result === true) return; + } + } + } + + /** + * @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, + isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, + definitions: oldScope.definitions.createChild(), + renames: oldScope.renames.createChild() + }; + + this.scope.renames.set("this", null); + + this.enterPatterns(params, ident => { + this.scope.renames.set(ident, null); + this.scope.definitions.add(ident); + }); + + fn(); + + this.scope = oldScope; + } + + inFunctionScope(hasThis, params, fn) { + const oldScope = this.scope; + this.scope = { + topLevelScope: oldScope.topLevelScope, + inTry: false, + inShorthand: false, + isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, + definitions: oldScope.definitions.createChild(), + renames: oldScope.renames.createChild() + }; + + if (hasThis) { + this.scope.renames.set("this", null); + } + + this.enterPatterns(params, ident => { + this.scope.renames.set(ident, null); + this.scope.definitions.add(ident); + }); + + fn(); + + this.scope = oldScope; + } + + inBlockScope(fn) { + const oldScope = this.scope; + this.scope = { + topLevelScope: oldScope.topLevelScope, + inTry: oldScope.inTry, + inShorthand: false, + isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, + definitions: oldScope.definitions.createChild(), + renames: oldScope.renames.createChild() + }; + + fn(); + + this.scope = oldScope; + } + + // TODO webpack 5: remove this methods + // only for backward-compat + detectStrictMode(statements) { + this.detectMode(statements); + } + + detectMode(statements) { + const isLiteral = + statements.length >= 1 && + statements[0].type === "ExpressionStatement" && + statements[0].expression.type === "Literal"; + if (isLiteral && statements[0].expression.value === "use strict") { + this.scope.isStrict = true; + } + if (isLiteral && 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": + this.enterPattern(pattern.value, onIdent); + break; + } + } + + enterIdentifier(pattern, onIdent) { + onIdent(pattern.name, pattern); + } + + enterObjectPattern(pattern, onIdent) { + for ( + let propIndex = 0, len = pattern.properties.length; + propIndex < len; + propIndex++ + ) { + const prop = pattern.properties[propIndex]; + this.enterPattern(prop, onIdent); + } + } + + enterArrayPattern(pattern, onIdent) { + for ( + let elementIndex = 0, len = pattern.elements.length; + elementIndex < len; + elementIndex++ + ) { + const element = pattern.elements[elementIndex]; + this.enterPattern(element, onIdent); + } + } + + enterRestElement(pattern, onIdent) { + this.enterPattern(pattern.argument, onIdent); + } + + enterAssignmentPattern(pattern, onIdent) { + this.enterPattern(pattern.left, onIdent); + } + + evaluateExpression(expression) { + try { + const hook = this.hooks.evaluate.get(expression.type); + if (hook !== undefined) { + const result = hook.call(expression); + if (result !== undefined) { + if (result) { + result.setExpression(expression); + } + return result; + } + } + } catch (e) { + console.warn(e); + // ignore error + } + return new BasicEvaluatedExpression() + .setRange(expression.range) + .setExpression(expression); + } + + 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 + }; + } + + parse(source, initialState) { + let ast; + let comments; + if (typeof source === "object" && source !== null) { + ast = source; + comments = source.comments; + } else { + comments = []; + ast = Parser.parse(source, { + sourceType: this.sourceType, + onComment: comments + }); + } + + const oldScope = this.scope; + const oldState = this.state; + const oldComments = this.comments; + this.scope = { + topLevelScope: true, + inTry: false, + inShorthand: false, + isStrict: false, + isAsmJs: false, + definitions: new StackedSetMap(), + renames: new StackedSetMap() + }; + const state = (this.state = initialState || {}); + this.comments = comments; + if (this.hooks.program.call(ast, comments) === undefined) { + this.detectMode(ast.body); + this.prewalkStatements(ast.body); + this.blockPrewalkStatements(ast.body); + this.walkStatements(ast.body); + } + this.scope = oldScope; + this.state = oldState; + this.comments = oldComments; + return state; + } + + evaluate(source) { + const ast = Parser.parse("(" + source + ")", { + sourceType: this.sourceType, + locations: false + }); + // TODO(https://github.com/acornjs/acorn/issues/741) + // @ts-ignore + if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") { + throw new Error("evaluate: Source is not a expression"); + } + // TODO(https://github.com/acornjs/acorn/issues/741) + // @ts-ignore + return this.evaluateExpression(ast.body[0].expression); + } + + getComments(range) { + return this.comments.filter( + comment => comment.range[0] >= range[0] && comment.range[1] <= range[1] + ); + } + + parseCommentOptions(range) { + const comments = this.getComments(range); + if (comments.length === 0) { + return EMPTY_COMMENT_OPTIONS; + } + let options = {}; + 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 { + const val = vm.runInNewContext(`(function(){return {${value}};})()`); + Object.assign(options, val); + } catch (e) { + e.comment = comment; + errors.push(e); + } + } + } + return { options, errors }; + } + + getNameForExpression(expression) { + let expr = expression; + const exprName = []; + while ( + expr.type === "MemberExpression" && + expr.property.type === (expr.computed ? "Literal" : "Identifier") + ) { + exprName.push(expr.computed ? expr.property.value : expr.property.name); + expr = expr.object; + } + let free; + if (expr.type === "Identifier") { + free = !this.scope.definitions.has(expr.name); + exprName.push(this.scope.renames.get(expr.name) || expr.name); + } else if ( + expr.type === "ThisExpression" && + this.scope.renames.get("this") + ) { + free = true; + exprName.push(this.scope.renames.get("this")); + } else if (expr.type === "ThisExpression") { + free = this.scope.topLevelScope; + exprName.push("this"); + } else { + return null; + } + let prefix = ""; + for (let i = exprName.length - 1; i >= 2; i--) { + prefix += exprName[i] + "."; + } + if (exprName.length > 1) { + prefix += exprName[1]; + } + const name = prefix ? prefix + "." + exprName[0] : exprName[0]; + const nameGeneral = prefix; + return { + name, + nameGeneral, + free + }; + } + + static parse(code, options) { + const type = options ? options.sourceType : "module"; + const parserOptions = Object.assign( + Object.create(null), + defaultParserOptions, + options + ); + + if (type === "auto") { + parserOptions.sourceType = "module"; + } else if (parserOptions.sourceType === "script") { + parserOptions.allowReturnOutsideFunction = true; + } + + let ast; + let error; + let threw = false; + try { + ast = acornParser.parse(code, parserOptions); + } catch (e) { + error = e; + threw = true; + } + + if (threw && type === "auto") { + parserOptions.sourceType = "script"; + parserOptions.allowReturnOutsideFunction = true; + if (Array.isArray(parserOptions.onComment)) { + parserOptions.onComment.length = 0; + } + try { + ast = acornParser.parse(code, parserOptions); + threw = false; + } catch (e) { + threw = true; + } + } + + if (threw) { + throw error; + } + + return ast; + } +} + +// TODO remove in webpack 5 +Object.defineProperty(Parser.prototype, "getCommentOptions", { + configurable: false, + value: util.deprecate( + /** + * @deprecated + * @param {TODO} range Range + * @returns {void} + * @this {Parser} + */ + function(range) { + return this.parseCommentOptions(range).options; + }, + "Parser.getCommentOptions: Use Parser.parseCommentOptions(range) instead" + ) +}); + +module.exports = Parser; diff --git a/node_modules/webpack/lib/ParserHelpers.js b/node_modules/webpack/lib/ParserHelpers.js new file mode 100644 index 0000000..5248f12 --- /dev/null +++ b/node_modules/webpack/lib/ParserHelpers.js @@ -0,0 +1,103 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const path = require("path"); + +const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); +const ConstDependency = require("./dependencies/ConstDependency"); +const UnsupportedFeatureWarning = require("./UnsupportedFeatureWarning"); + +const ParserHelpers = exports; + +ParserHelpers.addParsedVariableToModule = (parser, name, expression) => { + if (!parser.state.current.addVariable) return false; + var deps = []; + parser.parse(expression, { + current: { + addDependency: dep => { + dep.userRequest = name; + deps.push(dep); + } + }, + module: parser.state.module + }); + parser.state.current.addVariable(name, expression, deps); + return true; +}; + +ParserHelpers.requireFileAsExpression = (context, pathToModule) => { + var moduleJsPath = path.relative(context, pathToModule); + if (!/^[A-Z]:/i.test(moduleJsPath)) { + moduleJsPath = "./" + moduleJsPath.replace(/\\/g, "/"); + } + return "require(" + JSON.stringify(moduleJsPath) + ")"; +}; + +ParserHelpers.toConstantDependency = (parser, value) => { + return function constDependency(expr) { + var dep = new ConstDependency(value, expr.range, false); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + }; +}; + +ParserHelpers.toConstantDependencyWithWebpackRequire = (parser, value) => { + return function constDependencyWithWebpackRequire(expr) { + var dep = new ConstDependency(value, expr.range, true); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + }; +}; + +ParserHelpers.evaluateToString = value => { + return function stringExpression(expr) { + return new BasicEvaluatedExpression().setString(value).setRange(expr.range); + }; +}; + +ParserHelpers.evaluateToBoolean = value => { + return function booleanExpression(expr) { + return new BasicEvaluatedExpression() + .setBoolean(value) + .setRange(expr.range); + }; +}; + +ParserHelpers.evaluateToIdentifier = (identifier, truthy) => { + return function identifierExpression(expr) { + let evex = new BasicEvaluatedExpression() + .setIdentifier(identifier) + .setRange(expr.range); + if (truthy === true) { + evex = evex.setTruthy(); + } else if (truthy === false) { + evex = evex.setFalsy(); + } + return evex; + }; +}; + +ParserHelpers.expressionIsUnsupported = (parser, message) => { + return function unsupportedExpression(expr) { + var dep = new ConstDependency("(void 0)", expr.range, false); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + if (!parser.state.module) return; + parser.state.module.warnings.push( + new UnsupportedFeatureWarning(parser.state.module, message, expr.loc) + ); + return true; + }; +}; + +ParserHelpers.skipTraversal = function skipTraversal() { + return true; +}; + +ParserHelpers.approve = function approve() { + return true; +}; diff --git a/node_modules/webpack/lib/PrefetchPlugin.js b/node_modules/webpack/lib/PrefetchPlugin.js new file mode 100644 index 0000000..cc9d17c --- /dev/null +++ b/node_modules/webpack/lib/PrefetchPlugin.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const PrefetchDependency = require("./dependencies/PrefetchDependency"); + +class PrefetchPlugin { + constructor(context, request) { + if (!request) { + this.request = context; + } else { + this.context = context; + this.request = request; + } + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "PrefetchPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + PrefetchDependency, + normalModuleFactory + ); + } + ); + compiler.hooks.make.tapAsync("PrefetchPlugin", (compilation, callback) => { + compilation.prefetch( + this.context || compiler.context, + new PrefetchDependency(this.request), + callback + ); + }); + } +} +module.exports = PrefetchPlugin; diff --git a/node_modules/webpack/lib/ProgressPlugin.js b/node_modules/webpack/lib/ProgressPlugin.js new file mode 100644 index 0000000..93a5830 --- /dev/null +++ b/node_modules/webpack/lib/ProgressPlugin.js @@ -0,0 +1,307 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/ProgressPlugin.json"); + +/** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginArgument} ProgressPluginArgument */ +/** @typedef {import("../declarations/plugins/ProgressPlugin").ProgressPluginOptions} ProgressPluginOptions */ + +const createDefaultHandler = (profile, logger) => { + let lastState; + let lastStateTime; + + const defaultHandler = (percentage, msg, ...args) => { + logger.status(`${Math.floor(percentage * 100)}%`, msg, ...args); + if (profile) { + let state = msg; + state = state.replace(/^\d+\/\d+\s+/, ""); + if (percentage === 0) { + lastState = null; + lastStateTime = Date.now(); + } else if (state !== lastState || percentage === 1) { + const now = Date.now(); + if (lastState) { + const diff = now - lastStateTime; + const stateMsg = `${diff}ms ${lastState}`; + if (diff > 1000) { + logger.warn(stateMsg); + } else if (diff > 10) { + logger.info(stateMsg); + } else if (diff > 0) { + logger.log(stateMsg); + } else { + logger.debug(stateMsg); + } + } + lastState = state; + lastStateTime = now; + } + } + if (percentage === 1) logger.status(); + }; + + return defaultHandler; +}; + +class ProgressPlugin { + /** + * @param {ProgressPluginArgument} options options + */ + constructor(options) { + if (typeof options === "function") { + options = { + handler: options + }; + } + + options = options || {}; + validateOptions(schema, options, "Progress Plugin"); + options = Object.assign({}, ProgressPlugin.defaultOptions, options); + + this.profile = options.profile; + this.handler = options.handler; + this.modulesCount = options.modulesCount; + this.showEntries = options.entries; + this.showModules = options.modules; + this.showActiveModules = options.activeModules; + } + + apply(compiler) { + const { modulesCount } = this; + const handler = + this.handler || + createDefaultHandler( + this.profile, + compiler.getInfrastructureLogger("webpack.Progress") + ); + const showEntries = this.showEntries; + const showModules = this.showModules; + const showActiveModules = this.showActiveModules; + if (compiler.compilers) { + const states = new Array(compiler.compilers.length); + compiler.compilers.forEach((compiler, idx) => { + new ProgressPlugin((p, msg, ...args) => { + states[idx] = [p, msg, ...args]; + handler( + states + .map(state => (state && state[0]) || 0) + .reduce((a, b) => a + b) / states.length, + `[${idx}] ${msg}`, + ...args + ); + }).apply(compiler); + }); + } else { + let lastModulesCount = 0; + let lastEntriesCount = 0; + let moduleCount = modulesCount; + let entriesCount = 1; + let doneModules = 0; + let doneEntries = 0; + const activeModules = new Set(); + let lastActiveModule = ""; + + const update = () => { + const percentByModules = + doneModules / Math.max(lastModulesCount, moduleCount); + const percentByEntries = + doneEntries / Math.max(lastEntriesCount, entriesCount); + + const items = [ + 0.1 + Math.max(percentByModules, percentByEntries) * 0.6, + "building" + ]; + if (showEntries) { + items.push(`${doneEntries}/${entriesCount} entries`); + } + if (showModules) { + items.push(`${doneModules}/${moduleCount} modules`); + } + if (showActiveModules) { + items.push(`${activeModules.size} active`); + items.push(lastActiveModule); + } + handler(...items); + }; + + const moduleAdd = module => { + moduleCount++; + if (showActiveModules) { + const ident = module.identifier(); + if (ident) { + activeModules.add(ident); + lastActiveModule = ident; + } + } + update(); + }; + + const entryAdd = (entry, name) => { + entriesCount++; + update(); + }; + + const moduleDone = module => { + doneModules++; + if (showActiveModules) { + const ident = module.identifier(); + if (ident) { + activeModules.delete(ident); + if (lastActiveModule === ident) { + lastActiveModule = ""; + for (const m of activeModules) { + lastActiveModule = m; + } + } + } + } + update(); + }; + + const entryDone = (entry, name) => { + doneEntries++; + update(); + }; + + compiler.hooks.compilation.tap("ProgressPlugin", compilation => { + if (compilation.compiler.isChild()) return; + lastModulesCount = moduleCount; + lastEntriesCount = entriesCount; + moduleCount = entriesCount = 0; + doneModules = doneEntries = 0; + handler(0, "compiling"); + + compilation.hooks.buildModule.tap("ProgressPlugin", moduleAdd); + compilation.hooks.failedModule.tap("ProgressPlugin", moduleDone); + compilation.hooks.succeedModule.tap("ProgressPlugin", moduleDone); + + compilation.hooks.addEntry.tap("ProgressPlugin", entryAdd); + compilation.hooks.failedEntry.tap("ProgressPlugin", entryDone); + compilation.hooks.succeedEntry.tap("ProgressPlugin", entryDone); + + const hooks = { + finishModules: "finish module graph", + seal: "sealing", + beforeChunks: "chunk graph", + afterChunks: "after chunk graph", + optimizeDependenciesBasic: "basic dependencies optimization", + optimizeDependencies: "dependencies optimization", + optimizeDependenciesAdvanced: "advanced dependencies optimization", + afterOptimizeDependencies: "after dependencies optimization", + optimize: "optimizing", + optimizeModulesBasic: "basic module optimization", + optimizeModules: "module optimization", + optimizeModulesAdvanced: "advanced module optimization", + afterOptimizeModules: "after module optimization", + optimizeChunksBasic: "basic chunk optimization", + optimizeChunks: "chunk optimization", + optimizeChunksAdvanced: "advanced chunk optimization", + afterOptimizeChunks: "after chunk optimization", + optimizeTree: "module and chunk tree optimization", + afterOptimizeTree: "after module and chunk tree optimization", + optimizeChunkModulesBasic: "basic chunk modules optimization", + optimizeChunkModules: "chunk modules optimization", + optimizeChunkModulesAdvanced: "advanced chunk modules optimization", + afterOptimizeChunkModules: "after chunk modules optimization", + reviveModules: "module reviving", + optimizeModuleOrder: "module order optimization", + advancedOptimizeModuleOrder: "advanced module order optimization", + beforeModuleIds: "before module ids", + moduleIds: "module ids", + optimizeModuleIds: "module id optimization", + afterOptimizeModuleIds: "module id optimization", + reviveChunks: "chunk reviving", + optimizeChunkOrder: "chunk order optimization", + beforeChunkIds: "before chunk ids", + optimizeChunkIds: "chunk id optimization", + afterOptimizeChunkIds: "after chunk id optimization", + recordModules: "record modules", + recordChunks: "record chunks", + beforeHash: "hashing", + afterHash: "after hashing", + recordHash: "record hash", + beforeModuleAssets: "module assets processing", + beforeChunkAssets: "chunk assets processing", + additionalChunkAssets: "additional chunk assets processing", + record: "recording", + additionalAssets: "additional asset processing", + optimizeChunkAssets: "chunk asset optimization", + afterOptimizeChunkAssets: "after chunk asset optimization", + optimizeAssets: "asset optimization", + afterOptimizeAssets: "after asset optimization", + afterSeal: "after seal" + }; + const numberOfHooks = Object.keys(hooks).length; + Object.keys(hooks).forEach((name, idx) => { + const title = hooks[name]; + const percentage = (idx / numberOfHooks) * 0.25 + 0.7; + compilation.hooks[name].intercept({ + name: "ProgressPlugin", + context: true, + call: () => { + handler(percentage, title); + }, + tap: (context, tap) => { + if (context) { + // p is percentage from 0 to 1 + // args is any number of messages in a hierarchical matter + context.reportProgress = (p, ...args) => { + handler(percentage, title, tap.name, ...args); + }; + } + handler(percentage, title, tap.name); + } + }); + }); + }); + compiler.hooks.emit.intercept({ + name: "ProgressPlugin", + context: true, + call: () => { + handler(0.95, "emitting"); + }, + tap: (context, tap) => { + if (context) { + context.reportProgress = (p, ...args) => { + handler(0.95, "emitting", tap.name, ...args); + }; + } + handler(0.95, "emitting", tap.name); + } + }); + compiler.hooks.afterEmit.intercept({ + name: "ProgressPlugin", + context: true, + call: () => { + handler(0.98, "after emitting"); + }, + tap: (context, tap) => { + if (context) { + context.reportProgress = (p, ...args) => { + handler(0.98, "after emitting", tap.name, ...args); + }; + } + handler(0.98, "after emitting", tap.name); + } + }); + compiler.hooks.done.tap("ProgressPlugin", () => { + handler(1, ""); + }); + } + } +} + +ProgressPlugin.defaultOptions = { + profile: false, + modulesCount: 500, + modules: true, + activeModules: true, + // TODO webpack 5 default this to true + entries: false +}; + +module.exports = ProgressPlugin; diff --git a/node_modules/webpack/lib/ProvidePlugin.js b/node_modules/webpack/lib/ProvidePlugin.js new file mode 100644 index 0000000..4e6a69d --- /dev/null +++ b/node_modules/webpack/lib/ProvidePlugin.js @@ -0,0 +1,86 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ParserHelpers = require("./ParserHelpers"); +const ConstDependency = require("./dependencies/ConstDependency"); + +const NullFactory = require("./NullFactory"); + +class ProvidePlugin { + constructor(definitions) { + this.definitions = definitions; + } + + apply(compiler) { + const definitions = this.definitions; + compiler.hooks.compilation.tap( + "ProvidePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + const handler = (parser, parserOptions) => { + Object.keys(definitions).forEach(name => { + var request = [].concat(definitions[name]); + var splittedName = name.split("."); + if (splittedName.length > 0) { + splittedName.slice(1).forEach((_, i) => { + const name = splittedName.slice(0, i + 1).join("."); + parser.hooks.canRename + .for(name) + .tap("ProvidePlugin", ParserHelpers.approve); + }); + } + parser.hooks.expression.for(name).tap("ProvidePlugin", expr => { + let nameIdentifier = name; + const scopedName = name.includes("."); + let expression = `require(${JSON.stringify(request[0])})`; + if (scopedName) { + nameIdentifier = `__webpack_provided_${name.replace( + /\./g, + "_dot_" + )}`; + } + if (request.length > 1) { + expression += request + .slice(1) + .map(r => `[${JSON.stringify(r)}]`) + .join(""); + } + if ( + !ParserHelpers.addParsedVariableToModule( + parser, + nameIdentifier, + expression + ) + ) { + return false; + } + if (scopedName) { + ParserHelpers.toConstantDependency( + parser, + nameIdentifier + )(expr); + } + return true; + }); + }); + }; + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("ProvidePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("ProvidePlugin", handler); + + // Disable ProvidePlugin for javascript/esm, see https://github.com/webpack/webpack/issues/7032 + } + ); + } +} +module.exports = ProvidePlugin; diff --git a/node_modules/webpack/lib/RawModule.js b/node_modules/webpack/lib/RawModule.js new file mode 100644 index 0000000..ab3fd3a --- /dev/null +++ b/node_modules/webpack/lib/RawModule.js @@ -0,0 +1,56 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Module = require("./Module"); +const { OriginalSource, RawSource } = require("webpack-sources"); + +module.exports = class RawModule extends Module { + constructor(source, identifier, readableIdentifier) { + super("javascript/dynamic", null); + this.sourceStr = source; + this.identifierStr = identifier || this.sourceStr; + this.readableIdentifierStr = readableIdentifier || this.identifierStr; + this.built = false; + } + + identifier() { + return this.identifierStr; + } + + size() { + return this.sourceStr.length; + } + + readableIdentifier(requestShortener) { + return requestShortener.shorten(this.readableIdentifierStr); + } + + needRebuild() { + return false; + } + + build(options, compilations, resolver, fs, callback) { + this.built = true; + this.buildMeta = {}; + this.buildInfo = { + cacheable: true + }; + callback(); + } + + source() { + if (this.useSourceMap) { + return new OriginalSource(this.sourceStr, this.identifier()); + } else { + return new RawSource(this.sourceStr); + } + } + + updateHash(hash) { + hash.update(this.sourceStr); + super.updateHash(hash); + } +}; diff --git a/node_modules/webpack/lib/RecordIdsPlugin.js b/node_modules/webpack/lib/RecordIdsPlugin.js new file mode 100644 index 0000000..3979f1f --- /dev/null +++ b/node_modules/webpack/lib/RecordIdsPlugin.js @@ -0,0 +1,236 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const identifierUtils = require("./util/identifier"); + +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./Module")} Module */ + +/** + * @typedef {Object} RecordsChunks + * @property {Record<string, number>=} byName + * @property {Record<string, number>=} bySource + * @property {number[]=} usedIds + */ + +/** + * @typedef {Object} RecordsModules + * @property {Record<string, number>=} byIdentifier + * @property {Record<string, number>=} bySource + * @property {Record<number, number>=} usedIds + */ + +/** + * @typedef {Object} Records + * @property {RecordsChunks=} chunks + * @property {RecordsModules=} modules + */ + +class RecordIdsPlugin { + /** + * @param {Object} options Options object + * @param {boolean=} options.portableIds true, when ids need to be portable + */ + constructor(options) { + this.options = options || {}; + } + + /** + * @param {Compiler} compiler the Compiler + * @returns {void} + */ + apply(compiler) { + const portableIds = this.options.portableIds; + compiler.hooks.compilation.tap("RecordIdsPlugin", compilation => { + compilation.hooks.recordModules.tap( + "RecordIdsPlugin", + /** + * @param {Module[]} modules the modules array + * @param {Records} records the records object + * @returns {void} + */ + (modules, records) => { + if (!records.modules) records.modules = {}; + if (!records.modules.byIdentifier) records.modules.byIdentifier = {}; + if (!records.modules.usedIds) records.modules.usedIds = {}; + for (const module of modules) { + if (typeof module.id !== "number") continue; + const identifier = portableIds + ? identifierUtils.makePathsRelative( + compiler.context, + module.identifier(), + compilation.cache + ) + : module.identifier(); + records.modules.byIdentifier[identifier] = module.id; + records.modules.usedIds[module.id] = module.id; + } + } + ); + compilation.hooks.reviveModules.tap( + "RecordIdsPlugin", + /** + * @param {Module[]} modules the modules array + * @param {Records} records the records object + * @returns {void} + */ + (modules, records) => { + if (!records.modules) return; + if (records.modules.byIdentifier) { + /** @type {Set<number>} */ + const usedIds = new Set(); + for (const module of modules) { + if (module.id !== null) continue; + const identifier = portableIds + ? identifierUtils.makePathsRelative( + compiler.context, + module.identifier(), + compilation.cache + ) + : module.identifier(); + const id = records.modules.byIdentifier[identifier]; + if (id === undefined) continue; + if (usedIds.has(id)) continue; + usedIds.add(id); + module.id = id; + } + } + if (Array.isArray(records.modules.usedIds)) { + compilation.usedModuleIds = new Set(records.modules.usedIds); + } + } + ); + + /** + * @param {Module} module the module + * @returns {string} the (portable) identifier + */ + const getModuleIdentifier = module => { + if (portableIds) { + return identifierUtils.makePathsRelative( + compiler.context, + module.identifier(), + compilation.cache + ); + } + return module.identifier(); + }; + + /** + * @param {Chunk} chunk the chunk + * @returns {string[]} sources of the chunk + */ + const getChunkSources = chunk => { + /** @type {string[]} */ + const sources = []; + for (const chunkGroup of chunk.groupsIterable) { + const index = chunkGroup.chunks.indexOf(chunk); + if (chunkGroup.name) { + sources.push(`${index} ${chunkGroup.name}`); + } else { + for (const origin of chunkGroup.origins) { + if (origin.module) { + if (origin.request) { + sources.push( + `${index} ${getModuleIdentifier(origin.module)} ${ + origin.request + }` + ); + } else if (typeof origin.loc === "string") { + sources.push( + `${index} ${getModuleIdentifier(origin.module)} ${ + origin.loc + }` + ); + } else if ( + origin.loc && + typeof origin.loc === "object" && + origin.loc.start + ) { + sources.push( + `${index} ${getModuleIdentifier( + origin.module + )} ${JSON.stringify(origin.loc.start)}` + ); + } + } + } + } + } + return sources; + }; + + compilation.hooks.recordChunks.tap( + "RecordIdsPlugin", + /** + * @param {Chunk[]} chunks the chunks array + * @param {Records} records the records object + * @returns {void} + */ + (chunks, records) => { + if (!records.chunks) records.chunks = {}; + if (!records.chunks.byName) records.chunks.byName = {}; + if (!records.chunks.bySource) records.chunks.bySource = {}; + /** @type {Set<number>} */ + const usedIds = new Set(); + for (const chunk of chunks) { + if (typeof chunk.id !== "number") continue; + const name = chunk.name; + if (name) records.chunks.byName[name] = chunk.id; + const sources = getChunkSources(chunk); + for (const source of sources) { + records.chunks.bySource[source] = chunk.id; + } + usedIds.add(chunk.id); + } + records.chunks.usedIds = Array.from(usedIds).sort(); + } + ); + compilation.hooks.reviveChunks.tap( + "RecordIdsPlugin", + /** + * @param {Chunk[]} chunks the chunks array + * @param {Records} records the records object + * @returns {void} + */ + (chunks, records) => { + if (!records.chunks) return; + /** @type {Set<number>} */ + const usedIds = new Set(); + if (records.chunks.byName) { + for (const chunk of chunks) { + if (chunk.id !== null) continue; + if (!chunk.name) continue; + const id = records.chunks.byName[chunk.name]; + if (id === undefined) continue; + if (usedIds.has(id)) continue; + usedIds.add(id); + chunk.id = id; + } + } + if (records.chunks.bySource) { + for (const chunk of chunks) { + const sources = getChunkSources(chunk); + for (const source of sources) { + const id = records.chunks.bySource[source]; + if (id === undefined) continue; + if (usedIds.has(id)) continue; + usedIds.add(id); + chunk.id = id; + break; + } + } + } + if (Array.isArray(records.chunks.usedIds)) { + compilation.usedChunkIds = new Set(records.chunks.usedIds); + } + } + ); + }); + } +} +module.exports = RecordIdsPlugin; diff --git a/node_modules/webpack/lib/RemovedPluginError.js b/node_modules/webpack/lib/RemovedPluginError.js new file mode 100644 index 0000000..626c3b4 --- /dev/null +++ b/node_modules/webpack/lib/RemovedPluginError.js @@ -0,0 +1,11 @@ +"use strict"; + +const WebpackError = require("./WebpackError"); + +module.exports = class RemovedPluginError extends WebpackError { + constructor(message) { + super(message); + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/RequestShortener.js b/node_modules/webpack/lib/RequestShortener.js new file mode 100644 index 0000000..3d9af00 --- /dev/null +++ b/node_modules/webpack/lib/RequestShortener.js @@ -0,0 +1,83 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const NORMALIZE_SLASH_DIRECTION_REGEXP = /\\/g; +const PATH_CHARS_REGEXP = /[-[\]{}()*+?.,\\^$|#\s]/g; +const SEPARATOR_REGEXP = /[/\\]$/; +const FRONT_OR_BACK_BANG_REGEXP = /^!|!$/g; +const INDEX_JS_REGEXP = /\/index.js(!|\?|\(query\))/g; +const MATCH_RESOURCE_REGEXP = /!=!/; + +const normalizeBackSlashDirection = request => { + return request.replace(NORMALIZE_SLASH_DIRECTION_REGEXP, "/"); +}; + +const createRegExpForPath = path => { + const regexpTypePartial = path.replace(PATH_CHARS_REGEXP, "\\$&"); + return new RegExp(`(^|!)${regexpTypePartial}`, "g"); +}; + +class RequestShortener { + constructor(directory) { + directory = normalizeBackSlashDirection(directory); + if (SEPARATOR_REGEXP.test(directory)) { + directory = directory.substr(0, directory.length - 1); + } + + if (directory) { + this.currentDirectoryRegExp = createRegExpForPath(directory); + } + + const dirname = path.dirname(directory); + const endsWithSeparator = SEPARATOR_REGEXP.test(dirname); + const parentDirectory = endsWithSeparator + ? dirname.substr(0, dirname.length - 1) + : dirname; + if (parentDirectory && parentDirectory !== directory) { + this.parentDirectoryRegExp = createRegExpForPath(`${parentDirectory}/`); + } + + if (__dirname.length >= 2) { + const buildins = normalizeBackSlashDirection(path.join(__dirname, "..")); + const buildinsAsModule = + this.currentDirectoryRegExp && + this.currentDirectoryRegExp.test(buildins); + this.buildinsAsModule = buildinsAsModule; + this.buildinsRegExp = createRegExpForPath(buildins); + } + + this.cache = new Map(); + } + + shorten(request) { + if (!request) return request; + const cacheEntry = this.cache.get(request); + if (cacheEntry !== undefined) { + return cacheEntry; + } + let result = normalizeBackSlashDirection(request); + if (this.buildinsAsModule && this.buildinsRegExp) { + result = result.replace(this.buildinsRegExp, "!(webpack)"); + } + if (this.currentDirectoryRegExp) { + result = result.replace(this.currentDirectoryRegExp, "!."); + } + if (this.parentDirectoryRegExp) { + result = result.replace(this.parentDirectoryRegExp, "!../"); + } + if (!this.buildinsAsModule && this.buildinsRegExp) { + result = result.replace(this.buildinsRegExp, "!(webpack)"); + } + result = result.replace(INDEX_JS_REGEXP, "$1"); + result = result.replace(FRONT_OR_BACK_BANG_REGEXP, ""); + result = result.replace(MATCH_RESOURCE_REGEXP, " = "); + this.cache.set(request, result); + return result; + } +} + +module.exports = RequestShortener; diff --git a/node_modules/webpack/lib/RequireJsStuffPlugin.js b/node_modules/webpack/lib/RequireJsStuffPlugin.js new file mode 100644 index 0000000..632deef --- /dev/null +++ b/node_modules/webpack/lib/RequireJsStuffPlugin.js @@ -0,0 +1,66 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ParserHelpers = require("./ParserHelpers"); +const ConstDependency = require("./dependencies/ConstDependency"); +const NullFactory = require("./NullFactory"); + +module.exports = class RequireJsStuffPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "RequireJsStuffPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set(ConstDependency, new NullFactory()); + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + const handler = (parser, parserOptions) => { + if (parserOptions.requireJs !== undefined && !parserOptions.requireJs) + return; + + parser.hooks.call + .for("require.config") + .tap( + "RequireJsStuffPlugin", + ParserHelpers.toConstantDependency(parser, "undefined") + ); + parser.hooks.call + .for("requirejs.config") + .tap( + "RequireJsStuffPlugin", + ParserHelpers.toConstantDependency(parser, "undefined") + ); + + parser.hooks.expression + .for("require.version") + .tap( + "RequireJsStuffPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("0.0.0") + ) + ); + parser.hooks.expression + .for("requirejs.onError") + .tap( + "RequireJsStuffPlugin", + ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + "__webpack_require__.oe" + ) + ); + }; + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("RequireJsStuffPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("RequireJsStuffPlugin", handler); + } + ); + } +}; diff --git a/node_modules/webpack/lib/ResolverFactory.js b/node_modules/webpack/lib/ResolverFactory.js new file mode 100644 index 0000000..7166257 --- /dev/null +++ b/node_modules/webpack/lib/ResolverFactory.js @@ -0,0 +1,74 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const { Tapable, HookMap, SyncHook, SyncWaterfallHook } = require("tapable"); +const Factory = require("enhanced-resolve").ResolverFactory; +const { cachedCleverMerge } = require("./util/cleverMerge"); + +/** @typedef {import("enhanced-resolve").Resolver} Resolver */ + +const EMTPY_RESOLVE_OPTIONS = {}; + +module.exports = class ResolverFactory extends Tapable { + constructor() { + super(); + this.hooks = { + resolveOptions: new HookMap( + () => new SyncWaterfallHook(["resolveOptions"]) + ), + resolver: new HookMap(() => new SyncHook(["resolver", "resolveOptions"])) + }; + this._pluginCompat.tap("ResolverFactory", options => { + let match; + match = /^resolve-options (.+)$/.exec(options.name); + if (match) { + this.hooks.resolveOptions + .for(match[1]) + .tap(options.fn.name || "unnamed compat plugin", options.fn); + return true; + } + match = /^resolver (.+)$/.exec(options.name); + if (match) { + this.hooks.resolver + .for(match[1]) + .tap(options.fn.name || "unnamed compat plugin", options.fn); + return true; + } + }); + this.cache2 = new Map(); + } + + get(type, resolveOptions) { + resolveOptions = resolveOptions || EMTPY_RESOLVE_OPTIONS; + const ident = `${type}|${JSON.stringify(resolveOptions)}`; + const resolver = this.cache2.get(ident); + if (resolver) return resolver; + const newResolver = this._create(type, resolveOptions); + this.cache2.set(ident, newResolver); + return newResolver; + } + + _create(type, resolveOptions) { + const originalResolveOptions = Object.assign({}, resolveOptions); + resolveOptions = this.hooks.resolveOptions.for(type).call(resolveOptions); + const resolver = Factory.createResolver(resolveOptions); + if (!resolver) { + throw new Error("No resolver created"); + } + /** @type {Map<Object, Resolver>} */ + const childCache = new Map(); + resolver.withOptions = options => { + const cacheEntry = childCache.get(options); + if (cacheEntry !== undefined) return cacheEntry; + const mergedOptions = cachedCleverMerge(originalResolveOptions, options); + const resolver = this.get(type, mergedOptions); + childCache.set(options, resolver); + return resolver; + }; + this.hooks.resolver.for(type).call(resolver, resolveOptions); + return resolver; + } +}; diff --git a/node_modules/webpack/lib/RuleSet.js b/node_modules/webpack/lib/RuleSet.js new file mode 100644 index 0000000..7ed8eba --- /dev/null +++ b/node_modules/webpack/lib/RuleSet.js @@ -0,0 +1,567 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +/* +<rules>: <rule> +<rules>: [<rule>] +<rule>: { + resource: { + test: <condition>, + include: <condition>, + exclude: <condition>, + }, + resource: <condition>, -> resource.test + test: <condition>, -> resource.test + include: <condition>, -> resource.include + exclude: <condition>, -> resource.exclude + resourceQuery: <condition>, + compiler: <condition>, + issuer: <condition>, + use: "loader", -> use[0].loader + loader: <>, -> use[0].loader + loaders: <>, -> use + options: {}, -> use[0].options, + query: {}, -> options + parser: {}, + use: [ + "loader" -> use[x].loader + ], + use: [ + { + loader: "loader", + options: {} + } + ], + rules: [ + <rule> + ], + oneOf: [ + <rule> + ] +} + +<condition>: /regExp/ +<condition>: function(arg) {} +<condition>: "starting" +<condition>: [<condition>] // or +<condition>: { and: [<condition>] } +<condition>: { or: [<condition>] } +<condition>: { not: [<condition>] } +<condition>: { test: <condition>, include: <condition>, exclude: <condition> } + + +normalized: + +{ + resource: function(), + resourceQuery: function(), + compiler: function(), + issuer: function(), + use: [ + { + loader: string, + options: string, + <any>: <any> + } + ], + rules: [<rule>], + oneOf: [<rule>], + <any>: <any>, +} + +*/ + +"use strict"; + +const notMatcher = matcher => { + return str => { + return !matcher(str); + }; +}; + +const orMatcher = items => { + return str => { + for (let i = 0; i < items.length; i++) { + if (items[i](str)) return true; + } + return false; + }; +}; + +const andMatcher = items => { + return str => { + for (let i = 0; i < items.length; i++) { + if (!items[i](str)) return false; + } + return true; + }; +}; + +module.exports = class RuleSet { + constructor(rules) { + this.references = Object.create(null); + this.rules = RuleSet.normalizeRules(rules, this.references, "ref-"); + } + + static normalizeRules(rules, refs, ident) { + if (Array.isArray(rules)) { + return rules.map((rule, idx) => { + return RuleSet.normalizeRule(rule, refs, `${ident}-${idx}`); + }); + } else if (rules) { + return [RuleSet.normalizeRule(rules, refs, ident)]; + } else { + return []; + } + } + + static normalizeRule(rule, refs, ident) { + if (typeof rule === "string") { + return { + use: [ + { + loader: rule + } + ] + }; + } + if (!rule) { + throw new Error("Unexcepted null when object was expected as rule"); + } + if (typeof rule !== "object") { + throw new Error( + "Unexcepted " + + typeof rule + + " when object was expected as rule (" + + rule + + ")" + ); + } + + const newRule = {}; + let useSource; + let resourceSource; + let condition; + + const checkUseSource = newSource => { + if (useSource && useSource !== newSource) { + throw new Error( + RuleSet.buildErrorMessage( + rule, + new Error( + "Rule can only have one result source (provided " + + newSource + + " and " + + useSource + + ")" + ) + ) + ); + } + useSource = newSource; + }; + + const checkResourceSource = newSource => { + if (resourceSource && resourceSource !== newSource) { + throw new Error( + RuleSet.buildErrorMessage( + rule, + new Error( + "Rule can only have one resource source (provided " + + newSource + + " and " + + resourceSource + + ")" + ) + ) + ); + } + resourceSource = newSource; + }; + + if (rule.test || rule.include || rule.exclude) { + checkResourceSource("test + include + exclude"); + condition = { + test: rule.test, + include: rule.include, + exclude: rule.exclude + }; + try { + newRule.resource = RuleSet.normalizeCondition(condition); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(condition, error)); + } + } + + if (rule.resource) { + checkResourceSource("resource"); + try { + newRule.resource = RuleSet.normalizeCondition(rule.resource); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(rule.resource, error)); + } + } + + if (rule.realResource) { + try { + newRule.realResource = RuleSet.normalizeCondition(rule.realResource); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(rule.realResource, error)); + } + } + + if (rule.resourceQuery) { + try { + newRule.resourceQuery = RuleSet.normalizeCondition(rule.resourceQuery); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(rule.resourceQuery, error)); + } + } + + if (rule.compiler) { + try { + newRule.compiler = RuleSet.normalizeCondition(rule.compiler); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(rule.compiler, error)); + } + } + + if (rule.issuer) { + try { + newRule.issuer = RuleSet.normalizeCondition(rule.issuer); + } catch (error) { + throw new Error(RuleSet.buildErrorMessage(rule.issuer, error)); + } + } + + if (rule.loader && rule.loaders) { + throw new Error( + RuleSet.buildErrorMessage( + rule, + new Error( + "Provided loader and loaders for rule (use only one of them)" + ) + ) + ); + } + + const loader = rule.loaders || rule.loader; + if (typeof loader === "string" && !rule.options && !rule.query) { + checkUseSource("loader"); + newRule.use = RuleSet.normalizeUse(loader.split("!"), ident); + } else if (typeof loader === "string" && (rule.options || rule.query)) { + checkUseSource("loader + options/query"); + newRule.use = RuleSet.normalizeUse( + { + loader: loader, + options: rule.options, + query: rule.query + }, + ident + ); + } else if (loader && (rule.options || rule.query)) { + throw new Error( + RuleSet.buildErrorMessage( + rule, + new Error( + "options/query cannot be used with loaders (use options for each array item)" + ) + ) + ); + } else if (loader) { + checkUseSource("loaders"); + newRule.use = RuleSet.normalizeUse(loader, ident); + } else if (rule.options || rule.query) { + throw new Error( + RuleSet.buildErrorMessage( + rule, + new Error( + "options/query provided without loader (use loader + options)" + ) + ) + ); + } + + if (rule.use) { + checkUseSource("use"); + newRule.use = RuleSet.normalizeUse(rule.use, ident); + } + + if (rule.rules) { + newRule.rules = RuleSet.normalizeRules( + rule.rules, + refs, + `${ident}-rules` + ); + } + + if (rule.oneOf) { + newRule.oneOf = RuleSet.normalizeRules( + rule.oneOf, + refs, + `${ident}-oneOf` + ); + } + + const keys = Object.keys(rule).filter(key => { + return ![ + "resource", + "resourceQuery", + "compiler", + "test", + "include", + "exclude", + "issuer", + "loader", + "options", + "query", + "loaders", + "use", + "rules", + "oneOf" + ].includes(key); + }); + for (const key of keys) { + newRule[key] = rule[key]; + } + + if (Array.isArray(newRule.use)) { + for (const item of newRule.use) { + if (item.ident) { + refs[item.ident] = item.options; + } + } + } + + return newRule; + } + + static buildErrorMessage(condition, error) { + const conditionAsText = JSON.stringify( + condition, + (key, value) => { + return value === undefined ? "undefined" : value; + }, + 2 + ); + return error.message + " in " + conditionAsText; + } + + static normalizeUse(use, ident) { + if (typeof use === "function") { + return data => RuleSet.normalizeUse(use(data), ident); + } + if (Array.isArray(use)) { + return use + .map((item, idx) => RuleSet.normalizeUse(item, `${ident}-${idx}`)) + .reduce((arr, items) => arr.concat(items), []); + } + return [RuleSet.normalizeUseItem(use, ident)]; + } + + static normalizeUseItemString(useItemString) { + const idx = useItemString.indexOf("?"); + if (idx >= 0) { + return { + loader: useItemString.substr(0, idx), + options: useItemString.substr(idx + 1) + }; + } + return { + loader: useItemString, + options: undefined + }; + } + + static normalizeUseItem(item, ident) { + if (typeof item === "string") { + return RuleSet.normalizeUseItemString(item); + } + + const newItem = {}; + + if (item.options && item.query) { + throw new Error("Provided options and query in use"); + } + + if (!item.loader) { + throw new Error("No loader specified"); + } + + newItem.options = item.options || item.query; + + if (typeof newItem.options === "object" && newItem.options) { + if (newItem.options.ident) { + newItem.ident = newItem.options.ident; + } else { + newItem.ident = ident; + } + } + + const keys = Object.keys(item).filter(function(key) { + return !["options", "query"].includes(key); + }); + + for (const key of keys) { + newItem[key] = item[key]; + } + + return newItem; + } + + static normalizeCondition(condition) { + if (!condition) throw new Error("Expected condition but got falsy value"); + if (typeof condition === "string") { + return str => str.indexOf(condition) === 0; + } + if (typeof condition === "function") { + return condition; + } + if (condition instanceof RegExp) { + return condition.test.bind(condition); + } + if (Array.isArray(condition)) { + const items = condition.map(c => RuleSet.normalizeCondition(c)); + return orMatcher(items); + } + if (typeof condition !== "object") { + throw Error( + "Unexcepted " + + typeof condition + + " when condition was expected (" + + condition + + ")" + ); + } + + const matchers = []; + Object.keys(condition).forEach(key => { + const value = condition[key]; + switch (key) { + case "or": + case "include": + case "test": + if (value) matchers.push(RuleSet.normalizeCondition(value)); + break; + case "and": + if (value) { + const items = value.map(c => RuleSet.normalizeCondition(c)); + matchers.push(andMatcher(items)); + } + break; + case "not": + case "exclude": + if (value) { + const matcher = RuleSet.normalizeCondition(value); + matchers.push(notMatcher(matcher)); + } + break; + default: + throw new Error("Unexcepted property " + key + " in condition"); + } + }); + if (matchers.length === 0) { + throw new Error("Excepted condition but got " + condition); + } + if (matchers.length === 1) { + return matchers[0]; + } + return andMatcher(matchers); + } + + exec(data) { + const result = []; + this._run( + data, + { + rules: this.rules + }, + result + ); + return result; + } + + _run(data, rule, result) { + // test conditions + if (rule.resource && !data.resource) return false; + if (rule.realResource && !data.realResource) return false; + if (rule.resourceQuery && !data.resourceQuery) return false; + if (rule.compiler && !data.compiler) return false; + if (rule.issuer && !data.issuer) return false; + if (rule.resource && !rule.resource(data.resource)) return false; + if (rule.realResource && !rule.realResource(data.realResource)) + return false; + if (data.issuer && rule.issuer && !rule.issuer(data.issuer)) return false; + if ( + data.resourceQuery && + rule.resourceQuery && + !rule.resourceQuery(data.resourceQuery) + ) { + return false; + } + if (data.compiler && rule.compiler && !rule.compiler(data.compiler)) { + return false; + } + + // apply + const keys = Object.keys(rule).filter(key => { + return ![ + "resource", + "realResource", + "resourceQuery", + "compiler", + "issuer", + "rules", + "oneOf", + "use", + "enforce" + ].includes(key); + }); + for (const key of keys) { + result.push({ + type: key, + value: rule[key] + }); + } + + if (rule.use) { + const process = use => { + if (typeof use === "function") { + process(use(data)); + } else if (Array.isArray(use)) { + use.forEach(process); + } else { + result.push({ + type: "use", + value: use, + enforce: rule.enforce + }); + } + }; + process(rule.use); + } + + if (rule.rules) { + for (let i = 0; i < rule.rules.length; i++) { + this._run(data, rule.rules[i], result); + } + } + + if (rule.oneOf) { + for (let i = 0; i < rule.oneOf.length; i++) { + if (this._run(data, rule.oneOf[i], result)) break; + } + } + + return true; + } + + findOptionsByIdent(ident) { + const options = this.references[ident]; + if (!options) { + throw new Error("Can't find options with ident '" + ident + "'"); + } + return options; + } +}; diff --git a/node_modules/webpack/lib/RuntimeTemplate.js b/node_modules/webpack/lib/RuntimeTemplate.js new file mode 100644 index 0000000..613aed1 --- /dev/null +++ b/node_modules/webpack/lib/RuntimeTemplate.js @@ -0,0 +1,336 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("./Template"); + +/** @typedef {import("./Module")} Module */ + +module.exports = class RuntimeTemplate { + constructor(outputOptions, requestShortener) { + this.outputOptions = outputOptions || {}; + this.requestShortener = requestShortener; + } + + /** + * Add a comment + * @param {object} options Information content of the comment + * @param {string=} options.request request string used originally + * @param {string=} options.chunkName name of the chunk referenced + * @param {string=} options.chunkReason reason information of the chunk + * @param {string=} options.message additional message + * @param {string=} options.exportName name of the export + * @returns {string} comment + */ + comment({ request, chunkName, chunkReason, message, exportName }) { + let content; + if (this.outputOptions.pathinfo) { + content = [message, request, chunkName, chunkReason] + .filter(Boolean) + .map(item => this.requestShortener.shorten(item)) + .join(" | "); + } else { + content = [message, chunkName, chunkReason] + .filter(Boolean) + .map(item => this.requestShortener.shorten(item)) + .join(" | "); + } + if (!content) return ""; + if (this.outputOptions.pathinfo) { + return Template.toComment(content) + " "; + } else { + return Template.toNormalComment(content) + " "; + } + } + + throwMissingModuleErrorFunction({ request }) { + const err = `Cannot find module '${request}'`; + return `function webpackMissingModule() { var e = new Error(${JSON.stringify( + err + )}); e.code = 'MODULE_NOT_FOUND'; throw e; }`; + } + + missingModule({ request }) { + return `!(${this.throwMissingModuleErrorFunction({ request })}())`; + } + + missingModuleStatement({ request }) { + return `${this.missingModule({ request })};\n`; + } + + missingModulePromise({ request }) { + return `Promise.resolve().then(${this.throwMissingModuleErrorFunction({ + request + })})`; + } + + moduleId({ module, request }) { + if (!module) { + return this.missingModule({ + request + }); + } + if (module.id === null) { + throw new Error( + `RuntimeTemplate.moduleId(): Module ${module.identifier()} has no id. This should not happen.` + ); + } + return `${this.comment({ request })}${JSON.stringify(module.id)}`; + } + + moduleRaw({ module, request }) { + if (!module) { + return this.missingModule({ + request + }); + } + return `__webpack_require__(${this.moduleId({ module, request })})`; + } + + moduleExports({ module, request }) { + return this.moduleRaw({ + module, + request + }); + } + + moduleNamespace({ module, request, strict }) { + if (!module) { + return this.missingModule({ + request + }); + } + const moduleId = this.moduleId({ + module, + request + }); + const exportsType = module.buildMeta && module.buildMeta.exportsType; + if (exportsType === "namespace") { + const rawModule = this.moduleRaw({ + module, + request + }); + return rawModule; + } else if (exportsType === "named") { + return `__webpack_require__.t(${moduleId}, 3)`; + } else if (strict) { + return `__webpack_require__.t(${moduleId}, 1)`; + } else { + return `__webpack_require__.t(${moduleId}, 7)`; + } + } + + moduleNamespacePromise({ block, module, request, message, strict, weak }) { + if (!module) { + return this.missingModulePromise({ + request + }); + } + if (module.id === null) { + throw new Error( + `RuntimeTemplate.moduleNamespacePromise(): Module ${module.identifier()} has no id. This should not happen.` + ); + } + const promise = this.blockPromise({ + block, + message + }); + + let getModuleFunction; + let idExpr = JSON.stringify(module.id); + const comment = this.comment({ + request + }); + let header = ""; + if (weak) { + if (idExpr.length > 8) { + // 'var x="nnnnnn";x,"+x+",x' vs '"nnnnnn",nnnnnn,"nnnnnn"' + header += `var id = ${idExpr}; `; + idExpr = "id"; + } + header += `if(!__webpack_require__.m[${idExpr}]) { var e = new Error("Module '" + ${idExpr} + "' is not available (weak dependency)"); e.code = 'MODULE_NOT_FOUND'; throw e; } `; + } + const moduleId = this.moduleId({ + module, + request + }); + const exportsType = module.buildMeta && module.buildMeta.exportsType; + if (exportsType === "namespace") { + if (header) { + const rawModule = this.moduleRaw({ + module, + request + }); + getModuleFunction = `function() { ${header}return ${rawModule}; }`; + } else { + getModuleFunction = `__webpack_require__.bind(null, ${comment}${idExpr})`; + } + } else if (exportsType === "named") { + if (header) { + getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 3); }`; + } else { + getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 3)`; + } + } else if (strict) { + if (header) { + getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 1); }`; + } else { + getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 1)`; + } + } else { + if (header) { + getModuleFunction = `function() { ${header}return __webpack_require__.t(${moduleId}, 7); }`; + } else { + getModuleFunction = `__webpack_require__.t.bind(null, ${comment}${idExpr}, 7)`; + } + } + + return `${promise || "Promise.resolve()"}.then(${getModuleFunction})`; + } + + /** + * + * @param {Object} options options object + * @param {boolean=} options.update whether a new variable should be created or the existing one updated + * @param {Module} options.module the module + * @param {string} options.request the request that should be printed as comment + * @param {string} options.importVar name of the import variable + * @param {Module} options.originModule module in which the statement is emitted + * @returns {string} the import statement + */ + importStatement({ update, module, request, importVar, originModule }) { + if (!module) { + return this.missingModuleStatement({ + request + }); + } + const moduleId = this.moduleId({ + module, + request + }); + const optDeclaration = update ? "" : "var "; + + const exportsType = module.buildMeta && module.buildMeta.exportsType; + let content = `/* harmony import */ ${optDeclaration}${importVar} = __webpack_require__(${moduleId});\n`; + + if (!exportsType && !originModule.buildMeta.strictHarmonyModule) { + content += `/* harmony import */ ${optDeclaration}${importVar}_default = /*#__PURE__*/__webpack_require__.n(${importVar});\n`; + } + if (exportsType === "named") { + if (Array.isArray(module.buildMeta.providedExports)) { + content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/__webpack_require__.t(${moduleId}, 1);\n`; + } else { + content += `${optDeclaration}${importVar}_namespace = /*#__PURE__*/__webpack_require__.t(${moduleId});\n`; + } + } + return content; + } + + exportFromImport({ + module, + request, + exportName, + originModule, + asiSafe, + isCall, + callContext, + importVar + }) { + if (!module) { + return this.missingModule({ + request + }); + } + const exportsType = module.buildMeta && module.buildMeta.exportsType; + + if (!exportsType) { + if (exportName === "default") { + if (!originModule.buildMeta.strictHarmonyModule) { + if (isCall) { + return `${importVar}_default()`; + } else if (asiSafe) { + return `(${importVar}_default())`; + } else { + return `${importVar}_default.a`; + } + } else { + return importVar; + } + } else if (originModule.buildMeta.strictHarmonyModule) { + if (exportName) { + return "/* non-default import from non-esm module */undefined"; + } else { + return `/*#__PURE__*/__webpack_require__.t(${importVar})`; + } + } + } + + if (exportsType === "named") { + if (exportName === "default") { + return importVar; + } else if (!exportName) { + return `${importVar}_namespace`; + } + } + + if (exportName) { + const used = module.isUsed(exportName); + if (!used) { + const comment = Template.toNormalComment(`unused export ${exportName}`); + return `${comment} undefined`; + } + const comment = + used !== exportName ? Template.toNormalComment(exportName) + " " : ""; + const access = `${importVar}[${comment}${JSON.stringify(used)}]`; + if (isCall) { + if (callContext === false && asiSafe) { + return `(0,${access})`; + } else if (callContext === false) { + return `Object(${access})`; + } + } + return access; + } else { + return importVar; + } + } + + blockPromise({ block, message }) { + if (!block || !block.chunkGroup || block.chunkGroup.chunks.length === 0) { + const comment = this.comment({ + message + }); + return `Promise.resolve(${comment.trim()})`; + } + const chunks = block.chunkGroup.chunks.filter( + chunk => !chunk.hasRuntime() && chunk.id !== null + ); + const comment = this.comment({ + message, + chunkName: block.chunkName, + chunkReason: block.chunkReason + }); + if (chunks.length === 1) { + const chunkId = JSON.stringify(chunks[0].id); + return `__webpack_require__.e(${comment}${chunkId})`; + } else if (chunks.length > 0) { + const requireChunkId = chunk => + `__webpack_require__.e(${JSON.stringify(chunk.id)})`; + return `Promise.all(${comment.trim()}[${chunks + .map(requireChunkId) + .join(", ")}])`; + } else { + return `Promise.resolve(${comment.trim()})`; + } + } + + onError() { + return "__webpack_require__.oe"; + } + + defineEsModuleFlagStatement({ exportsArgument }) { + return `__webpack_require__.r(${exportsArgument});\n`; + } +}; diff --git a/node_modules/webpack/lib/SetVarMainTemplatePlugin.js b/node_modules/webpack/lib/SetVarMainTemplatePlugin.js new file mode 100644 index 0000000..63db282 --- /dev/null +++ b/node_modules/webpack/lib/SetVarMainTemplatePlugin.js @@ -0,0 +1,69 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +/** @typedef {import("./Compilation")} Compilation */ + +class SetVarMainTemplatePlugin { + /** + * @param {string} varExpression the accessor where the library is exported + * @param {boolean} copyObject specify copying the exports + */ + constructor(varExpression, copyObject) { + /** @type {string} */ + this.varExpression = varExpression; + /** @type {boolean} */ + this.copyObject = copyObject; + } + + /** + * @param {Compilation} compilation the compilation instance + * @returns {void} + */ + apply(compilation) { + const { mainTemplate, chunkTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + const varExpression = mainTemplate.getAssetPath(this.varExpression, { + hash, + chunk + }); + if (this.copyObject) { + return new ConcatSource( + `(function(e, a) { for(var i in a) e[i] = a[i]; }(${varExpression}, `, + source, + "))" + ); + } else { + const prefix = `${varExpression} =\n`; + return new ConcatSource(prefix, source); + } + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "SetVarMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.globalHashPaths.tap( + "SetVarMainTemplatePlugin", + paths => { + if (this.varExpression) paths.push(this.varExpression); + return paths; + } + ); + mainTemplate.hooks.hash.tap("SetVarMainTemplatePlugin", hash => { + hash.update("set var"); + hash.update(`${this.varExpression}`); + hash.update(`${this.copyObject}`); + }); + } +} + +module.exports = SetVarMainTemplatePlugin; diff --git a/node_modules/webpack/lib/SingleEntryPlugin.js b/node_modules/webpack/lib/SingleEntryPlugin.js new file mode 100644 index 0000000..4a1703b --- /dev/null +++ b/node_modules/webpack/lib/SingleEntryPlugin.js @@ -0,0 +1,63 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const SingleEntryDependency = require("./dependencies/SingleEntryDependency"); + +/** @typedef {import("./Compiler")} Compiler */ + +class SingleEntryPlugin { + /** + * An entry plugin which will handle + * creation of the SingleEntryDependency + * + * @param {string} context context path + * @param {string} entry entry path + * @param {string} name entry key name + */ + constructor(context, entry, name) { + this.context = context; + this.entry = entry; + this.name = name; + } + + /** + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "SingleEntryPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + SingleEntryDependency, + normalModuleFactory + ); + } + ); + + compiler.hooks.make.tapAsync( + "SingleEntryPlugin", + (compilation, callback) => { + const { entry, name, context } = this; + + const dep = SingleEntryPlugin.createDependency(entry, name); + compilation.addEntry(context, dep, name, callback); + } + ); + } + + /** + * @param {string} entry entry request + * @param {string} name entry name + * @returns {SingleEntryDependency} the dependency + */ + static createDependency(entry, name) { + const dep = new SingleEntryDependency(entry); + dep.loc = { name }; + return dep; + } +} + +module.exports = SingleEntryPlugin; diff --git a/node_modules/webpack/lib/SizeFormatHelpers.js b/node_modules/webpack/lib/SizeFormatHelpers.js new file mode 100644 index 0000000..c4677f6 --- /dev/null +++ b/node_modules/webpack/lib/SizeFormatHelpers.js @@ -0,0 +1,24 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; + +const SizeFormatHelpers = exports; + +SizeFormatHelpers.formatSize = size => { + if (typeof size !== "number" || Number.isNaN(size) === true) { + return "unknown size"; + } + + if (size <= 0) { + return "0 bytes"; + } + + const abbreviations = ["bytes", "KiB", "MiB", "GiB"]; + const index = Math.floor(Math.log(size) / Math.log(1024)); + + return `${+(size / Math.pow(1024, index)).toPrecision(3)} ${ + abbreviations[index] + }`; +}; diff --git a/node_modules/webpack/lib/SourceMapDevToolModuleOptionsPlugin.js b/node_modules/webpack/lib/SourceMapDevToolModuleOptionsPlugin.js new file mode 100644 index 0000000..e593ced --- /dev/null +++ b/node_modules/webpack/lib/SourceMapDevToolModuleOptionsPlugin.js @@ -0,0 +1,49 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); + +class SourceMapDevToolModuleOptionsPlugin { + constructor(options) { + this.options = options; + } + + apply(compilation) { + const options = this.options; + if (options.module !== false) { + compilation.hooks.buildModule.tap( + "SourceMapDevToolModuleOptionsPlugin", + module => { + module.useSourceMap = true; + } + ); + } + if (options.lineToLine === true) { + compilation.hooks.buildModule.tap( + "SourceMapDevToolModuleOptionsPlugin", + module => { + module.lineToLine = true; + } + ); + } else if (options.lineToLine) { + compilation.hooks.buildModule.tap( + "SourceMapDevToolModuleOptionsPlugin", + module => { + if (!module.resource) return; + let resourcePath = module.resource; + const idx = resourcePath.indexOf("?"); + if (idx >= 0) resourcePath = resourcePath.substr(0, idx); + module.lineToLine = ModuleFilenameHelpers.matchObject( + options.lineToLine, + resourcePath + ); + } + ); + } + } +} + +module.exports = SourceMapDevToolModuleOptionsPlugin; diff --git a/node_modules/webpack/lib/SourceMapDevToolPlugin.js b/node_modules/webpack/lib/SourceMapDevToolPlugin.js new file mode 100644 index 0000000..3018eb2 --- /dev/null +++ b/node_modules/webpack/lib/SourceMapDevToolPlugin.js @@ -0,0 +1,418 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const { ConcatSource, RawSource } = require("webpack-sources"); +const ModuleFilenameHelpers = require("./ModuleFilenameHelpers"); +const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOptionsPlugin"); +const createHash = require("./util/createHash"); +const { absolutify } = require("./util/identifier"); + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/SourceMapDevToolPlugin.json"); + +/** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("source-map").RawSourceMap} SourceMap */ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Compilation")} Compilation */ +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./Compilation")} SourceMapDefinition */ + +/** + * @typedef {object} SourceMapTask + * @property {Source} asset + * @property {Array<string | Module>} [modules] + * @property {string} source + * @property {string} file + * @property {SourceMap} sourceMap + * @property {Chunk} chunk + */ + +/** + * @param {string} name file path + * @returns {string} file name + */ +const basename = name => { + if (!name.includes("/")) return name; + return name.substr(name.lastIndexOf("/") + 1); +}; + +/** + * @type {WeakMap<Source, {file: string, assets: {[k: string]: ConcatSource | RawSource}}>} + */ +const assetsCache = new WeakMap(); + +/** + * Creating {@link SourceMapTask} for given file + * @param {string} file current compiled file + * @param {Source} asset the asset + * @param {Chunk} chunk related chunk + * @param {SourceMapDevToolPluginOptions} options source map options + * @param {Compilation} compilation compilation instance + * @returns {SourceMapTask | undefined} created task instance or `undefined` + */ +const getTaskForFile = (file, asset, chunk, options, compilation) => { + let source, sourceMap; + /** + * Check if asset can build source map + */ + if (asset.sourceAndMap) { + const sourceAndMap = asset.sourceAndMap(options); + sourceMap = sourceAndMap.map; + source = sourceAndMap.source; + } else { + sourceMap = asset.map(options); + source = asset.source(); + } + if (!sourceMap || typeof source !== "string") return; + const context = compilation.options.context; + const modules = sourceMap.sources.map(source => { + if (source.startsWith("webpack://")) { + source = absolutify(context, source.slice(10)); + } + const module = compilation.findModule(source); + return module || source; + }); + + return { + chunk, + file, + asset, + source, + sourceMap, + modules + }; +}; + +class SourceMapDevToolPlugin { + /** + * @param {SourceMapDevToolPluginOptions} [options] options object + * @throws {Error} throws error, if got more than 1 arguments + */ + constructor(options) { + if (arguments.length > 1) { + throw new Error( + "SourceMapDevToolPlugin only takes one argument (pass an options object)" + ); + } + + if (!options) options = {}; + + validateOptions(schema, options, "SourceMap DevTool Plugin"); + + /** @type {string | false} */ + this.sourceMapFilename = options.filename; + /** @type {string | false} */ + this.sourceMappingURLComment = + options.append === false + ? false + : options.append || "\n//# sourceMappingURL=[url]"; + /** @type {string | Function} */ + this.moduleFilenameTemplate = + options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]"; + /** @type {string | Function} */ + this.fallbackModuleFilenameTemplate = + options.fallbackModuleFilenameTemplate || + "webpack://[namespace]/[resourcePath]?[hash]"; + /** @type {string} */ + this.namespace = options.namespace || ""; + /** @type {SourceMapDevToolPluginOptions} */ + this.options = options; + } + + /** + * Apply compiler + * @param {Compiler} compiler compiler instance + * @returns {void} + */ + apply(compiler) { + const sourceMapFilename = this.sourceMapFilename; + const sourceMappingURLComment = this.sourceMappingURLComment; + const moduleFilenameTemplate = this.moduleFilenameTemplate; + const namespace = this.namespace; + const fallbackModuleFilenameTemplate = this.fallbackModuleFilenameTemplate; + const requestShortener = compiler.requestShortener; + const options = this.options; + options.test = options.test || /\.(m?js|css)($|\?)/i; + + const matchObject = ModuleFilenameHelpers.matchObject.bind( + undefined, + options + ); + + compiler.hooks.compilation.tap("SourceMapDevToolPlugin", compilation => { + new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation); + + compilation.hooks.afterOptimizeChunkAssets.tap( + /** @type {TODO} */ + ({ name: "SourceMapDevToolPlugin", context: true }), + /** + * @param {object} context hook context + * @param {Array<Chunk>} chunks resulted chunks + * @throws {Error} throws error, if `sourceMapFilename === false && sourceMappingURLComment === false` + * @returns {void} + */ + (context, chunks) => { + /** @type {Map<string | Module, string>} */ + const moduleToSourceNameMapping = new Map(); + /** + * @type {Function} + * @returns {void} + */ + const reportProgress = + context && context.reportProgress + ? context.reportProgress + : () => {}; + + const files = []; + for (const chunk of chunks) { + for (const file of chunk.files) { + if (matchObject(file)) { + files.push({ + file, + chunk + }); + } + } + } + + reportProgress(0.0); + const tasks = []; + files.forEach(({ file, chunk }, idx) => { + const asset = compilation.getAsset(file).source; + const cache = assetsCache.get(asset); + /** + * If presented in cache, reassigns assets. Cache assets already have source maps. + */ + if (cache && cache.file === file) { + for (const cachedFile in cache.assets) { + if (cachedFile === file) { + compilation.updateAsset(cachedFile, cache.assets[cachedFile]); + } else { + compilation.emitAsset(cachedFile, cache.assets[cachedFile], { + development: true + }); + } + /** + * Add file to chunk, if not presented there + */ + if (cachedFile !== file) chunk.files.push(cachedFile); + } + return; + } + + reportProgress( + (0.5 * idx) / files.length, + file, + "generate SourceMap" + ); + /** @type {SourceMapTask | undefined} */ + const task = getTaskForFile( + file, + asset, + chunk, + options, + compilation + ); + + if (task) { + const modules = task.modules; + + for (let idx = 0; idx < modules.length; idx++) { + const module = modules[idx]; + if (!moduleToSourceNameMapping.get(module)) { + moduleToSourceNameMapping.set( + module, + ModuleFilenameHelpers.createFilename( + module, + { + moduleFilenameTemplate: moduleFilenameTemplate, + namespace: namespace + }, + requestShortener + ) + ); + } + } + + tasks.push(task); + } + }); + + reportProgress(0.5, "resolve sources"); + /** @type {Set<string>} */ + const usedNamesSet = new Set(moduleToSourceNameMapping.values()); + /** @type {Set<string>} */ + const conflictDetectionSet = new Set(); + + /** + * all modules in defined order (longest identifier first) + * @type {Array<string | Module>} + */ + const allModules = Array.from(moduleToSourceNameMapping.keys()).sort( + (a, b) => { + const ai = typeof a === "string" ? a : a.identifier(); + const bi = typeof b === "string" ? b : b.identifier(); + return ai.length - bi.length; + } + ); + + // find modules with conflicting source names + for (let idx = 0; idx < allModules.length; idx++) { + const module = allModules[idx]; + let sourceName = moduleToSourceNameMapping.get(module); + let hasName = conflictDetectionSet.has(sourceName); + if (!hasName) { + conflictDetectionSet.add(sourceName); + continue; + } + + // try the fallback name first + sourceName = ModuleFilenameHelpers.createFilename( + module, + { + moduleFilenameTemplate: fallbackModuleFilenameTemplate, + namespace: namespace + }, + requestShortener + ); + hasName = usedNamesSet.has(sourceName); + if (!hasName) { + moduleToSourceNameMapping.set(module, sourceName); + usedNamesSet.add(sourceName); + continue; + } + + // elsewise just append stars until we have a valid name + while (hasName) { + sourceName += "*"; + hasName = usedNamesSet.has(sourceName); + } + moduleToSourceNameMapping.set(module, sourceName); + usedNamesSet.add(sourceName); + } + tasks.forEach((task, index) => { + reportProgress( + 0.5 + (0.5 * index) / tasks.length, + task.file, + "attach SourceMap" + ); + const assets = Object.create(null); + const chunk = task.chunk; + const file = task.file; + const asset = task.asset; + const sourceMap = task.sourceMap; + const source = task.source; + const modules = task.modules; + const moduleFilenames = modules.map(m => + moduleToSourceNameMapping.get(m) + ); + sourceMap.sources = moduleFilenames; + if (options.noSources) { + sourceMap.sourcesContent = undefined; + } + sourceMap.sourceRoot = options.sourceRoot || ""; + sourceMap.file = file; + assetsCache.set(asset, { file, assets }); + /** @type {string | false} */ + let currentSourceMappingURLComment = sourceMappingURLComment; + if ( + currentSourceMappingURLComment !== false && + /\.css($|\?)/i.test(file) + ) { + currentSourceMappingURLComment = currentSourceMappingURLComment.replace( + /^\n\/\/(.*)$/, + "\n/*$1*/" + ); + } + const sourceMapString = JSON.stringify(sourceMap); + if (sourceMapFilename) { + let filename = file; + let query = ""; + const idx = filename.indexOf("?"); + if (idx >= 0) { + query = filename.substr(idx); + filename = filename.substr(0, idx); + } + const pathParams = { + chunk, + filename: options.fileContext + ? path.relative(options.fileContext, filename) + : filename, + query, + basename: basename(filename), + contentHash: createHash("md4") + .update(sourceMapString) + .digest("hex") + }; + let sourceMapFile = compilation.getPath( + sourceMapFilename, + pathParams + ); + const sourceMapUrl = options.publicPath + ? options.publicPath + sourceMapFile.replace(/\\/g, "/") + : path + .relative(path.dirname(file), sourceMapFile) + .replace(/\\/g, "/"); + /** + * Add source map url to compilation asset, if {@link currentSourceMappingURLComment} presented + */ + if (currentSourceMappingURLComment !== false) { + const asset = new ConcatSource( + new RawSource(source), + compilation.getPath( + currentSourceMappingURLComment, + Object.assign({ url: sourceMapUrl }, pathParams) + ) + ); + assets[file] = asset; + compilation.updateAsset(file, asset); + } + /** + * Add source map file to compilation assets and chunk files + */ + const asset = new RawSource(sourceMapString); + assets[sourceMapFile] = asset; + compilation.emitAsset(sourceMapFile, asset, { + development: true + }); + chunk.files.push(sourceMapFile); + } else { + if (currentSourceMappingURLComment === false) { + throw new Error( + "SourceMapDevToolPlugin: append can't be false when no filename is provided" + ); + } + /** + * Add source map as data url to asset + */ + const asset = new ConcatSource( + new RawSource(source), + currentSourceMappingURLComment + .replace(/\[map\]/g, () => sourceMapString) + .replace( + /\[url\]/g, + () => + `data:application/json;charset=utf-8;base64,${Buffer.from( + sourceMapString, + "utf-8" + ).toString("base64")}` + ) + ); + assets[file] = asset; + compilation.updateAsset(file, asset); + } + }); + reportProgress(1.0); + } + ); + }); + } +} + +module.exports = SourceMapDevToolPlugin; diff --git a/node_modules/webpack/lib/Stats.js b/node_modules/webpack/lib/Stats.js new file mode 100644 index 0000000..6c5c338 --- /dev/null +++ b/node_modules/webpack/lib/Stats.js @@ -0,0 +1,1685 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequestShortener = require("./RequestShortener"); +const SizeFormatHelpers = require("./SizeFormatHelpers"); +const formatLocation = require("./formatLocation"); +const identifierUtils = require("./util/identifier"); +const compareLocations = require("./compareLocations"); +const { LogType } = require("./logging/Logger"); + +const optionsOrFallback = (...args) => { + let optionValues = []; + optionValues.push(...args); + return optionValues.find(optionValue => optionValue !== undefined); +}; + +const compareId = (a, b) => { + if (typeof a !== typeof b) { + return typeof a < typeof b ? -1 : 1; + } + if (a < b) return -1; + if (a > b) return 1; + return 0; +}; + +class Stats { + constructor(compilation) { + this.compilation = compilation; + this.hash = compilation.hash; + this.startTime = undefined; + this.endTime = undefined; + } + + static filterWarnings(warnings, warningsFilter) { + // we dont have anything to filter so all warnings can be shown + if (!warningsFilter) { + return warnings; + } + + // create a chain of filters + // if they return "true" a warning should be suppressed + const normalizedWarningsFilters = [].concat(warningsFilter).map(filter => { + if (typeof filter === "string") { + return warning => warning.includes(filter); + } + + if (filter instanceof RegExp) { + return warning => filter.test(warning); + } + + if (typeof filter === "function") { + return filter; + } + + throw new Error( + `Can only filter warnings with Strings or RegExps. (Given: ${filter})` + ); + }); + return warnings.filter(warning => { + return !normalizedWarningsFilters.some(check => check(warning)); + }); + } + + formatFilePath(filePath) { + const OPTIONS_REGEXP = /^(\s|\S)*!/; + return filePath.includes("!") + ? `${filePath.replace(OPTIONS_REGEXP, "")} (${filePath})` + : `${filePath}`; + } + + hasWarnings() { + return ( + this.compilation.warnings.length > 0 || + this.compilation.children.some(child => child.getStats().hasWarnings()) + ); + } + + hasErrors() { + return ( + this.compilation.errors.length > 0 || + this.compilation.children.some(child => child.getStats().hasErrors()) + ); + } + + // remove a prefixed "!" that can be specified to reverse sort order + normalizeFieldKey(field) { + if (field[0] === "!") { + return field.substr(1); + } + return field; + } + + // if a field is prefixed by a "!" reverse sort order + sortOrderRegular(field) { + if (field[0] === "!") { + return false; + } + return true; + } + + toJson(options, forToString) { + if (typeof options === "boolean" || typeof options === "string") { + options = Stats.presetToOptions(options); + } else if (!options) { + options = {}; + } + + const optionOrLocalFallback = (v, def) => + v !== undefined ? v : options.all !== undefined ? options.all : def; + + const testAgainstGivenOption = item => { + if (typeof item === "string") { + const regExp = new RegExp( + `[\\\\/]${item.replace( + // eslint-disable-next-line no-useless-escape + /[-[\]{}()*+?.\\^$|]/g, + "\\$&" + )}([\\\\/]|$|!|\\?)` + ); + return ident => regExp.test(ident); + } + if (item && typeof item === "object" && typeof item.test === "function") { + return ident => item.test(ident); + } + if (typeof item === "function") { + return item; + } + if (typeof item === "boolean") { + return () => item; + } + }; + + const compilation = this.compilation; + const context = optionsOrFallback( + options.context, + compilation.compiler.context + ); + const requestShortener = + compilation.compiler.context === context + ? compilation.requestShortener + : new RequestShortener(context); + const showPerformance = optionOrLocalFallback(options.performance, true); + const showHash = optionOrLocalFallback(options.hash, true); + const showEnv = optionOrLocalFallback(options.env, false); + const showVersion = optionOrLocalFallback(options.version, true); + const showTimings = optionOrLocalFallback(options.timings, true); + const showBuiltAt = optionOrLocalFallback(options.builtAt, true); + const showAssets = optionOrLocalFallback(options.assets, true); + const showEntrypoints = optionOrLocalFallback(options.entrypoints, true); + const showChunkGroups = optionOrLocalFallback( + options.chunkGroups, + !forToString + ); + const showChunks = optionOrLocalFallback(options.chunks, !forToString); + const showChunkModules = optionOrLocalFallback(options.chunkModules, true); + const showChunkOrigins = optionOrLocalFallback( + options.chunkOrigins, + !forToString + ); + const showModules = optionOrLocalFallback(options.modules, true); + const showNestedModules = optionOrLocalFallback( + options.nestedModules, + true + ); + const showModuleAssets = optionOrLocalFallback( + options.moduleAssets, + !forToString + ); + const showDepth = optionOrLocalFallback(options.depth, !forToString); + const showCachedModules = optionOrLocalFallback(options.cached, true); + const showCachedAssets = optionOrLocalFallback(options.cachedAssets, true); + const showReasons = optionOrLocalFallback(options.reasons, !forToString); + const showUsedExports = optionOrLocalFallback( + options.usedExports, + !forToString + ); + const showProvidedExports = optionOrLocalFallback( + options.providedExports, + !forToString + ); + const showOptimizationBailout = optionOrLocalFallback( + options.optimizationBailout, + !forToString + ); + const showChildren = optionOrLocalFallback(options.children, true); + const showSource = optionOrLocalFallback(options.source, !forToString); + const showModuleTrace = optionOrLocalFallback(options.moduleTrace, true); + const showErrors = optionOrLocalFallback(options.errors, true); + const showErrorDetails = optionOrLocalFallback( + options.errorDetails, + !forToString + ); + const showWarnings = optionOrLocalFallback(options.warnings, true); + const warningsFilter = optionsOrFallback(options.warningsFilter, null); + const showPublicPath = optionOrLocalFallback( + options.publicPath, + !forToString + ); + const showLogging = optionOrLocalFallback( + options.logging, + forToString ? "info" : true + ); + const showLoggingTrace = optionOrLocalFallback( + options.loggingTrace, + !forToString + ); + const loggingDebug = [] + .concat(optionsOrFallback(options.loggingDebug, [])) + .map(testAgainstGivenOption); + + const excludeModules = [] + .concat(optionsOrFallback(options.excludeModules, options.exclude, [])) + .map(testAgainstGivenOption); + const excludeAssets = [] + .concat(optionsOrFallback(options.excludeAssets, [])) + .map(testAgainstGivenOption); + const maxModules = optionsOrFallback( + options.maxModules, + forToString ? 15 : Infinity + ); + const sortModules = optionsOrFallback(options.modulesSort, "id"); + const sortChunks = optionsOrFallback(options.chunksSort, "id"); + const sortAssets = optionsOrFallback(options.assetsSort, ""); + const showOutputPath = optionOrLocalFallback( + options.outputPath, + !forToString + ); + + if (!showCachedModules) { + excludeModules.push((ident, module) => !module.built); + } + + const createModuleFilter = () => { + let i = 0; + return module => { + if (excludeModules.length > 0) { + const ident = requestShortener.shorten(module.resource); + const excluded = excludeModules.some(fn => fn(ident, module)); + if (excluded) return false; + } + const result = i < maxModules; + i++; + return result; + }; + }; + + const createAssetFilter = () => { + return asset => { + if (excludeAssets.length > 0) { + const ident = asset.name; + const excluded = excludeAssets.some(fn => fn(ident, asset)); + if (excluded) return false; + } + return showCachedAssets || asset.emitted; + }; + }; + + const sortByFieldAndOrder = (fieldKey, a, b) => { + if (a[fieldKey] === null && b[fieldKey] === null) return 0; + if (a[fieldKey] === null) return 1; + if (b[fieldKey] === null) return -1; + if (a[fieldKey] === b[fieldKey]) return 0; + if (typeof a[fieldKey] !== typeof b[fieldKey]) + return typeof a[fieldKey] < typeof b[fieldKey] ? -1 : 1; + return a[fieldKey] < b[fieldKey] ? -1 : 1; + }; + + const sortByField = (field, originalArray) => { + const originalMap = originalArray.reduce((map, v, i) => { + map.set(v, i); + return map; + }, new Map()); + return (a, b) => { + if (field) { + const fieldKey = this.normalizeFieldKey(field); + + // if a field is prefixed with a "!" the sort is reversed! + const sortIsRegular = this.sortOrderRegular(field); + + const cmp = sortByFieldAndOrder( + fieldKey, + sortIsRegular ? a : b, + sortIsRegular ? b : a + ); + if (cmp) return cmp; + } + return originalMap.get(a) - originalMap.get(b); + }; + }; + + const formatError = e => { + let text = ""; + if (typeof e === "string") { + e = { message: e }; + } + if (e.chunk) { + text += `chunk ${e.chunk.name || e.chunk.id}${ + e.chunk.hasRuntime() + ? " [entry]" + : e.chunk.canBeInitial() + ? " [initial]" + : "" + }\n`; + } + if (e.file) { + text += `${e.file}\n`; + } + if ( + e.module && + e.module.readableIdentifier && + typeof e.module.readableIdentifier === "function" + ) { + text += this.formatFilePath( + e.module.readableIdentifier(requestShortener) + ); + if (typeof e.loc === "object") { + const locInfo = formatLocation(e.loc); + if (locInfo) text += ` ${locInfo}`; + } + text += "\n"; + } + text += e.message; + if (showErrorDetails && e.details) { + text += `\n${e.details}`; + } + if (showErrorDetails && e.missing) { + text += e.missing.map(item => `\n[${item}]`).join(""); + } + if (showModuleTrace && e.origin) { + text += `\n @ ${this.formatFilePath( + e.origin.readableIdentifier(requestShortener) + )}`; + if (typeof e.originLoc === "object") { + const locInfo = formatLocation(e.originLoc); + if (locInfo) text += ` ${locInfo}`; + } + if (e.dependencies) { + for (const dep of e.dependencies) { + if (!dep.loc) continue; + if (typeof dep.loc === "string") continue; + const locInfo = formatLocation(dep.loc); + if (!locInfo) continue; + text += ` ${locInfo}`; + } + } + let current = e.origin; + while (current.issuer) { + current = current.issuer; + text += `\n @ ${current.readableIdentifier(requestShortener)}`; + } + } + return text; + }; + + const obj = { + errors: compilation.errors.map(formatError), + warnings: Stats.filterWarnings( + compilation.warnings.map(formatError), + warningsFilter + ) + }; + + //We just hint other renderers since actually omitting + //errors/warnings from the JSON would be kind of weird. + Object.defineProperty(obj, "_showWarnings", { + value: showWarnings, + enumerable: false + }); + Object.defineProperty(obj, "_showErrors", { + value: showErrors, + enumerable: false + }); + + if (showVersion) { + obj.version = require("../package.json").version; + } + + if (showHash) obj.hash = this.hash; + if (showTimings && this.startTime && this.endTime) { + obj.time = this.endTime - this.startTime; + } + + if (showBuiltAt && this.endTime) { + obj.builtAt = this.endTime; + } + + if (showEnv && options._env) { + obj.env = options._env; + } + + if (compilation.needAdditionalPass) { + obj.needAdditionalPass = true; + } + if (showPublicPath) { + obj.publicPath = this.compilation.mainTemplate.getPublicPath({ + hash: this.compilation.hash + }); + } + if (showOutputPath) { + obj.outputPath = this.compilation.mainTemplate.outputOptions.path; + } + if (showAssets) { + const assetsByFile = {}; + const compilationAssets = compilation + .getAssets() + .sort((a, b) => (a.name < b.name ? -1 : 1)); + obj.assetsByChunkName = {}; + obj.assets = compilationAssets + .map(({ name, source, info }) => { + const obj = { + name, + size: source.size(), + chunks: [], + chunkNames: [], + info, + // TODO webpack 5: remove .emitted + emitted: source.emitted || compilation.emittedAssets.has(name) + }; + + if (showPerformance) { + obj.isOverSizeLimit = source.isOverSizeLimit; + } + + assetsByFile[name] = obj; + return obj; + }) + .filter(createAssetFilter()); + obj.filteredAssets = compilationAssets.length - obj.assets.length; + + for (const chunk of compilation.chunks) { + for (const asset of chunk.files) { + if (assetsByFile[asset]) { + for (const id of chunk.ids) { + assetsByFile[asset].chunks.push(id); + } + if (chunk.name) { + assetsByFile[asset].chunkNames.push(chunk.name); + if (obj.assetsByChunkName[chunk.name]) { + obj.assetsByChunkName[chunk.name] = [] + .concat(obj.assetsByChunkName[chunk.name]) + .concat([asset]); + } else { + obj.assetsByChunkName[chunk.name] = asset; + } + } + } + } + } + obj.assets.sort(sortByField(sortAssets, obj.assets)); + } + + const fnChunkGroup = groupMap => { + const obj = {}; + for (const keyValuePair of groupMap) { + const name = keyValuePair[0]; + const cg = keyValuePair[1]; + const children = cg.getChildrenByOrders(); + obj[name] = { + chunks: cg.chunks.map(c => c.id), + assets: cg.chunks.reduce( + (array, c) => array.concat(c.files || []), + [] + ), + children: Object.keys(children).reduce((obj, key) => { + const groups = children[key]; + obj[key] = groups.map(group => ({ + name: group.name, + chunks: group.chunks.map(c => c.id), + assets: group.chunks.reduce( + (array, c) => array.concat(c.files || []), + [] + ) + })); + return obj; + }, Object.create(null)), + childAssets: Object.keys(children).reduce((obj, key) => { + const groups = children[key]; + obj[key] = Array.from( + groups.reduce((set, group) => { + for (const chunk of group.chunks) { + for (const asset of chunk.files) { + set.add(asset); + } + } + return set; + }, new Set()) + ); + return obj; + }, Object.create(null)) + }; + if (showPerformance) { + obj[name].isOverSizeLimit = cg.isOverSizeLimit; + } + } + + return obj; + }; + + if (showEntrypoints) { + obj.entrypoints = fnChunkGroup(compilation.entrypoints); + } + + if (showChunkGroups) { + obj.namedChunkGroups = fnChunkGroup(compilation.namedChunkGroups); + } + + const fnModule = module => { + const path = []; + let current = module; + while (current.issuer) { + path.push((current = current.issuer)); + } + path.reverse(); + const obj = { + id: module.id, + identifier: module.identifier(), + name: module.readableIdentifier(requestShortener), + index: module.index, + index2: module.index2, + size: module.size(), + cacheable: module.buildInfo.cacheable, + built: !!module.built, + optional: module.optional, + prefetched: module.prefetched, + chunks: Array.from(module.chunksIterable, chunk => chunk.id), + issuer: module.issuer && module.issuer.identifier(), + issuerId: module.issuer && module.issuer.id, + issuerName: + module.issuer && module.issuer.readableIdentifier(requestShortener), + issuerPath: + module.issuer && + path.map(module => ({ + id: module.id, + identifier: module.identifier(), + name: module.readableIdentifier(requestShortener), + profile: module.profile + })), + profile: module.profile, + failed: !!module.error, + errors: module.errors ? module.errors.length : 0, + warnings: module.warnings ? module.warnings.length : 0 + }; + if (showModuleAssets) { + obj.assets = Object.keys(module.buildInfo.assets || {}); + } + if (showReasons) { + obj.reasons = module.reasons + .sort((a, b) => { + if (a.module && !b.module) return -1; + if (!a.module && b.module) return 1; + if (a.module && b.module) { + const cmp = compareId(a.module.id, b.module.id); + if (cmp) return cmp; + } + if (a.dependency && !b.dependency) return -1; + if (!a.dependency && b.dependency) return 1; + if (a.dependency && b.dependency) { + const cmp = compareLocations(a.dependency.loc, b.dependency.loc); + if (cmp) return cmp; + if (a.dependency.type < b.dependency.type) return -1; + if (a.dependency.type > b.dependency.type) return 1; + } + return 0; + }) + .map(reason => { + const obj = { + moduleId: reason.module ? reason.module.id : null, + moduleIdentifier: reason.module + ? reason.module.identifier() + : null, + module: reason.module + ? reason.module.readableIdentifier(requestShortener) + : null, + moduleName: reason.module + ? reason.module.readableIdentifier(requestShortener) + : null, + type: reason.dependency ? reason.dependency.type : null, + explanation: reason.explanation, + userRequest: reason.dependency + ? reason.dependency.userRequest + : null + }; + if (reason.dependency) { + const locInfo = formatLocation(reason.dependency.loc); + if (locInfo) { + obj.loc = locInfo; + } + } + return obj; + }); + } + if (showUsedExports) { + if (module.used === true) { + obj.usedExports = module.usedExports; + } else if (module.used === false) { + obj.usedExports = false; + } + } + if (showProvidedExports) { + obj.providedExports = Array.isArray(module.buildMeta.providedExports) + ? module.buildMeta.providedExports + : null; + } + if (showOptimizationBailout) { + obj.optimizationBailout = module.optimizationBailout.map(item => { + if (typeof item === "function") return item(requestShortener); + return item; + }); + } + if (showDepth) { + obj.depth = module.depth; + } + if (showNestedModules) { + if (module.modules) { + const modules = module.modules; + obj.modules = modules + .sort(sortByField("depth", modules)) + .filter(createModuleFilter()) + .map(fnModule); + obj.filteredModules = modules.length - obj.modules.length; + obj.modules.sort(sortByField(sortModules, obj.modules)); + } + } + if (showSource && module._source) { + obj.source = module._source.source(); + } + return obj; + }; + if (showChunks) { + obj.chunks = compilation.chunks.map(chunk => { + const parents = new Set(); + const children = new Set(); + const siblings = new Set(); + const childIdByOrder = chunk.getChildIdsByOrders(); + for (const chunkGroup of chunk.groupsIterable) { + for (const parentGroup of chunkGroup.parentsIterable) { + for (const chunk of parentGroup.chunks) { + parents.add(chunk.id); + } + } + for (const childGroup of chunkGroup.childrenIterable) { + for (const chunk of childGroup.chunks) { + children.add(chunk.id); + } + } + for (const sibling of chunkGroup.chunks) { + if (sibling !== chunk) siblings.add(sibling.id); + } + } + const obj = { + id: chunk.id, + rendered: chunk.rendered, + initial: chunk.canBeInitial(), + entry: chunk.hasRuntime(), + recorded: chunk.recorded, + reason: chunk.chunkReason, + size: chunk.modulesSize(), + names: chunk.name ? [chunk.name] : [], + files: chunk.files.slice(), + hash: chunk.renderedHash, + siblings: Array.from(siblings).sort(compareId), + parents: Array.from(parents).sort(compareId), + children: Array.from(children).sort(compareId), + childrenByOrder: childIdByOrder + }; + if (showChunkModules) { + const modules = chunk.getModules(); + obj.modules = modules + .slice() + .sort(sortByField("depth", modules)) + .filter(createModuleFilter()) + .map(fnModule); + obj.filteredModules = chunk.getNumberOfModules() - obj.modules.length; + obj.modules.sort(sortByField(sortModules, obj.modules)); + } + if (showChunkOrigins) { + obj.origins = Array.from(chunk.groupsIterable, g => g.origins) + .reduce((a, b) => a.concat(b), []) + .map(origin => ({ + moduleId: origin.module ? origin.module.id : undefined, + module: origin.module ? origin.module.identifier() : "", + moduleIdentifier: origin.module ? origin.module.identifier() : "", + moduleName: origin.module + ? origin.module.readableIdentifier(requestShortener) + : "", + loc: formatLocation(origin.loc), + request: origin.request, + reasons: origin.reasons || [] + })) + .sort((a, b) => { + const cmp1 = compareId(a.moduleId, b.moduleId); + if (cmp1) return cmp1; + const cmp2 = compareId(a.loc, b.loc); + if (cmp2) return cmp2; + const cmp3 = compareId(a.request, b.request); + if (cmp3) return cmp3; + return 0; + }); + } + return obj; + }); + obj.chunks.sort(sortByField(sortChunks, obj.chunks)); + } + if (showModules) { + obj.modules = compilation.modules + .slice() + .sort(sortByField("depth", compilation.modules)) + .filter(createModuleFilter()) + .map(fnModule); + obj.filteredModules = compilation.modules.length - obj.modules.length; + obj.modules.sort(sortByField(sortModules, obj.modules)); + } + if (showLogging) { + const util = require("util"); + obj.logging = {}; + let acceptedTypes; + let collapsedGroups = false; + switch (showLogging) { + case "none": + acceptedTypes = new Set([]); + break; + case "error": + acceptedTypes = new Set([LogType.error]); + break; + case "warn": + acceptedTypes = new Set([LogType.error, LogType.warn]); + break; + case "info": + acceptedTypes = new Set([LogType.error, LogType.warn, LogType.info]); + break; + case true: + case "log": + acceptedTypes = new Set([ + LogType.error, + LogType.warn, + LogType.info, + LogType.log, + LogType.group, + LogType.groupEnd, + LogType.groupCollapsed, + LogType.clear + ]); + break; + case "verbose": + acceptedTypes = new Set([ + LogType.error, + LogType.warn, + LogType.info, + LogType.log, + LogType.group, + LogType.groupEnd, + LogType.groupCollapsed, + LogType.profile, + LogType.profileEnd, + LogType.time, + LogType.status, + LogType.clear + ]); + collapsedGroups = true; + break; + } + for (const [origin, logEntries] of compilation.logging) { + const debugMode = loggingDebug.some(fn => fn(origin)); + let collapseCounter = 0; + let processedLogEntries = logEntries; + if (!debugMode) { + processedLogEntries = processedLogEntries.filter(entry => { + if (!acceptedTypes.has(entry.type)) return false; + if (!collapsedGroups) { + switch (entry.type) { + case LogType.groupCollapsed: + collapseCounter++; + return collapseCounter === 1; + case LogType.group: + if (collapseCounter > 0) collapseCounter++; + return collapseCounter === 0; + case LogType.groupEnd: + if (collapseCounter > 0) { + collapseCounter--; + return false; + } + return true; + default: + return collapseCounter === 0; + } + } + return true; + }); + } + processedLogEntries = processedLogEntries.map(entry => { + let message = undefined; + if (entry.type === LogType.time) { + message = `${entry.args[0]}: ${entry.args[1] * 1000 + + entry.args[2] / 1000000}ms`; + } else if (entry.args && entry.args.length > 0) { + message = util.format(entry.args[0], ...entry.args.slice(1)); + } + return { + type: + (debugMode || collapsedGroups) && + entry.type === LogType.groupCollapsed + ? LogType.group + : entry.type, + message, + trace: showLoggingTrace && entry.trace ? entry.trace : undefined + }; + }); + let name = identifierUtils + .makePathsRelative(context, origin, compilation.cache) + .replace(/\|/g, " "); + if (name in obj.logging) { + let i = 1; + while (`${name}#${i}` in obj.logging) { + i++; + } + name = `${name}#${i}`; + } + obj.logging[name] = { + entries: processedLogEntries, + filteredEntries: logEntries.length - processedLogEntries.length, + debug: debugMode + }; + } + } + if (showChildren) { + obj.children = compilation.children.map((child, idx) => { + const childOptions = Stats.getChildOptions(options, idx); + const obj = new Stats(child).toJson(childOptions, forToString); + delete obj.hash; + delete obj.version; + if (child.name) { + obj.name = identifierUtils.makePathsRelative( + context, + child.name, + compilation.cache + ); + } + return obj; + }); + } + + return obj; + } + + toString(options) { + if (typeof options === "boolean" || typeof options === "string") { + options = Stats.presetToOptions(options); + } else if (!options) { + options = {}; + } + + const useColors = optionsOrFallback(options.colors, false); + + const obj = this.toJson(options, true); + + return Stats.jsonToString(obj, useColors); + } + + static jsonToString(obj, useColors) { + const buf = []; + + const defaultColors = { + bold: "\u001b[1m", + yellow: "\u001b[1m\u001b[33m", + red: "\u001b[1m\u001b[31m", + green: "\u001b[1m\u001b[32m", + cyan: "\u001b[1m\u001b[36m", + magenta: "\u001b[1m\u001b[35m" + }; + + const colors = Object.keys(defaultColors).reduce( + (obj, color) => { + obj[color] = str => { + if (useColors) { + buf.push( + useColors === true || useColors[color] === undefined + ? defaultColors[color] + : useColors[color] + ); + } + buf.push(str); + if (useColors) { + buf.push("\u001b[39m\u001b[22m"); + } + }; + return obj; + }, + { + normal: str => buf.push(str) + } + ); + + const coloredTime = time => { + let times = [800, 400, 200, 100]; + if (obj.time) { + times = [obj.time / 2, obj.time / 4, obj.time / 8, obj.time / 16]; + } + if (time < times[3]) colors.normal(`${time}ms`); + else if (time < times[2]) colors.bold(`${time}ms`); + else if (time < times[1]) colors.green(`${time}ms`); + else if (time < times[0]) colors.yellow(`${time}ms`); + else colors.red(`${time}ms`); + }; + + const newline = () => buf.push("\n"); + + const getText = (arr, row, col) => { + return arr[row][col].value; + }; + + const table = (array, align, splitter) => { + const rows = array.length; + const cols = array[0].length; + const colSizes = new Array(cols); + for (let col = 0; col < cols; col++) { + colSizes[col] = 0; + } + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const value = `${getText(array, row, col)}`; + if (value.length > colSizes[col]) { + colSizes[col] = value.length; + } + } + } + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const format = array[row][col].color; + const value = `${getText(array, row, col)}`; + let l = value.length; + if (align[col] === "l") { + format(value); + } + for (; l < colSizes[col] && col !== cols - 1; l++) { + colors.normal(" "); + } + if (align[col] === "r") { + format(value); + } + if (col + 1 < cols && colSizes[col] !== 0) { + colors.normal(splitter || " "); + } + } + newline(); + } + }; + + const getAssetColor = (asset, defaultColor) => { + if (asset.isOverSizeLimit) { + return colors.yellow; + } + + return defaultColor; + }; + + if (obj.hash) { + colors.normal("Hash: "); + colors.bold(obj.hash); + newline(); + } + if (obj.version) { + colors.normal("Version: webpack "); + colors.bold(obj.version); + newline(); + } + if (typeof obj.time === "number") { + colors.normal("Time: "); + colors.bold(obj.time); + colors.normal("ms"); + newline(); + } + if (typeof obj.builtAt === "number") { + const builtAtDate = new Date(obj.builtAt); + let timeZone = undefined; + + try { + builtAtDate.toLocaleTimeString(); + } catch (err) { + // Force UTC if runtime timezone is unsupported + timeZone = "UTC"; + } + + colors.normal("Built at: "); + colors.normal( + builtAtDate.toLocaleDateString(undefined, { + day: "2-digit", + month: "2-digit", + year: "numeric", + timeZone + }) + ); + colors.normal(" "); + colors.bold(builtAtDate.toLocaleTimeString(undefined, { timeZone })); + newline(); + } + if (obj.env) { + colors.normal("Environment (--env): "); + colors.bold(JSON.stringify(obj.env, null, 2)); + newline(); + } + if (obj.publicPath) { + colors.normal("PublicPath: "); + colors.bold(obj.publicPath); + newline(); + } + + if (obj.assets && obj.assets.length > 0) { + const t = [ + [ + { + value: "Asset", + color: colors.bold + }, + { + value: "Size", + color: colors.bold + }, + { + value: "Chunks", + color: colors.bold + }, + { + value: "", + color: colors.bold + }, + { + value: "", + color: colors.bold + }, + { + value: "Chunk Names", + color: colors.bold + } + ] + ]; + for (const asset of obj.assets) { + t.push([ + { + value: asset.name, + color: getAssetColor(asset, colors.green) + }, + { + value: SizeFormatHelpers.formatSize(asset.size), + color: getAssetColor(asset, colors.normal) + }, + { + value: asset.chunks.join(", "), + color: colors.bold + }, + { + value: [ + asset.emitted && "[emitted]", + asset.info.immutable && "[immutable]", + asset.info.development && "[dev]", + asset.info.hotModuleReplacement && "[hmr]" + ] + .filter(Boolean) + .join(" "), + color: colors.green + }, + { + value: asset.isOverSizeLimit ? "[big]" : "", + color: getAssetColor(asset, colors.normal) + }, + { + value: asset.chunkNames.join(", "), + color: colors.normal + } + ]); + } + table(t, "rrrlll"); + } + if (obj.filteredAssets > 0) { + colors.normal(" "); + if (obj.assets.length > 0) colors.normal("+ "); + colors.normal(obj.filteredAssets); + if (obj.assets.length > 0) colors.normal(" hidden"); + colors.normal(obj.filteredAssets !== 1 ? " assets" : " asset"); + newline(); + } + + const processChunkGroups = (namedGroups, prefix) => { + for (const name of Object.keys(namedGroups)) { + const cg = namedGroups[name]; + colors.normal(`${prefix} `); + colors.bold(name); + if (cg.isOverSizeLimit) { + colors.normal(" "); + colors.yellow("[big]"); + } + colors.normal(" ="); + for (const asset of cg.assets) { + colors.normal(" "); + colors.green(asset); + } + for (const name of Object.keys(cg.childAssets)) { + const assets = cg.childAssets[name]; + if (assets && assets.length > 0) { + colors.normal(" "); + colors.magenta(`(${name}:`); + for (const asset of assets) { + colors.normal(" "); + colors.green(asset); + } + colors.magenta(")"); + } + } + newline(); + } + }; + + if (obj.entrypoints) { + processChunkGroups(obj.entrypoints, "Entrypoint"); + } + + if (obj.namedChunkGroups) { + let outputChunkGroups = obj.namedChunkGroups; + if (obj.entrypoints) { + outputChunkGroups = Object.keys(outputChunkGroups) + .filter(name => !obj.entrypoints[name]) + .reduce((result, name) => { + result[name] = obj.namedChunkGroups[name]; + return result; + }, {}); + } + processChunkGroups(outputChunkGroups, "Chunk Group"); + } + + const modulesByIdentifier = {}; + if (obj.modules) { + for (const module of obj.modules) { + modulesByIdentifier[`$${module.identifier}`] = module; + } + } else if (obj.chunks) { + for (const chunk of obj.chunks) { + if (chunk.modules) { + for (const module of chunk.modules) { + modulesByIdentifier[`$${module.identifier}`] = module; + } + } + } + } + + const processModuleAttributes = module => { + colors.normal(" "); + colors.normal(SizeFormatHelpers.formatSize(module.size)); + if (module.chunks) { + for (const chunk of module.chunks) { + colors.normal(" {"); + colors.yellow(chunk); + colors.normal("}"); + } + } + if (typeof module.depth === "number") { + colors.normal(` [depth ${module.depth}]`); + } + if (module.cacheable === false) { + colors.red(" [not cacheable]"); + } + if (module.optional) { + colors.yellow(" [optional]"); + } + if (module.built) { + colors.green(" [built]"); + } + if (module.assets && module.assets.length) { + colors.magenta( + ` [${module.assets.length} asset${ + module.assets.length === 1 ? "" : "s" + }]` + ); + } + if (module.prefetched) { + colors.magenta(" [prefetched]"); + } + if (module.failed) colors.red(" [failed]"); + if (module.warnings) { + colors.yellow( + ` [${module.warnings} warning${module.warnings === 1 ? "" : "s"}]` + ); + } + if (module.errors) { + colors.red( + ` [${module.errors} error${module.errors === 1 ? "" : "s"}]` + ); + } + }; + + const processModuleContent = (module, prefix) => { + if (Array.isArray(module.providedExports)) { + colors.normal(prefix); + if (module.providedExports.length === 0) { + colors.cyan("[no exports]"); + } else { + colors.cyan(`[exports: ${module.providedExports.join(", ")}]`); + } + newline(); + } + if (module.usedExports !== undefined) { + if (module.usedExports !== true) { + colors.normal(prefix); + if (module.usedExports === null) { + colors.cyan("[used exports unknown]"); + } else if (module.usedExports === false) { + colors.cyan("[no exports used]"); + } else if ( + Array.isArray(module.usedExports) && + module.usedExports.length === 0 + ) { + colors.cyan("[no exports used]"); + } else if (Array.isArray(module.usedExports)) { + const providedExportsCount = Array.isArray(module.providedExports) + ? module.providedExports.length + : null; + if ( + providedExportsCount !== null && + providedExportsCount === module.usedExports.length + ) { + colors.cyan("[all exports used]"); + } else { + colors.cyan( + `[only some exports used: ${module.usedExports.join(", ")}]` + ); + } + } + newline(); + } + } + if (Array.isArray(module.optimizationBailout)) { + for (const item of module.optimizationBailout) { + colors.normal(prefix); + colors.yellow(item); + newline(); + } + } + if (module.reasons) { + for (const reason of module.reasons) { + colors.normal(prefix); + if (reason.type) { + colors.normal(reason.type); + colors.normal(" "); + } + if (reason.userRequest) { + colors.cyan(reason.userRequest); + colors.normal(" "); + } + if (reason.moduleId !== null) { + colors.normal("["); + colors.normal(reason.moduleId); + colors.normal("]"); + } + if (reason.module && reason.module !== reason.moduleId) { + colors.normal(" "); + colors.magenta(reason.module); + } + if (reason.loc) { + colors.normal(" "); + colors.normal(reason.loc); + } + if (reason.explanation) { + colors.normal(" "); + colors.cyan(reason.explanation); + } + newline(); + } + } + if (module.profile) { + colors.normal(prefix); + let sum = 0; + if (module.issuerPath) { + for (const m of module.issuerPath) { + colors.normal("["); + colors.normal(m.id); + colors.normal("] "); + if (m.profile) { + const time = (m.profile.factory || 0) + (m.profile.building || 0); + coloredTime(time); + sum += time; + colors.normal(" "); + } + colors.normal("-> "); + } + } + for (const key of Object.keys(module.profile)) { + colors.normal(`${key}:`); + const time = module.profile[key]; + coloredTime(time); + colors.normal(" "); + sum += time; + } + colors.normal("= "); + coloredTime(sum); + newline(); + } + if (module.modules) { + processModulesList(module, prefix + "| "); + } + }; + + const processModulesList = (obj, prefix) => { + if (obj.modules) { + let maxModuleId = 0; + for (const module of obj.modules) { + if (typeof module.id === "number") { + if (maxModuleId < module.id) maxModuleId = module.id; + } + } + let contentPrefix = prefix + " "; + if (maxModuleId >= 10) contentPrefix += " "; + if (maxModuleId >= 100) contentPrefix += " "; + if (maxModuleId >= 1000) contentPrefix += " "; + for (const module of obj.modules) { + colors.normal(prefix); + const name = module.name || module.identifier; + if (typeof module.id === "string" || typeof module.id === "number") { + if (typeof module.id === "number") { + if (module.id < 1000 && maxModuleId >= 1000) colors.normal(" "); + if (module.id < 100 && maxModuleId >= 100) colors.normal(" "); + if (module.id < 10 && maxModuleId >= 10) colors.normal(" "); + } else { + if (maxModuleId >= 1000) colors.normal(" "); + if (maxModuleId >= 100) colors.normal(" "); + if (maxModuleId >= 10) colors.normal(" "); + } + if (name !== module.id) { + colors.normal("["); + colors.normal(module.id); + colors.normal("]"); + colors.normal(" "); + } else { + colors.normal("["); + colors.bold(module.id); + colors.normal("]"); + } + } + if (name !== module.id) { + colors.bold(name); + } + processModuleAttributes(module); + newline(); + processModuleContent(module, contentPrefix); + } + if (obj.filteredModules > 0) { + colors.normal(prefix); + colors.normal(" "); + if (obj.modules.length > 0) colors.normal(" + "); + colors.normal(obj.filteredModules); + if (obj.modules.length > 0) colors.normal(" hidden"); + colors.normal(obj.filteredModules !== 1 ? " modules" : " module"); + newline(); + } + } + }; + + if (obj.chunks) { + for (const chunk of obj.chunks) { + colors.normal("chunk "); + if (chunk.id < 1000) colors.normal(" "); + if (chunk.id < 100) colors.normal(" "); + if (chunk.id < 10) colors.normal(" "); + colors.normal("{"); + colors.yellow(chunk.id); + colors.normal("} "); + colors.green(chunk.files.join(", ")); + if (chunk.names && chunk.names.length > 0) { + colors.normal(" ("); + colors.normal(chunk.names.join(", ")); + colors.normal(")"); + } + colors.normal(" "); + colors.normal(SizeFormatHelpers.formatSize(chunk.size)); + for (const id of chunk.parents) { + colors.normal(" <{"); + colors.yellow(id); + colors.normal("}>"); + } + for (const id of chunk.siblings) { + colors.normal(" ={"); + colors.yellow(id); + colors.normal("}="); + } + for (const id of chunk.children) { + colors.normal(" >{"); + colors.yellow(id); + colors.normal("}<"); + } + if (chunk.childrenByOrder) { + for (const name of Object.keys(chunk.childrenByOrder)) { + const children = chunk.childrenByOrder[name]; + colors.normal(" "); + colors.magenta(`(${name}:`); + for (const id of children) { + colors.normal(" {"); + colors.yellow(id); + colors.normal("}"); + } + colors.magenta(")"); + } + } + if (chunk.entry) { + colors.yellow(" [entry]"); + } else if (chunk.initial) { + colors.yellow(" [initial]"); + } + if (chunk.rendered) { + colors.green(" [rendered]"); + } + if (chunk.recorded) { + colors.green(" [recorded]"); + } + if (chunk.reason) { + colors.yellow(` ${chunk.reason}`); + } + newline(); + if (chunk.origins) { + for (const origin of chunk.origins) { + colors.normal(" > "); + if (origin.reasons && origin.reasons.length) { + colors.yellow(origin.reasons.join(" ")); + colors.normal(" "); + } + if (origin.request) { + colors.normal(origin.request); + colors.normal(" "); + } + if (origin.module) { + colors.normal("["); + colors.normal(origin.moduleId); + colors.normal("] "); + const module = modulesByIdentifier[`$${origin.module}`]; + if (module) { + colors.bold(module.name); + colors.normal(" "); + } + } + if (origin.loc) { + colors.normal(origin.loc); + } + newline(); + } + } + processModulesList(chunk, " "); + } + } + + processModulesList(obj, ""); + + if (obj.logging) { + for (const origin of Object.keys(obj.logging)) { + const logData = obj.logging[origin]; + if (logData.entries.length > 0) { + newline(); + if (logData.debug) { + colors.red("DEBUG "); + } + colors.bold("LOG from " + origin); + newline(); + let indent = ""; + for (const entry of logData.entries) { + let color = colors.normal; + let prefix = " "; + switch (entry.type) { + case LogType.clear: + colors.normal(`${indent}-------`); + newline(); + continue; + case LogType.error: + color = colors.red; + prefix = "<e> "; + break; + case LogType.warn: + color = colors.yellow; + prefix = "<w> "; + break; + case LogType.info: + color = colors.green; + prefix = "<i> "; + break; + case LogType.log: + color = colors.bold; + break; + case LogType.trace: + case LogType.debug: + color = colors.normal; + break; + case LogType.status: + color = colors.magenta; + prefix = "<s> "; + break; + case LogType.profile: + color = colors.magenta; + prefix = "<p> "; + break; + case LogType.profileEnd: + color = colors.magenta; + prefix = "</p> "; + break; + case LogType.time: + color = colors.magenta; + prefix = "<t> "; + break; + case LogType.group: + color = colors.cyan; + prefix = "<-> "; + break; + case LogType.groupCollapsed: + color = colors.cyan; + prefix = "<+> "; + break; + case LogType.groupEnd: + if (indent.length >= 2) + indent = indent.slice(0, indent.length - 2); + continue; + } + if (entry.message) { + for (const line of entry.message.split("\n")) { + colors.normal(`${indent}${prefix}`); + color(line); + newline(); + } + } + if (entry.trace) { + for (const line of entry.trace) { + colors.normal(`${indent}| ${line}`); + newline(); + } + } + switch (entry.type) { + case LogType.group: + indent += " "; + break; + } + } + if (logData.filteredEntries) { + colors.normal(`+ ${logData.filteredEntries} hidden lines`); + newline(); + } + } + } + } + + if (obj._showWarnings && obj.warnings) { + for (const warning of obj.warnings) { + newline(); + colors.yellow(`WARNING in ${warning}`); + newline(); + } + } + if (obj._showErrors && obj.errors) { + for (const error of obj.errors) { + newline(); + colors.red(`ERROR in ${error}`); + newline(); + } + } + if (obj.children) { + for (const child of obj.children) { + const childString = Stats.jsonToString(child, useColors); + if (childString) { + if (child.name) { + colors.normal("Child "); + colors.bold(child.name); + colors.normal(":"); + } else { + colors.normal("Child"); + } + newline(); + buf.push(" "); + buf.push(childString.replace(/\n/g, "\n ")); + newline(); + } + } + } + if (obj.needAdditionalPass) { + colors.yellow( + "Compilation needs an additional pass and will compile again." + ); + } + + while (buf[buf.length - 1] === "\n") { + buf.pop(); + } + return buf.join(""); + } + + static presetToOptions(name) { + // Accepted values: none, errors-only, minimal, normal, detailed, verbose + // Any other falsy value will behave as 'none', truthy values as 'normal' + const pn = + (typeof name === "string" && name.toLowerCase()) || name || "none"; + switch (pn) { + case "none": + return { + all: false + }; + case "verbose": + return { + entrypoints: true, + chunkGroups: true, + modules: false, + chunks: true, + chunkModules: true, + chunkOrigins: true, + depth: true, + env: true, + reasons: true, + usedExports: true, + providedExports: true, + optimizationBailout: true, + errorDetails: true, + publicPath: true, + logging: "verbose", + exclude: false, + maxModules: Infinity + }; + case "detailed": + return { + entrypoints: true, + chunkGroups: true, + chunks: true, + chunkModules: false, + chunkOrigins: true, + depth: true, + usedExports: true, + providedExports: true, + optimizationBailout: true, + errorDetails: true, + publicPath: true, + logging: true, + exclude: false, + maxModules: Infinity + }; + case "minimal": + return { + all: false, + modules: true, + maxModules: 0, + errors: true, + warnings: true, + logging: "warn" + }; + case "errors-only": + return { + all: false, + errors: true, + moduleTrace: true, + logging: "error" + }; + case "errors-warnings": + return { + all: false, + errors: true, + warnings: true, + logging: "warn" + }; + default: + return {}; + } + } + + static getChildOptions(options, idx) { + let innerOptions; + if (Array.isArray(options.children)) { + if (idx < options.children.length) { + innerOptions = options.children[idx]; + } + } else if (typeof options.children === "object" && options.children) { + innerOptions = options.children; + } + if (typeof innerOptions === "boolean" || typeof innerOptions === "string") { + innerOptions = Stats.presetToOptions(innerOptions); + } + if (!innerOptions) { + return options; + } + const childOptions = Object.assign({}, options); + delete childOptions.children; // do not inherit children + return Object.assign(childOptions, innerOptions); + } +} + +module.exports = Stats; diff --git a/node_modules/webpack/lib/SystemMainTemplatePlugin.js b/node_modules/webpack/lib/SystemMainTemplatePlugin.js new file mode 100644 index 0000000..1c3e4c8 --- /dev/null +++ b/node_modules/webpack/lib/SystemMainTemplatePlugin.js @@ -0,0 +1,135 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Joel Denning @joeldenning + */ + +"use strict"; + +const { ConcatSource } = require("webpack-sources"); +const Template = require("./Template"); + +/** @typedef {import("./Compilation")} Compilation */ + +/** + * @typedef {Object} SystemMainTemplatePluginOptions + * @param {string=} name the library name + */ + +class SystemMainTemplatePlugin { + /** + * @param {SystemMainTemplatePluginOptions} options the plugin options + */ + constructor(options) { + this.name = options.name; + } + + /** + * @param {Compilation} compilation the compilation instance + * @returns {void} + */ + apply(compilation) { + const { mainTemplate, chunkTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + const externals = chunk.getModules().filter(m => m.external); + + // The name this bundle should be registered as with System + const name = this.name + ? `${JSON.stringify( + mainTemplate.getAssetPath(this.name, { hash, chunk }) + )}, ` + : ""; + + // The array of dependencies that are external to webpack and will be provided by System + const systemDependencies = JSON.stringify( + externals.map(m => + typeof m.request === "object" ? m.request.amd : m.request + ) + ); + + // The name of the variable provided by System for exporting + const dynamicExport = "__WEBPACK_DYNAMIC_EXPORT__"; + + // An array of the internal variable names for the webpack externals + const externalWebpackNames = externals.map( + m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__` + ); + + // Declaring variables for the internal variable names for the webpack externals + const externalVarDeclarations = + externalWebpackNames.length > 0 + ? `var ${externalWebpackNames.join(", ")};` + : ""; + + // The system.register format requires an array of setter functions for externals. + const setters = + externalWebpackNames.length === 0 + ? "" + : Template.asString([ + "setters: [", + Template.indent( + externalWebpackNames + .map(external => + Template.asString([ + "function(module) {", + Template.indent(`${external} = module;`), + "}" + ]) + ) + .join(",\n") + ), + "]," + ]); + + return new ConcatSource( + Template.asString([ + `System.register(${name}${systemDependencies}, function(${dynamicExport}) {`, + Template.indent([ + externalVarDeclarations, + "return {", + Template.indent([ + setters, + "execute: function() {", + Template.indent(`${dynamicExport}(`) + ]) + ]) + ]) + "\n", + source, + "\n" + + Template.asString([ + Template.indent([ + Template.indent([Template.indent([");"]), "}"]), + "};" + ]), + "})" + ]) + ); + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "SystemMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.globalHashPaths.tap( + "SystemMainTemplatePlugin", + paths => { + if (this.name) { + paths.push(this.name); + } + return paths; + } + ); + + mainTemplate.hooks.hash.tap("SystemMainTemplatePlugin", hash => { + hash.update("exports system"); + if (this.name) { + hash.update(this.name); + } + }); + } +} + +module.exports = SystemMainTemplatePlugin; diff --git a/node_modules/webpack/lib/Template.js b/node_modules/webpack/lib/Template.js new file mode 100644 index 0000000..0543957 --- /dev/null +++ b/node_modules/webpack/lib/Template.js @@ -0,0 +1,291 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./ModuleTemplate")} ModuleTemplate */ +/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */ + +const { ConcatSource } = require("webpack-sources"); +const HotUpdateChunk = require("./HotUpdateChunk"); + +const START_LOWERCASE_ALPHABET_CODE = "a".charCodeAt(0); +const START_UPPERCASE_ALPHABET_CODE = "A".charCodeAt(0); +const DELTA_A_TO_Z = "z".charCodeAt(0) - START_LOWERCASE_ALPHABET_CODE + 1; +const FUNCTION_CONTENT_REGEX = /^function\s?\(\)\s?\{\r?\n?|\r?\n?\}$/g; +const INDENT_MULTILINE_REGEX = /^\t/gm; +const LINE_SEPARATOR_REGEX = /\r?\n/g; +const IDENTIFIER_NAME_REPLACE_REGEX = /^([^a-zA-Z$_])/; +const IDENTIFIER_ALPHA_NUMERIC_NAME_REPLACE_REGEX = /[^a-zA-Z0-9$]+/g; +const COMMENT_END_REGEX = /\*\//g; +const PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g; +const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g; + +/** @typedef {import("webpack-sources").Source} Source */ + +/** + * @typedef {Object} HasId + * @property {number | string} id + */ + +/** + * @typedef {function(Module, number): boolean} ModuleFilterPredicate + */ + +/** + * @param {HasId} a first id object to be sorted + * @param {HasId} b second id object to be sorted against + * @returns {-1|0|1} the sort value + */ +const stringifyIdSortPredicate = (a, b) => { + const aId = a.id + ""; + const bId = b.id + ""; + if (aId < bId) return -1; + if (aId > bId) return 1; + return 0; +}; + +class Template { + /** + * + * @param {Function} fn a runtime function (.runtime.js) "template" + * @returns {string} the updated and normalized function string + */ + static getFunctionContent(fn) { + return fn + .toString() + .replace(FUNCTION_CONTENT_REGEX, "") + .replace(INDENT_MULTILINE_REGEX, "") + .replace(LINE_SEPARATOR_REGEX, "\n"); + } + + /** + * @param {string} str the string converted to identifier + * @returns {string} created identifier + */ + static toIdentifier(str) { + if (typeof str !== "string") return ""; + return str + .replace(IDENTIFIER_NAME_REPLACE_REGEX, "_$1") + .replace(IDENTIFIER_ALPHA_NUMERIC_NAME_REPLACE_REGEX, "_"); + } + /** + * + * @param {string} str string to be converted to commented in bundle code + * @returns {string} returns a commented version of string + */ + static toComment(str) { + if (!str) return ""; + return `/*! ${str.replace(COMMENT_END_REGEX, "* /")} */`; + } + + /** + * + * @param {string} str string to be converted to "normal comment" + * @returns {string} returns a commented version of string + */ + static toNormalComment(str) { + if (!str) return ""; + return `/* ${str.replace(COMMENT_END_REGEX, "* /")} */`; + } + + /** + * @param {string} str string path to be normalized + * @returns {string} normalized bundle-safe path + */ + static toPath(str) { + if (typeof str !== "string") return ""; + return str + .replace(PATH_NAME_NORMALIZE_REPLACE_REGEX, "-") + .replace(MATCH_PADDED_HYPHENS_REPLACE_REGEX, ""); + } + + // map number to a single character a-z, A-Z or <_ + number> if number is too big + /** + * + * @param {number} n number to convert to ident + * @returns {string} returns single character ident + */ + static numberToIdentifer(n) { + // lower case + if (n < DELTA_A_TO_Z) { + return String.fromCharCode(START_LOWERCASE_ALPHABET_CODE + n); + } + + // upper case + if (n < DELTA_A_TO_Z * 2) { + return String.fromCharCode( + START_UPPERCASE_ALPHABET_CODE + n - DELTA_A_TO_Z + ); + } + + // use multiple letters + return ( + Template.numberToIdentifer(n % (2 * DELTA_A_TO_Z)) + + Template.numberToIdentifer(Math.floor(n / (2 * DELTA_A_TO_Z))) + ); + } + + /** + * + * @param {string | string[]} s string to convert to identity + * @returns {string} converted identity + */ + static indent(s) { + if (Array.isArray(s)) { + return s.map(Template.indent).join("\n"); + } else { + const str = s.trimRight(); + if (!str) return ""; + const ind = str[0] === "\n" ? "" : "\t"; + return ind + str.replace(/\n([^\n])/g, "\n\t$1"); + } + } + + /** + * + * @param {string|string[]} s string to create prefix for + * @param {string} prefix prefix to compose + * @returns {string} returns new prefix string + */ + static prefix(s, prefix) { + const str = Template.asString(s).trim(); + if (!str) return ""; + const ind = str[0] === "\n" ? "" : prefix; + return ind + str.replace(/\n([^\n])/g, "\n" + prefix + "$1"); + } + + /** + * + * @param {string|string[]} str string or string collection + * @returns {string} returns a single string from array + */ + static asString(str) { + if (Array.isArray(str)) { + return str.join("\n"); + } + return str; + } + + /** + * @typedef {Object} WithId + * @property {string|number} id + */ + + /** + * @param {WithId[]} modules a collection of modules to get array bounds for + * @returns {[number, number] | false} returns the upper and lower array bounds + * or false if not every module has a number based id + */ + static getModulesArrayBounds(modules) { + let maxId = -Infinity; + let minId = Infinity; + for (const module of modules) { + if (typeof module.id !== "number") return false; + if (maxId < module.id) maxId = /** @type {number} */ (module.id); + if (minId > module.id) minId = /** @type {number} */ (module.id); + } + if (minId < 16 + ("" + minId).length) { + // add minId x ',' instead of 'Array(minId).concat(…)' + minId = 0; + } + const objectOverhead = modules + .map(module => (module.id + "").length + 2) + .reduce((a, b) => a + b, -1); + const arrayOverhead = + minId === 0 ? maxId : 16 + ("" + minId).length + maxId; + return arrayOverhead < objectOverhead ? [minId, maxId] : false; + } + + /** + * @param {Chunk} chunk chunk whose modules will be rendered + * @param {ModuleFilterPredicate} filterFn function used to filter modules from chunk to render + * @param {ModuleTemplate} moduleTemplate ModuleTemplate instance used to render modules + * @param {TODO | TODO[]} dependencyTemplates templates needed for each module to render dependencies + * @param {string=} prefix applying prefix strings + * @returns {ConcatSource} rendered chunk modules in a Source object + */ + static renderChunkModules( + chunk, + filterFn, + moduleTemplate, + dependencyTemplates, + prefix = "" + ) { + const source = new ConcatSource(); + const modules = chunk.getModules().filter(filterFn); + let removedModules; + if (chunk instanceof HotUpdateChunk) { + removedModules = chunk.removedModules; + } + if ( + modules.length === 0 && + (!removedModules || removedModules.length === 0) + ) { + source.add("[]"); + return source; + } + /** @type {{id: string|number, source: Source|string}[]} */ + const allModules = modules.map(module => { + return { + id: module.id, + source: moduleTemplate.render(module, dependencyTemplates, { + chunk + }) + }; + }); + if (removedModules && removedModules.length > 0) { + for (const id of removedModules) { + allModules.push({ + id, + source: "false" + }); + } + } + const bounds = Template.getModulesArrayBounds(allModules); + if (bounds) { + // Render a spare array + const minId = bounds[0]; + const maxId = bounds[1]; + if (minId !== 0) { + source.add(`Array(${minId}).concat(`); + } + source.add("[\n"); + /** @type {Map<string|number, {id: string|number, source: Source|string}>} */ + const modules = new Map(); + for (const module of allModules) { + modules.set(module.id, module); + } + for (let idx = minId; idx <= maxId; idx++) { + const module = modules.get(idx); + if (idx !== minId) { + source.add(",\n"); + } + source.add(`/* ${idx} */`); + if (module) { + source.add("\n"); + source.add(module.source); + } + } + source.add("\n" + prefix + "]"); + if (minId !== 0) { + source.add(")"); + } + } else { + // Render an object + source.add("{\n"); + allModules.sort(stringifyIdSortPredicate).forEach((module, idx) => { + if (idx !== 0) { + source.add(",\n"); + } + source.add(`\n/***/ ${JSON.stringify(module.id)}:\n`); + source.add(module.source); + }); + source.add(`\n\n${prefix}}`); + } + return source; + } +} + +module.exports = Template; diff --git a/node_modules/webpack/lib/TemplatedPathPlugin.js b/node_modules/webpack/lib/TemplatedPathPlugin.js new file mode 100644 index 0000000..d463f51 --- /dev/null +++ b/node_modules/webpack/lib/TemplatedPathPlugin.js @@ -0,0 +1,188 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Jason Anderson @diurnalist +*/ +"use strict"; + +const REGEXP_HASH = /\[hash(?::(\d+))?\]/gi, + REGEXP_CHUNKHASH = /\[chunkhash(?::(\d+))?\]/gi, + REGEXP_MODULEHASH = /\[modulehash(?::(\d+))?\]/gi, + REGEXP_CONTENTHASH = /\[contenthash(?::(\d+))?\]/gi, + REGEXP_NAME = /\[name\]/gi, + REGEXP_ID = /\[id\]/gi, + REGEXP_MODULEID = /\[moduleid\]/gi, + REGEXP_FILE = /\[file\]/gi, + REGEXP_QUERY = /\[query\]/gi, + REGEXP_FILEBASE = /\[filebase\]/gi, + REGEXP_URL = /\[url\]/gi; + +// Using global RegExp for .test is dangerous +// We use a normal RegExp instead of .test +const REGEXP_HASH_FOR_TEST = new RegExp(REGEXP_HASH.source, "i"), + REGEXP_CHUNKHASH_FOR_TEST = new RegExp(REGEXP_CHUNKHASH.source, "i"), + REGEXP_CONTENTHASH_FOR_TEST = new RegExp(REGEXP_CONTENTHASH.source, "i"), + REGEXP_NAME_FOR_TEST = new RegExp(REGEXP_NAME.source, "i"); + +const withHashLength = (replacer, handlerFn, assetInfo) => { + const fn = (match, hashLength, ...args) => { + if (assetInfo) assetInfo.immutable = true; + const length = hashLength && parseInt(hashLength, 10); + if (length && handlerFn) { + return handlerFn(length); + } + const hash = replacer(match, hashLength, ...args); + return length ? hash.slice(0, length) : hash; + }; + return fn; +}; + +const getReplacer = (value, allowEmpty) => { + const fn = (match, ...args) => { + // last argument in replacer is the entire input string + const input = args[args.length - 1]; + if (value === null || value === undefined) { + if (!allowEmpty) { + throw new Error( + `Path variable ${match} not implemented in this context: ${input}` + ); + } + return ""; + } else { + return `${escapePathVariables(value)}`; + } + }; + return fn; +}; + +const escapePathVariables = value => { + return typeof value === "string" + ? value.replace(/\[(\\*[\w:]+\\*)\]/gi, "[\\$1\\]") + : value; +}; + +const replacePathVariables = (path, data, assetInfo) => { + const chunk = data.chunk; + const chunkId = chunk && chunk.id; + const chunkName = chunk && (chunk.name || chunk.id); + const chunkHash = chunk && (chunk.renderedHash || chunk.hash); + const chunkHashWithLength = chunk && chunk.hashWithLength; + const contentHashType = data.contentHashType; + const contentHash = + (chunk && chunk.contentHash && chunk.contentHash[contentHashType]) || + data.contentHash; + const contentHashWithLength = + (chunk && + chunk.contentHashWithLength && + chunk.contentHashWithLength[contentHashType]) || + data.contentHashWithLength; + const module = data.module; + const moduleId = module && module.id; + const moduleHash = module && (module.renderedHash || module.hash); + const moduleHashWithLength = module && module.hashWithLength; + + if (typeof path === "function") { + path = path(data); + } + + if ( + data.noChunkHash && + (REGEXP_CHUNKHASH_FOR_TEST.test(path) || + REGEXP_CONTENTHASH_FOR_TEST.test(path)) + ) { + throw new Error( + `Cannot use [chunkhash] or [contenthash] for chunk in '${path}' (use [hash] instead)` + ); + } + + return ( + path + .replace( + REGEXP_HASH, + withHashLength(getReplacer(data.hash), data.hashWithLength, assetInfo) + ) + .replace( + REGEXP_CHUNKHASH, + withHashLength(getReplacer(chunkHash), chunkHashWithLength, assetInfo) + ) + .replace( + REGEXP_CONTENTHASH, + withHashLength( + getReplacer(contentHash), + contentHashWithLength, + assetInfo + ) + ) + .replace( + REGEXP_MODULEHASH, + withHashLength(getReplacer(moduleHash), moduleHashWithLength, assetInfo) + ) + .replace(REGEXP_ID, getReplacer(chunkId)) + .replace(REGEXP_MODULEID, getReplacer(moduleId)) + .replace(REGEXP_NAME, getReplacer(chunkName)) + .replace(REGEXP_FILE, getReplacer(data.filename)) + .replace(REGEXP_FILEBASE, getReplacer(data.basename)) + // query is optional, it's OK if it's in a path but there's nothing to replace it with + .replace(REGEXP_QUERY, getReplacer(data.query, true)) + // only available in sourceMappingURLComment + .replace(REGEXP_URL, getReplacer(data.url)) + .replace(/\[\\(\\*[\w:]+\\*)\\\]/gi, "[$1]") + ); +}; + +class TemplatedPathPlugin { + apply(compiler) { + compiler.hooks.compilation.tap("TemplatedPathPlugin", compilation => { + const mainTemplate = compilation.mainTemplate; + + mainTemplate.hooks.assetPath.tap( + "TemplatedPathPlugin", + replacePathVariables + ); + + mainTemplate.hooks.globalHash.tap( + "TemplatedPathPlugin", + (chunk, paths) => { + const outputOptions = mainTemplate.outputOptions; + const publicPath = outputOptions.publicPath || ""; + const filename = outputOptions.filename || ""; + const chunkFilename = + outputOptions.chunkFilename || outputOptions.filename; + if ( + REGEXP_HASH_FOR_TEST.test(publicPath) || + REGEXP_CHUNKHASH_FOR_TEST.test(publicPath) || + REGEXP_CONTENTHASH_FOR_TEST.test(publicPath) || + REGEXP_NAME_FOR_TEST.test(publicPath) + ) + return true; + if (REGEXP_HASH_FOR_TEST.test(filename)) return true; + if (REGEXP_HASH_FOR_TEST.test(chunkFilename)) return true; + if (REGEXP_HASH_FOR_TEST.test(paths.join("|"))) return true; + } + ); + + mainTemplate.hooks.hashForChunk.tap( + "TemplatedPathPlugin", + (hash, chunk) => { + const outputOptions = mainTemplate.outputOptions; + const chunkFilename = + outputOptions.chunkFilename || outputOptions.filename; + if (REGEXP_CHUNKHASH_FOR_TEST.test(chunkFilename)) { + hash.update(JSON.stringify(chunk.getChunkMaps(true).hash)); + } + if (REGEXP_CONTENTHASH_FOR_TEST.test(chunkFilename)) { + hash.update( + JSON.stringify( + chunk.getChunkMaps(true).contentHash.javascript || {} + ) + ); + } + if (REGEXP_NAME_FOR_TEST.test(chunkFilename)) { + hash.update(JSON.stringify(chunk.getChunkMaps(true).name)); + } + } + ); + }); + } +} + +module.exports = TemplatedPathPlugin; diff --git a/node_modules/webpack/lib/UmdMainTemplatePlugin.js b/node_modules/webpack/lib/UmdMainTemplatePlugin.js new file mode 100644 index 0000000..7843c78 --- /dev/null +++ b/node_modules/webpack/lib/UmdMainTemplatePlugin.js @@ -0,0 +1,305 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource, OriginalSource } = require("webpack-sources"); +const Template = require("./Template"); + +/** @typedef {import("../declarations/WebpackOptions").LibraryCustomUmdObject} LibraryCustomUmdObject */ +/** @typedef {import("./Compilation")} Compilation */ + +/** + * @param {string[]} accessor the accessor to convert to path + * @returns {string} the path + */ +const accessorToObjectAccess = accessor => { + return accessor.map(a => `[${JSON.stringify(a)}]`).join(""); +}; + +/** + * @param {string=} base the path prefix + * @param {string|string[]} accessor the accessor + * @param {string=} joinWith the element separator + * @returns {string} the path + */ +const accessorAccess = (base, accessor, joinWith = ", ") => { + const accessors = Array.isArray(accessor) ? accessor : [accessor]; + return accessors + .map((_, idx) => { + const a = base + ? base + accessorToObjectAccess(accessors.slice(0, idx + 1)) + : accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1)); + if (idx === accessors.length - 1) return a; + if (idx === 0 && base === undefined) + return `${a} = typeof ${a} === "object" ? ${a} : {}`; + return `${a} = ${a} || {}`; + }) + .join(joinWith); +}; + +/** @typedef {string | string[] | LibraryCustomUmdObject} UmdMainTemplatePluginName */ + +/** + * @typedef {Object} AuxiliaryCommentObject + * @property {string} root + * @property {string} commonjs + * @property {string} commonjs2 + * @property {string} amd + */ + +/** + * @typedef {Object} UmdMainTemplatePluginOption + * @property {boolean=} optionalAmdExternalAsGlobal + * @property {boolean} namedDefine + * @property {string | AuxiliaryCommentObject} auxiliaryComment + */ + +class UmdMainTemplatePlugin { + /** + * @param {UmdMainTemplatePluginName} name the name of the UMD library + * @param {UmdMainTemplatePluginOption} options the plugin option + */ + constructor(name, options) { + if (typeof name === "object" && !Array.isArray(name)) { + this.name = name.root || name.amd || name.commonjs; + this.names = name; + } else { + this.name = name; + this.names = { + commonjs: name, + root: name, + amd: name + }; + } + this.optionalAmdExternalAsGlobal = options.optionalAmdExternalAsGlobal; + this.namedDefine = options.namedDefine; + this.auxiliaryComment = options.auxiliaryComment; + } + + /** + * @param {Compilation} compilation the compilation instance + * @returns {void} + */ + apply(compilation) { + const { mainTemplate, chunkTemplate, runtimeTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + let externals = chunk + .getModules() + .filter( + m => + m.external && + (m.externalType === "umd" || m.externalType === "umd2") + ); + const optionalExternals = []; + let requiredExternals = []; + if (this.optionalAmdExternalAsGlobal) { + for (const m of externals) { + if (m.optional) { + optionalExternals.push(m); + } else { + requiredExternals.push(m); + } + } + externals = requiredExternals.concat(optionalExternals); + } else { + requiredExternals = externals; + } + + const replaceKeys = str => { + return mainTemplate.getAssetPath(str, { + hash, + chunk + }); + }; + + const externalsDepsArray = modules => { + return `[${replaceKeys( + modules + .map(m => + JSON.stringify( + typeof m.request === "object" ? m.request.amd : m.request + ) + ) + .join(", ") + )}]`; + }; + + const externalsRootArray = modules => { + return replaceKeys( + modules + .map(m => { + let request = m.request; + if (typeof request === "object") request = request.root; + return `root${accessorToObjectAccess([].concat(request))}`; + }) + .join(", ") + ); + }; + + const externalsRequireArray = type => { + return replaceKeys( + externals + .map(m => { + let expr; + let request = m.request; + if (typeof request === "object") { + request = request[type]; + } + if (request === undefined) { + throw new Error( + "Missing external configuration for type:" + type + ); + } + if (Array.isArray(request)) { + expr = `require(${JSON.stringify( + request[0] + )})${accessorToObjectAccess(request.slice(1))}`; + } else { + expr = `require(${JSON.stringify(request)})`; + } + if (m.optional) { + expr = `(function webpackLoadOptionalExternalModule() { try { return ${expr}; } catch(e) {} }())`; + } + return expr; + }) + .join(", ") + ); + }; + + const externalsArguments = modules => { + return modules + .map( + m => + `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__` + ) + .join(", "); + }; + + const libraryName = library => { + return JSON.stringify(replaceKeys([].concat(library).pop())); + }; + + let amdFactory; + if (optionalExternals.length > 0) { + const wrapperArguments = externalsArguments(requiredExternals); + const factoryArguments = + requiredExternals.length > 0 + ? externalsArguments(requiredExternals) + + ", " + + externalsRootArray(optionalExternals) + : externalsRootArray(optionalExternals); + amdFactory = + `function webpackLoadOptionalExternalModuleAmd(${wrapperArguments}) {\n` + + ` return factory(${factoryArguments});\n` + + " }"; + } else { + amdFactory = "factory"; + } + + const auxiliaryComment = this.auxiliaryComment; + + const getAuxilaryComment = type => { + if (auxiliaryComment) { + if (typeof auxiliaryComment === "string") + return "\t//" + auxiliaryComment + "\n"; + if (auxiliaryComment[type]) + return "\t//" + auxiliaryComment[type] + "\n"; + } + return ""; + }; + + return new ConcatSource( + new OriginalSource( + "(function webpackUniversalModuleDefinition(root, factory) {\n" + + getAuxilaryComment("commonjs2") + + " if(typeof exports === 'object' && typeof module === 'object')\n" + + " module.exports = factory(" + + externalsRequireArray("commonjs2") + + ");\n" + + getAuxilaryComment("amd") + + " else if(typeof define === 'function' && define.amd)\n" + + (requiredExternals.length > 0 + ? this.names.amd && this.namedDefine === true + ? " define(" + + libraryName(this.names.amd) + + ", " + + externalsDepsArray(requiredExternals) + + ", " + + amdFactory + + ");\n" + : " define(" + + externalsDepsArray(requiredExternals) + + ", " + + amdFactory + + ");\n" + : this.names.amd && this.namedDefine === true + ? " define(" + + libraryName(this.names.amd) + + ", [], " + + amdFactory + + ");\n" + : " define([], " + amdFactory + ");\n") + + (this.names.root || this.names.commonjs + ? getAuxilaryComment("commonjs") + + " else if(typeof exports === 'object')\n" + + " exports[" + + libraryName(this.names.commonjs || this.names.root) + + "] = factory(" + + externalsRequireArray("commonjs") + + ");\n" + + getAuxilaryComment("root") + + " else\n" + + " " + + replaceKeys( + accessorAccess("root", this.names.root || this.names.commonjs) + ) + + " = factory(" + + externalsRootArray(externals) + + ");\n" + : " else {\n" + + (externals.length > 0 + ? " var a = typeof exports === 'object' ? factory(" + + externalsRequireArray("commonjs") + + ") : factory(" + + externalsRootArray(externals) + + ");\n" + : " var a = factory();\n") + + " for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" + + " }\n") + + `})(${ + runtimeTemplate.outputOptions.globalObject + }, function(${externalsArguments(externals)}) {\nreturn `, + "webpack/universalModuleDefinition" + ), + source, + ";\n})" + ); + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "UmdMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.globalHashPaths.tap("UmdMainTemplatePlugin", paths => { + if (this.names.root) paths = paths.concat(this.names.root); + if (this.names.amd) paths = paths.concat(this.names.amd); + if (this.names.commonjs) paths = paths.concat(this.names.commonjs); + return paths; + }); + + mainTemplate.hooks.hash.tap("UmdMainTemplatePlugin", hash => { + hash.update("umd"); + hash.update(`${this.names.root}`); + hash.update(`${this.names.amd}`); + hash.update(`${this.names.commonjs}`); + }); + } +} + +module.exports = UmdMainTemplatePlugin; diff --git a/node_modules/webpack/lib/UnsupportedFeatureWarning.js b/node_modules/webpack/lib/UnsupportedFeatureWarning.js new file mode 100644 index 0000000..72eef83 --- /dev/null +++ b/node_modules/webpack/lib/UnsupportedFeatureWarning.js @@ -0,0 +1,30 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); + +/** @typedef {import("./Module")} Module */ +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ + +class UnsupportedFeatureWarning extends WebpackError { + /** + * @param {Module} module module relevant to warning + * @param {string} message description of warning + * @param {DependencyLocation} loc location start and end positions of the module + */ + constructor(module, message, loc) { + super(message); + + this.name = "UnsupportedFeatureWarning"; + this.module = module; + this.loc = loc; + this.hideStack = true; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = UnsupportedFeatureWarning; diff --git a/node_modules/webpack/lib/UseStrictPlugin.js b/node_modules/webpack/lib/UseStrictPlugin.js new file mode 100644 index 0000000..425be2e --- /dev/null +++ b/node_modules/webpack/lib/UseStrictPlugin.js @@ -0,0 +1,54 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ConstDependency = require("./dependencies/ConstDependency"); + +/** @typedef {import("./Compiler")} Compiler */ + +class UseStrictPlugin { + /** + * @param {Compiler} compiler Webpack Compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "UseStrictPlugin", + (compilation, { normalModuleFactory }) => { + const handler = parser => { + parser.hooks.program.tap("UseStrictPlugin", ast => { + const firstNode = ast.body[0]; + if ( + firstNode && + firstNode.type === "ExpressionStatement" && + firstNode.expression.type === "Literal" && + firstNode.expression.value === "use strict" + ) { + // Remove "use strict" expression. It will be added later by the renderer again. + // This is necessary in order to not break the strict mode when webpack prepends code. + // @see https://github.com/webpack/webpack/issues/1970 + const dep = new ConstDependency("", firstNode.range); + dep.loc = firstNode.loc; + parser.state.current.addDependency(dep); + parser.state.module.buildInfo.strict = true; + } + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("UseStrictPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("UseStrictPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("UseStrictPlugin", handler); + } + ); + } +} + +module.exports = UseStrictPlugin; diff --git a/node_modules/webpack/lib/WarnCaseSensitiveModulesPlugin.js b/node_modules/webpack/lib/WarnCaseSensitiveModulesPlugin.js new file mode 100644 index 0000000..867a33f --- /dev/null +++ b/node_modules/webpack/lib/WarnCaseSensitiveModulesPlugin.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const CaseSensitiveModulesWarning = require("./CaseSensitiveModulesWarning"); + +class WarnCaseSensitiveModulesPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "WarnCaseSensitiveModulesPlugin", + compilation => { + compilation.hooks.seal.tap("WarnCaseSensitiveModulesPlugin", () => { + const moduleWithoutCase = new Map(); + for (const module of compilation.modules) { + const identifier = module.identifier().toLowerCase(); + const array = moduleWithoutCase.get(identifier); + if (array) { + array.push(module); + } else { + moduleWithoutCase.set(identifier, [module]); + } + } + for (const pair of moduleWithoutCase) { + const array = pair[1]; + if (array.length > 1) { + compilation.warnings.push(new CaseSensitiveModulesWarning(array)); + } + } + }); + } + ); + } +} + +module.exports = WarnCaseSensitiveModulesPlugin; diff --git a/node_modules/webpack/lib/WarnNoModeSetPlugin.js b/node_modules/webpack/lib/WarnNoModeSetPlugin.js new file mode 100644 index 0000000..4a69a8c --- /dev/null +++ b/node_modules/webpack/lib/WarnNoModeSetPlugin.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const NoModeWarning = require("./NoModeWarning"); + +class WarnNoModeSetPlugin { + apply(compiler) { + compiler.hooks.thisCompilation.tap("WarnNoModeSetPlugin", compilation => { + compilation.warnings.push(new NoModeWarning()); + }); + } +} + +module.exports = WarnNoModeSetPlugin; diff --git a/node_modules/webpack/lib/WatchIgnorePlugin.js b/node_modules/webpack/lib/WatchIgnorePlugin.js new file mode 100644 index 0000000..5ba9cd0 --- /dev/null +++ b/node_modules/webpack/lib/WatchIgnorePlugin.js @@ -0,0 +1,106 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../schemas/plugins/WatchIgnorePlugin.json"); + +/** @typedef {import("../declarations/plugins/WatchIgnorePlugin").WatchIgnorePluginOptions} WatchIgnorePluginOptions */ + +class IgnoringWatchFileSystem { + constructor(wfs, paths) { + this.wfs = wfs; + this.paths = paths; + } + + watch(files, dirs, missing, startTime, options, callback, callbackUndelayed) { + const ignored = path => + this.paths.some(p => + p instanceof RegExp ? p.test(path) : path.indexOf(p) === 0 + ); + + const notIgnored = path => !ignored(path); + + const ignoredFiles = files.filter(ignored); + const ignoredDirs = dirs.filter(ignored); + + const watcher = this.wfs.watch( + files.filter(notIgnored), + dirs.filter(notIgnored), + missing, + startTime, + options, + ( + err, + filesModified, + dirsModified, + missingModified, + fileTimestamps, + dirTimestamps, + removedFiles + ) => { + if (err) return callback(err); + for (const path of ignoredFiles) { + fileTimestamps.set(path, 1); + } + + for (const path of ignoredDirs) { + dirTimestamps.set(path, 1); + } + + callback( + err, + filesModified, + dirsModified, + missingModified, + fileTimestamps, + dirTimestamps, + removedFiles + ); + }, + callbackUndelayed + ); + + return { + close: () => watcher.close(), + pause: () => watcher.pause(), + getContextTimestamps: () => { + const dirTimestamps = watcher.getContextTimestamps(); + for (const path of ignoredDirs) { + dirTimestamps.set(path, 1); + } + return dirTimestamps; + }, + getFileTimestamps: () => { + const fileTimestamps = watcher.getFileTimestamps(); + for (const path of ignoredFiles) { + fileTimestamps.set(path, 1); + } + return fileTimestamps; + } + }; + } +} + +class WatchIgnorePlugin { + /** + * @param {WatchIgnorePluginOptions} paths list of paths + */ + constructor(paths) { + validateOptions(schema, paths, "Watch Ignore Plugin"); + this.paths = paths; + } + + apply(compiler) { + compiler.hooks.afterEnvironment.tap("WatchIgnorePlugin", () => { + compiler.watchFileSystem = new IgnoringWatchFileSystem( + compiler.watchFileSystem, + this.paths + ); + }); + } +} + +module.exports = WatchIgnorePlugin; diff --git a/node_modules/webpack/lib/Watching.js b/node_modules/webpack/lib/Watching.js new file mode 100644 index 0000000..dc66db1 --- /dev/null +++ b/node_modules/webpack/lib/Watching.js @@ -0,0 +1,211 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Stats = require("./Stats"); + +class Watching { + constructor(compiler, watchOptions, handler) { + this.startTime = null; + this.invalid = false; + this.handler = handler; + this.callbacks = []; + this.closed = false; + this.suspended = false; + if (typeof watchOptions === "number") { + this.watchOptions = { + aggregateTimeout: watchOptions + }; + } else if (watchOptions && typeof watchOptions === "object") { + this.watchOptions = Object.assign({}, watchOptions); + } else { + this.watchOptions = {}; + } + this.watchOptions.aggregateTimeout = + this.watchOptions.aggregateTimeout || 200; + this.compiler = compiler; + this.running = true; + this.compiler.readRecords(err => { + if (err) return this._done(err); + + this._go(); + }); + } + + _go() { + this.startTime = Date.now(); + this.running = true; + this.invalid = false; + this.compiler.hooks.watchRun.callAsync(this.compiler, err => { + if (err) return this._done(err); + const onCompiled = (err, compilation) => { + if (err) return this._done(err); + if (this.invalid) return this._done(); + + if (this.compiler.hooks.shouldEmit.call(compilation) === false) { + return this._done(null, compilation); + } + + this.compiler.emitAssets(compilation, err => { + if (err) return this._done(err); + if (this.invalid) return this._done(); + this.compiler.emitRecords(err => { + if (err) return this._done(err); + + if (compilation.hooks.needAdditionalPass.call()) { + compilation.needAdditionalPass = true; + + const stats = new Stats(compilation); + stats.startTime = this.startTime; + stats.endTime = Date.now(); + this.compiler.hooks.done.callAsync(stats, err => { + if (err) return this._done(err); + + this.compiler.hooks.additionalPass.callAsync(err => { + if (err) return this._done(err); + this.compiler.compile(onCompiled); + }); + }); + return; + } + return this._done(null, compilation); + }); + }); + }; + this.compiler.compile(onCompiled); + }); + } + + _getStats(compilation) { + const stats = new Stats(compilation); + stats.startTime = this.startTime; + stats.endTime = Date.now(); + return stats; + } + + _done(err, compilation) { + this.running = false; + if (this.invalid) return this._go(); + + const stats = compilation ? this._getStats(compilation) : null; + if (err) { + this.compiler.hooks.failed.call(err); + this.handler(err, stats); + return; + } + this.compiler.hooks.done.callAsync(stats, () => { + this.handler(null, stats); + if (!this.closed) { + this.watch( + Array.from(compilation.fileDependencies), + Array.from(compilation.contextDependencies), + Array.from(compilation.missingDependencies) + ); + } + for (const cb of this.callbacks) cb(); + this.callbacks.length = 0; + }); + } + + watch(files, dirs, missing) { + this.pausedWatcher = null; + this.watcher = this.compiler.watchFileSystem.watch( + files, + dirs, + missing, + this.startTime, + this.watchOptions, + ( + err, + filesModified, + contextModified, + missingModified, + fileTimestamps, + contextTimestamps, + removedFiles + ) => { + this.pausedWatcher = this.watcher; + this.watcher = null; + if (err) { + return this.handler(err); + } + this.compiler.fileTimestamps = fileTimestamps; + this.compiler.contextTimestamps = contextTimestamps; + this.compiler.removedFiles = removedFiles; + if (!this.suspended) { + this._invalidate(); + } + }, + (fileName, changeTime) => { + this.compiler.hooks.invalid.call(fileName, changeTime); + } + ); + } + + invalidate(callback) { + if (callback) { + this.callbacks.push(callback); + } + if (this.watcher) { + this.compiler.fileTimestamps = this.watcher.getFileTimestamps(); + this.compiler.contextTimestamps = this.watcher.getContextTimestamps(); + } + return this._invalidate(); + } + + _invalidate() { + if (this.watcher) { + this.pausedWatcher = this.watcher; + this.watcher.pause(); + this.watcher = null; + } + + if (this.running) { + this.invalid = true; + return false; + } else { + this._go(); + } + } + + suspend() { + this.suspended = true; + this.invalid = false; + } + + resume() { + if (this.suspended) { + this.suspended = false; + this._invalidate(); + } + } + + close(callback) { + const finalCallback = () => { + this.compiler.hooks.watchClose.call(); + this.compiler.running = false; + this.compiler.watchMode = false; + if (callback !== undefined) callback(); + }; + + this.closed = true; + if (this.watcher) { + this.watcher.close(); + this.watcher = null; + } + if (this.pausedWatcher) { + this.pausedWatcher.close(); + this.pausedWatcher = null; + } + if (this.running) { + this.invalid = true; + this._done = finalCallback; + } else { + finalCallback(); + } + } +} + +module.exports = Watching; diff --git a/node_modules/webpack/lib/WebpackError.js b/node_modules/webpack/lib/WebpackError.js new file mode 100644 index 0000000..4f16001 --- /dev/null +++ b/node_modules/webpack/lib/WebpackError.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Jarid Margolin @jaridmargolin +*/ +"use strict"; + +const inspect = require("util").inspect.custom; + +class WebpackError extends Error { + /** + * Creates an instance of WebpackError. + * @param {string=} message error message + */ + constructor(message) { + super(message); + + this.details = undefined; + this.missing = undefined; + this.origin = undefined; + this.dependencies = undefined; + this.module = undefined; + + Error.captureStackTrace(this, this.constructor); + } + + [inspect]() { + return this.stack + (this.details ? `\n${this.details}` : ""); + } +} + +module.exports = WebpackError; diff --git a/node_modules/webpack/lib/WebpackOptionsApply.js b/node_modules/webpack/lib/WebpackOptionsApply.js new file mode 100644 index 0000000..a80113e --- /dev/null +++ b/node_modules/webpack/lib/WebpackOptionsApply.js @@ -0,0 +1,546 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const OptionsApply = require("./OptionsApply"); + +const JavascriptModulesPlugin = require("./JavascriptModulesPlugin"); +const JsonModulesPlugin = require("./JsonModulesPlugin"); +const WebAssemblyModulesPlugin = require("./wasm/WebAssemblyModulesPlugin"); + +const LoaderTargetPlugin = require("./LoaderTargetPlugin"); +const FunctionModulePlugin = require("./FunctionModulePlugin"); +const EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin"); +const SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin"); +const EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin"); + +const EntryOptionPlugin = require("./EntryOptionPlugin"); +const RecordIdsPlugin = require("./RecordIdsPlugin"); + +const APIPlugin = require("./APIPlugin"); +const ConstPlugin = require("./ConstPlugin"); +const CommonJsStuffPlugin = require("./CommonJsStuffPlugin"); +const CompatibilityPlugin = require("./CompatibilityPlugin"); + +const TemplatedPathPlugin = require("./TemplatedPathPlugin"); +const WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin"); +const UseStrictPlugin = require("./UseStrictPlugin"); + +const LoaderPlugin = require("./dependencies/LoaderPlugin"); +const CommonJsPlugin = require("./dependencies/CommonJsPlugin"); +const HarmonyModulesPlugin = require("./dependencies/HarmonyModulesPlugin"); +const SystemPlugin = require("./dependencies/SystemPlugin"); +const ImportPlugin = require("./dependencies/ImportPlugin"); +const RequireContextPlugin = require("./dependencies/RequireContextPlugin"); +const RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin"); +const RequireIncludePlugin = require("./dependencies/RequireIncludePlugin"); + +const { cachedCleverMerge } = require("./util/cleverMerge"); + +/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */ +/** @typedef {import("./Compiler")} Compiler */ + +class WebpackOptionsApply extends OptionsApply { + constructor() { + super(); + } + + /** + * @param {WebpackOptions} options options object + * @param {Compiler} compiler compiler object + * @returns {WebpackOptions} options object + */ + process(options, compiler) { + let ExternalsPlugin; + compiler.outputPath = options.output.path; + compiler.recordsInputPath = options.recordsInputPath || options.recordsPath; + compiler.recordsOutputPath = + options.recordsOutputPath || options.recordsPath; + compiler.name = options.name; + // TODO webpack 5 refactor this to MultiCompiler.setDependencies() with a WeakMap + // @ts-ignore TODO + compiler.dependencies = options.dependencies; + if (typeof options.target === "string") { + let JsonpTemplatePlugin; + let FetchCompileWasmTemplatePlugin; + let ReadFileCompileWasmTemplatePlugin; + let NodeSourcePlugin; + let NodeTargetPlugin; + let NodeTemplatePlugin; + + switch (options.target) { + case "web": + JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin"); + FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin"); + NodeSourcePlugin = require("./node/NodeSourcePlugin"); + new JsonpTemplatePlugin().apply(compiler); + new FetchCompileWasmTemplatePlugin({ + mangleImports: options.optimization.mangleWasmImports + }).apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeSourcePlugin(options.node).apply(compiler); + new LoaderTargetPlugin(options.target).apply(compiler); + break; + case "webworker": { + let WebWorkerTemplatePlugin = require("./webworker/WebWorkerTemplatePlugin"); + FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin"); + NodeSourcePlugin = require("./node/NodeSourcePlugin"); + new WebWorkerTemplatePlugin().apply(compiler); + new FetchCompileWasmTemplatePlugin({ + mangleImports: options.optimization.mangleWasmImports + }).apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeSourcePlugin(options.node).apply(compiler); + new LoaderTargetPlugin(options.target).apply(compiler); + break; + } + case "node": + case "async-node": + NodeTemplatePlugin = require("./node/NodeTemplatePlugin"); + ReadFileCompileWasmTemplatePlugin = require("./node/ReadFileCompileWasmTemplatePlugin"); + NodeTargetPlugin = require("./node/NodeTargetPlugin"); + new NodeTemplatePlugin({ + asyncChunkLoading: options.target === "async-node" + }).apply(compiler); + new ReadFileCompileWasmTemplatePlugin({ + mangleImports: options.optimization.mangleWasmImports + }).apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeTargetPlugin().apply(compiler); + new LoaderTargetPlugin("node").apply(compiler); + break; + case "node-webkit": + JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin"); + NodeTargetPlugin = require("./node/NodeTargetPlugin"); + ExternalsPlugin = require("./ExternalsPlugin"); + new JsonpTemplatePlugin().apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeTargetPlugin().apply(compiler); + new ExternalsPlugin("commonjs", "nw.gui").apply(compiler); + new LoaderTargetPlugin(options.target).apply(compiler); + break; + case "electron-main": + NodeTemplatePlugin = require("./node/NodeTemplatePlugin"); + NodeTargetPlugin = require("./node/NodeTargetPlugin"); + ExternalsPlugin = require("./ExternalsPlugin"); + new NodeTemplatePlugin({ + asyncChunkLoading: true + }).apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeTargetPlugin().apply(compiler); + new ExternalsPlugin("commonjs", [ + "app", + "auto-updater", + "browser-window", + "clipboard", + "content-tracing", + "crash-reporter", + "dialog", + "electron", + "global-shortcut", + "ipc", + "ipc-main", + "menu", + "menu-item", + "native-image", + "original-fs", + "power-monitor", + "power-save-blocker", + "protocol", + "screen", + "session", + "shell", + "tray", + "web-contents" + ]).apply(compiler); + new LoaderTargetPlugin(options.target).apply(compiler); + break; + case "electron-renderer": + case "electron-preload": + FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin"); + NodeTargetPlugin = require("./node/NodeTargetPlugin"); + ExternalsPlugin = require("./ExternalsPlugin"); + if (options.target === "electron-renderer") { + JsonpTemplatePlugin = require("./web/JsonpTemplatePlugin"); + new JsonpTemplatePlugin().apply(compiler); + } else if (options.target === "electron-preload") { + NodeTemplatePlugin = require("./node/NodeTemplatePlugin"); + new NodeTemplatePlugin({ + asyncChunkLoading: true + }).apply(compiler); + } + new FetchCompileWasmTemplatePlugin({ + mangleImports: options.optimization.mangleWasmImports + }).apply(compiler); + new FunctionModulePlugin().apply(compiler); + new NodeTargetPlugin().apply(compiler); + new ExternalsPlugin("commonjs", [ + "clipboard", + "crash-reporter", + "desktop-capturer", + "electron", + "ipc", + "ipc-renderer", + "native-image", + "original-fs", + "remote", + "screen", + "shell", + "web-frame" + ]).apply(compiler); + new LoaderTargetPlugin(options.target).apply(compiler); + break; + default: + throw new Error("Unsupported target '" + options.target + "'."); + } + } + // @ts-ignore This is always true, which is good this way + else if (options.target !== false) { + options.target(compiler); + } else { + throw new Error("Unsupported target '" + options.target + "'."); + } + + if (options.output.library || options.output.libraryTarget !== "var") { + const LibraryTemplatePlugin = require("./LibraryTemplatePlugin"); + new LibraryTemplatePlugin( + options.output.library, + options.output.libraryTarget, + options.output.umdNamedDefine, + options.output.auxiliaryComment || "", + options.output.libraryExport + ).apply(compiler); + } + if (options.externals) { + ExternalsPlugin = require("./ExternalsPlugin"); + new ExternalsPlugin( + options.output.libraryTarget, + options.externals + ).apply(compiler); + } + + let noSources; + let legacy; + let modern; + let comment; + if ( + options.devtool && + (options.devtool.includes("sourcemap") || + options.devtool.includes("source-map")) + ) { + const hidden = options.devtool.includes("hidden"); + const inline = options.devtool.includes("inline"); + const evalWrapped = options.devtool.includes("eval"); + const cheap = options.devtool.includes("cheap"); + const moduleMaps = options.devtool.includes("module"); + noSources = options.devtool.includes("nosources"); + legacy = options.devtool.includes("@"); + modern = options.devtool.includes("#"); + comment = + legacy && modern + ? "\n/*\n//@ source" + + "MappingURL=[url]\n//# source" + + "MappingURL=[url]\n*/" + : legacy + ? "\n/*\n//@ source" + "MappingURL=[url]\n*/" + : modern + ? "\n//# source" + "MappingURL=[url]" + : null; + const Plugin = evalWrapped + ? EvalSourceMapDevToolPlugin + : SourceMapDevToolPlugin; + new Plugin({ + filename: inline ? null : options.output.sourceMapFilename, + moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate, + fallbackModuleFilenameTemplate: + options.output.devtoolFallbackModuleFilenameTemplate, + append: hidden ? false : comment, + module: moduleMaps ? true : cheap ? false : true, + columns: cheap ? false : true, + lineToLine: options.output.devtoolLineToLine, + noSources: noSources, + namespace: options.output.devtoolNamespace + }).apply(compiler); + } else if (options.devtool && options.devtool.includes("eval")) { + legacy = options.devtool.includes("@"); + modern = options.devtool.includes("#"); + comment = + legacy && modern + ? "\n//@ sourceURL=[url]\n//# sourceURL=[url]" + : legacy + ? "\n//@ sourceURL=[url]" + : modern + ? "\n//# sourceURL=[url]" + : null; + new EvalDevToolModulePlugin({ + sourceUrlComment: comment, + moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate, + namespace: options.output.devtoolNamespace + }).apply(compiler); + } + + new JavascriptModulesPlugin().apply(compiler); + new JsonModulesPlugin().apply(compiler); + new WebAssemblyModulesPlugin({ + mangleImports: options.optimization.mangleWasmImports + }).apply(compiler); + + new EntryOptionPlugin().apply(compiler); + compiler.hooks.entryOption.call(options.context, options.entry); + + new CompatibilityPlugin().apply(compiler); + new HarmonyModulesPlugin(options.module).apply(compiler); + if (options.amd !== false) { + const AMDPlugin = require("./dependencies/AMDPlugin"); + const RequireJsStuffPlugin = require("./RequireJsStuffPlugin"); + new AMDPlugin(options.module, options.amd || {}).apply(compiler); + new RequireJsStuffPlugin().apply(compiler); + } + new CommonJsPlugin(options.module).apply(compiler); + new LoaderPlugin().apply(compiler); + if (options.node !== false) { + const NodeStuffPlugin = require("./NodeStuffPlugin"); + new NodeStuffPlugin(options.node).apply(compiler); + } + new CommonJsStuffPlugin().apply(compiler); + new APIPlugin().apply(compiler); + new ConstPlugin().apply(compiler); + new UseStrictPlugin().apply(compiler); + new RequireIncludePlugin().apply(compiler); + new RequireEnsurePlugin().apply(compiler); + new RequireContextPlugin( + options.resolve.modules, + options.resolve.extensions, + options.resolve.mainFiles + ).apply(compiler); + new ImportPlugin(options.module).apply(compiler); + new SystemPlugin(options.module).apply(compiler); + + if (typeof options.mode !== "string") { + const WarnNoModeSetPlugin = require("./WarnNoModeSetPlugin"); + new WarnNoModeSetPlugin().apply(compiler); + } + + const EnsureChunkConditionsPlugin = require("./optimize/EnsureChunkConditionsPlugin"); + new EnsureChunkConditionsPlugin().apply(compiler); + if (options.optimization.removeAvailableModules) { + const RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin"); + new RemoveParentModulesPlugin().apply(compiler); + } + if (options.optimization.removeEmptyChunks) { + const RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin"); + new RemoveEmptyChunksPlugin().apply(compiler); + } + if (options.optimization.mergeDuplicateChunks) { + const MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin"); + new MergeDuplicateChunksPlugin().apply(compiler); + } + if (options.optimization.flagIncludedChunks) { + const FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin"); + new FlagIncludedChunksPlugin().apply(compiler); + } + if (options.optimization.sideEffects) { + const SideEffectsFlagPlugin = require("./optimize/SideEffectsFlagPlugin"); + new SideEffectsFlagPlugin().apply(compiler); + } + if (options.optimization.providedExports) { + const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin"); + new FlagDependencyExportsPlugin().apply(compiler); + } + if (options.optimization.usedExports) { + const FlagDependencyUsagePlugin = require("./FlagDependencyUsagePlugin"); + new FlagDependencyUsagePlugin().apply(compiler); + } + if (options.optimization.concatenateModules) { + const ModuleConcatenationPlugin = require("./optimize/ModuleConcatenationPlugin"); + new ModuleConcatenationPlugin().apply(compiler); + } + if (options.optimization.splitChunks) { + const SplitChunksPlugin = require("./optimize/SplitChunksPlugin"); + new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler); + } + if (options.optimization.runtimeChunk) { + const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin"); + new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler); + } + if (options.optimization.noEmitOnErrors) { + const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin"); + new NoEmitOnErrorsPlugin().apply(compiler); + } + if (options.optimization.checkWasmTypes) { + const WasmFinalizeExportsPlugin = require("./wasm/WasmFinalizeExportsPlugin"); + new WasmFinalizeExportsPlugin().apply(compiler); + } + let moduleIds = options.optimization.moduleIds; + if (moduleIds === undefined) { + // TODO webpack 5 remove all these options + if (options.optimization.occurrenceOrder) { + moduleIds = "size"; + } + if (options.optimization.namedModules) { + moduleIds = "named"; + } + if (options.optimization.hashedModuleIds) { + moduleIds = "hashed"; + } + if (moduleIds === undefined) { + moduleIds = "natural"; + } + } + if (moduleIds) { + const NamedModulesPlugin = require("./NamedModulesPlugin"); + const HashedModuleIdsPlugin = require("./HashedModuleIdsPlugin"); + const OccurrenceModuleOrderPlugin = require("./optimize/OccurrenceModuleOrderPlugin"); + switch (moduleIds) { + case "natural": + // TODO webpack 5: see hint in Compilation.sortModules + break; + case "named": + new NamedModulesPlugin().apply(compiler); + break; + case "hashed": + new HashedModuleIdsPlugin().apply(compiler); + break; + case "size": + new OccurrenceModuleOrderPlugin({ + prioritiseInitial: true + }).apply(compiler); + break; + case "total-size": + new OccurrenceModuleOrderPlugin({ + prioritiseInitial: false + }).apply(compiler); + break; + default: + throw new Error( + `webpack bug: moduleIds: ${moduleIds} is not implemented` + ); + } + } + let chunkIds = options.optimization.chunkIds; + if (chunkIds === undefined) { + // TODO webpack 5 remove all these options + if (options.optimization.occurrenceOrder) { + // This looks weird but it's for backward-compat + // This bug already existed before adding this feature + chunkIds = "total-size"; + } + if (options.optimization.namedChunks) { + chunkIds = "named"; + } + if (chunkIds === undefined) { + chunkIds = "natural"; + } + } + if (chunkIds) { + const NaturalChunkOrderPlugin = require("./optimize/NaturalChunkOrderPlugin"); + const NamedChunksPlugin = require("./NamedChunksPlugin"); + const OccurrenceChunkOrderPlugin = require("./optimize/OccurrenceChunkOrderPlugin"); + switch (chunkIds) { + case "natural": + new NaturalChunkOrderPlugin().apply(compiler); + break; + case "named": + // TODO webapck 5: for backward-compat this need to have OccurrenceChunkOrderPlugin too + // The NamedChunksPlugin doesn't give every chunk a name + // This should be fixed, and the OccurrenceChunkOrderPlugin should be removed here. + new OccurrenceChunkOrderPlugin({ + prioritiseInitial: false + }).apply(compiler); + new NamedChunksPlugin().apply(compiler); + break; + case "size": + new OccurrenceChunkOrderPlugin({ + prioritiseInitial: true + }).apply(compiler); + break; + case "total-size": + new OccurrenceChunkOrderPlugin({ + prioritiseInitial: false + }).apply(compiler); + break; + default: + throw new Error( + `webpack bug: chunkIds: ${chunkIds} is not implemented` + ); + } + } + if (options.optimization.nodeEnv) { + const DefinePlugin = require("./DefinePlugin"); + new DefinePlugin({ + "process.env.NODE_ENV": JSON.stringify(options.optimization.nodeEnv) + }).apply(compiler); + } + if (options.optimization.minimize) { + for (const minimizer of options.optimization.minimizer) { + if (typeof minimizer === "function") { + minimizer.call(compiler, compiler); + } else { + minimizer.apply(compiler); + } + } + } + + if (options.performance) { + const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin"); + new SizeLimitsPlugin(options.performance).apply(compiler); + } + + new TemplatedPathPlugin().apply(compiler); + + new RecordIdsPlugin({ + portableIds: options.optimization.portableRecords + }).apply(compiler); + + new WarnCaseSensitiveModulesPlugin().apply(compiler); + + if (options.cache) { + const CachePlugin = require("./CachePlugin"); + new CachePlugin( + typeof options.cache === "object" ? options.cache : null + ).apply(compiler); + } + + compiler.hooks.afterPlugins.call(compiler); + if (!compiler.inputFileSystem) { + throw new Error("No input filesystem provided"); + } + compiler.resolverFactory.hooks.resolveOptions + .for("normal") + .tap("WebpackOptionsApply", resolveOptions => { + return Object.assign( + { + fileSystem: compiler.inputFileSystem + }, + cachedCleverMerge(options.resolve, resolveOptions) + ); + }); + compiler.resolverFactory.hooks.resolveOptions + .for("context") + .tap("WebpackOptionsApply", resolveOptions => { + return Object.assign( + { + fileSystem: compiler.inputFileSystem, + resolveToContext: true + }, + cachedCleverMerge(options.resolve, resolveOptions) + ); + }); + compiler.resolverFactory.hooks.resolveOptions + .for("loader") + .tap("WebpackOptionsApply", resolveOptions => { + return Object.assign( + { + fileSystem: compiler.inputFileSystem + }, + cachedCleverMerge(options.resolveLoader, resolveOptions) + ); + }); + compiler.hooks.afterResolvers.call(compiler); + return options; + } +} + +module.exports = WebpackOptionsApply; diff --git a/node_modules/webpack/lib/WebpackOptionsDefaulter.js b/node_modules/webpack/lib/WebpackOptionsDefaulter.js new file mode 100644 index 0000000..cb5541e --- /dev/null +++ b/node_modules/webpack/lib/WebpackOptionsDefaulter.js @@ -0,0 +1,381 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); + +const OptionsDefaulter = require("./OptionsDefaulter"); +const Template = require("./Template"); + +const isProductionLikeMode = options => { + return options.mode === "production" || !options.mode; +}; + +const isWebLikeTarget = options => { + return options.target === "web" || options.target === "webworker"; +}; + +const getDevtoolNamespace = library => { + // if options.output.library is a string + if (Array.isArray(library)) { + return library.join("."); + } else if (typeof library === "object") { + return getDevtoolNamespace(library.root); + } + return library || ""; +}; + +class WebpackOptionsDefaulter extends OptionsDefaulter { + constructor() { + super(); + + this.set("entry", "./src"); + + this.set("devtool", "make", options => + options.mode === "development" ? "eval" : false + ); + this.set("cache", "make", options => options.mode === "development"); + + this.set("context", process.cwd()); + this.set("target", "web"); + + this.set("module", "call", value => Object.assign({}, value)); + this.set("module.unknownContextRequest", "."); + this.set("module.unknownContextRegExp", false); + this.set("module.unknownContextRecursive", true); + this.set("module.unknownContextCritical", true); + this.set("module.exprContextRequest", "."); + this.set("module.exprContextRegExp", false); + this.set("module.exprContextRecursive", true); + this.set("module.exprContextCritical", true); + this.set("module.wrappedContextRegExp", /.*/); + this.set("module.wrappedContextRecursive", true); + this.set("module.wrappedContextCritical", false); + this.set("module.strictExportPresence", false); + this.set("module.strictThisContextOnImports", false); + this.set("module.unsafeCache", "make", options => !!options.cache); + this.set("module.rules", []); + this.set("module.defaultRules", "make", options => [ + { + type: "javascript/auto", + resolve: {} + }, + { + test: /\.mjs$/i, + type: "javascript/esm", + resolve: { + mainFields: + options.target === "web" || + options.target === "webworker" || + options.target === "electron-renderer" + ? ["browser", "main"] + : ["main"] + } + }, + { + test: /\.json$/i, + type: "json" + }, + { + test: /\.wasm$/i, + type: "webassembly/experimental" + } + ]); + + this.set("output", "call", (value, options) => { + if (typeof value === "string") { + return { + filename: value + }; + } else if (typeof value !== "object") { + return {}; + } else { + return Object.assign({}, value); + } + }); + + this.set("output.filename", "[name].js"); + this.set("output.chunkFilename", "make", options => { + const filename = options.output.filename; + if (typeof filename !== "function") { + const hasName = filename.includes("[name]"); + const hasId = filename.includes("[id]"); + const hasChunkHash = filename.includes("[chunkhash]"); + // Anything changing depending on chunk is fine + if (hasChunkHash || hasName || hasId) return filename; + // Elsewise prefix "[id]." in front of the basename to make it changing + return filename.replace(/(^|\/)([^/]*(?:\?|$))/, "$1[id].$2"); + } + return "[id].js"; + }); + this.set("output.webassemblyModuleFilename", "[modulehash].module.wasm"); + this.set("output.library", ""); + this.set("output.hotUpdateFunction", "make", options => { + return Template.toIdentifier( + "webpackHotUpdate" + Template.toIdentifier(options.output.library) + ); + }); + this.set("output.jsonpFunction", "make", options => { + return Template.toIdentifier( + "webpackJsonp" + Template.toIdentifier(options.output.library) + ); + }); + this.set("output.chunkCallbackName", "make", options => { + return Template.toIdentifier( + "webpackChunk" + Template.toIdentifier(options.output.library) + ); + }); + this.set("output.globalObject", "make", options => { + switch (options.target) { + case "web": + case "electron-renderer": + case "node-webkit": + return "window"; + case "webworker": + return "self"; + case "node": + case "async-node": + case "electron-main": + return "global"; + default: + return "self"; + } + }); + this.set("output.devtoolNamespace", "make", options => { + return getDevtoolNamespace(options.output.library); + }); + this.set("output.libraryTarget", "var"); + this.set("output.path", path.join(process.cwd(), "dist")); + this.set( + "output.pathinfo", + "make", + options => options.mode === "development" + ); + this.set("output.sourceMapFilename", "[file].map[query]"); + this.set("output.hotUpdateChunkFilename", "[id].[hash].hot-update.js"); + this.set("output.hotUpdateMainFilename", "[hash].hot-update.json"); + this.set("output.crossOriginLoading", false); + this.set("output.jsonpScriptType", false); + this.set("output.chunkLoadTimeout", 120000); + this.set("output.hashFunction", "md4"); + this.set("output.hashDigest", "hex"); + this.set("output.hashDigestLength", 20); + this.set("output.devtoolLineToLine", false); + this.set("output.strictModuleExceptionHandling", false); + + this.set("node", "call", value => { + if (typeof value === "boolean") { + return value; + } else { + return Object.assign({}, value); + } + }); + this.set("node.console", false); + this.set("node.process", true); + this.set("node.global", true); + this.set("node.Buffer", true); + this.set("node.setImmediate", true); + this.set("node.__filename", "mock"); + this.set("node.__dirname", "mock"); + + this.set("performance", "call", (value, options) => { + if (value === false) return false; + if ( + value === undefined && + (!isProductionLikeMode(options) || !isWebLikeTarget(options)) + ) + return false; + return Object.assign({}, value); + }); + this.set("performance.maxAssetSize", 250000); + this.set("performance.maxEntrypointSize", 250000); + this.set("performance.hints", "make", options => + isProductionLikeMode(options) ? "warning" : false + ); + + this.set("optimization", "call", value => Object.assign({}, value)); + // TODO webpack 5: Disable by default in a modes + this.set( + "optimization.removeAvailableModules", + "make", + options => options.mode !== "development" + ); + this.set("optimization.removeEmptyChunks", true); + this.set("optimization.mergeDuplicateChunks", true); + this.set("optimization.flagIncludedChunks", "make", options => + isProductionLikeMode(options) + ); + // TODO webpack 5 add `moduleIds: "named"` default for development + // TODO webpack 5 add `moduleIds: "size"` default for production + // TODO webpack 5 remove optimization.occurrenceOrder + this.set("optimization.occurrenceOrder", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.sideEffects", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.providedExports", true); + this.set("optimization.usedExports", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.concatenateModules", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.splitChunks", {}); + this.set("optimization.splitChunks.hidePathInfo", "make", options => { + return isProductionLikeMode(options); + }); + this.set("optimization.splitChunks.chunks", "async"); + this.set("optimization.splitChunks.minSize", "make", options => { + return isProductionLikeMode(options) ? 30000 : 10000; + }); + this.set("optimization.splitChunks.minChunks", 1); + this.set("optimization.splitChunks.maxAsyncRequests", "make", options => { + return isProductionLikeMode(options) ? 5 : Infinity; + }); + this.set("optimization.splitChunks.automaticNameDelimiter", "~"); + this.set("optimization.splitChunks.automaticNameMaxLength", 109); + this.set("optimization.splitChunks.maxInitialRequests", "make", options => { + return isProductionLikeMode(options) ? 3 : Infinity; + }); + this.set("optimization.splitChunks.name", true); + this.set("optimization.splitChunks.cacheGroups", {}); + this.set("optimization.splitChunks.cacheGroups.default", { + automaticNamePrefix: "", + reuseExistingChunk: true, + minChunks: 2, + priority: -20 + }); + this.set("optimization.splitChunks.cacheGroups.vendors", { + automaticNamePrefix: "vendors", + test: /[\\/]node_modules[\\/]/, + priority: -10 + }); + this.set("optimization.runtimeChunk", "call", value => { + if (value === "single") { + return { + name: "runtime" + }; + } + if (value === true || value === "multiple") { + return { + name: entrypoint => `runtime~${entrypoint.name}` + }; + } + return value; + }); + this.set("optimization.noEmitOnErrors", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.checkWasmTypes", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.mangleWasmImports", false); + // TODO webpack 5 remove optimization.namedModules + this.set( + "optimization.namedModules", + "make", + options => options.mode === "development" + ); + this.set("optimization.hashedModuleIds", false); + // TODO webpack 5 add `chunkIds: "named"` default for development + // TODO webpack 5 add `chunkIds: "size"` default for production + // TODO webpack 5 remove optimization.namedChunks + this.set( + "optimization.namedChunks", + "make", + options => options.mode === "development" + ); + this.set( + "optimization.portableRecords", + "make", + options => + !!( + options.recordsInputPath || + options.recordsOutputPath || + options.recordsPath + ) + ); + this.set("optimization.minimize", "make", options => + isProductionLikeMode(options) + ); + this.set("optimization.minimizer", "make", options => [ + { + apply: compiler => { + // Lazy load the Terser plugin + const TerserPlugin = require("terser-webpack-plugin"); + const SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin"); + new TerserPlugin({ + cache: true, + parallel: true, + sourceMap: + (options.devtool && /source-?map/.test(options.devtool)) || + (options.plugins && + options.plugins.some(p => p instanceof SourceMapDevToolPlugin)) + }).apply(compiler); + } + } + ]); + this.set("optimization.nodeEnv", "make", options => { + // TODO: In webpack 5, it should return `false` when mode is `none` + return options.mode || "production"; + }); + + this.set("resolve", "call", value => Object.assign({}, value)); + this.set("resolve.unsafeCache", true); + this.set("resolve.modules", ["node_modules"]); + this.set("resolve.extensions", [".wasm", ".mjs", ".js", ".json"]); + this.set("resolve.mainFiles", ["index"]); + this.set("resolve.aliasFields", "make", options => { + if ( + options.target === "web" || + options.target === "webworker" || + options.target === "electron-renderer" + ) { + return ["browser"]; + } else { + return []; + } + }); + this.set("resolve.mainFields", "make", options => { + if ( + options.target === "web" || + options.target === "webworker" || + options.target === "electron-renderer" + ) { + return ["browser", "module", "main"]; + } else { + return ["module", "main"]; + } + }); + this.set("resolve.cacheWithContext", "make", options => { + return ( + Array.isArray(options.resolve.plugins) && + options.resolve.plugins.length > 0 + ); + }); + + this.set("resolveLoader", "call", value => Object.assign({}, value)); + this.set("resolveLoader.unsafeCache", true); + this.set("resolveLoader.mainFields", ["loader", "main"]); + this.set("resolveLoader.extensions", [".js", ".json"]); + this.set("resolveLoader.mainFiles", ["index"]); + this.set("resolveLoader.roots", "make", options => [options.context]); + this.set("resolveLoader.cacheWithContext", "make", options => { + return ( + Array.isArray(options.resolveLoader.plugins) && + options.resolveLoader.plugins.length > 0 + ); + }); + + this.set("infrastructureLogging", "call", value => + Object.assign({}, value) + ); + this.set("infrastructureLogging.level", "info"); + this.set("infrastructureLogging.debug", false); + } +} + +module.exports = WebpackOptionsDefaulter; diff --git a/node_modules/webpack/lib/WebpackOptionsValidationError.js b/node_modules/webpack/lib/WebpackOptionsValidationError.js new file mode 100644 index 0000000..5f5da57 --- /dev/null +++ b/node_modules/webpack/lib/WebpackOptionsValidationError.js @@ -0,0 +1,390 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Gajus Kuizinas @gajus +*/ +"use strict"; + +const WebpackError = require("./WebpackError"); +const webpackOptionsSchema = require("../schemas/WebpackOptions.json"); + +const getSchemaPart = (path, parents, additionalPath) => { + parents = parents || 0; + path = path.split("/"); + path = path.slice(0, path.length - parents); + if (additionalPath) { + additionalPath = additionalPath.split("/"); + path = path.concat(additionalPath); + } + let schemaPart = webpackOptionsSchema; + for (let i = 1; i < path.length; i++) { + const inner = schemaPart[path[i]]; + if (inner) schemaPart = inner; + } + return schemaPart; +}; + +const getSchemaPartText = (schemaPart, additionalPath) => { + if (additionalPath) { + for (let i = 0; i < additionalPath.length; i++) { + const inner = schemaPart[additionalPath[i]]; + if (inner) schemaPart = inner; + } + } + while (schemaPart.$ref) { + schemaPart = getSchemaPart(schemaPart.$ref); + } + let schemaText = WebpackOptionsValidationError.formatSchema(schemaPart); + if (schemaPart.description) { + schemaText += `\n-> ${schemaPart.description}`; + } + return schemaText; +}; + +const getSchemaPartDescription = schemaPart => { + while (schemaPart.$ref) { + schemaPart = getSchemaPart(schemaPart.$ref); + } + if (schemaPart.description) { + return `\n-> ${schemaPart.description}`; + } + return ""; +}; + +const SPECIFICITY = { + type: 1, + oneOf: 1, + anyOf: 1, + allOf: 1, + additionalProperties: 2, + enum: 1, + instanceof: 1, + required: 2, + minimum: 2, + uniqueItems: 2, + minLength: 2, + minItems: 2, + minProperties: 2, + absolutePath: 2 +}; + +const filterMax = (array, fn) => { + const max = array.reduce((max, item) => Math.max(max, fn(item)), 0); + return array.filter(item => fn(item) === max); +}; + +const filterChildren = children => { + children = filterMax(children, err => + err.dataPath ? err.dataPath.length : 0 + ); + children = filterMax(children, err => SPECIFICITY[err.keyword] || 2); + return children; +}; + +const indent = (str, prefix, firstLine) => { + if (firstLine) { + return prefix + str.replace(/\n(?!$)/g, "\n" + prefix); + } else { + return str.replace(/\n(?!$)/g, `\n${prefix}`); + } +}; + +class WebpackOptionsValidationError extends WebpackError { + constructor(validationErrors) { + super( + "Invalid configuration object. " + + "Webpack has been initialised using a configuration object that does not match the API schema.\n" + + validationErrors + .map( + err => + " - " + + indent( + WebpackOptionsValidationError.formatValidationError(err), + " ", + false + ) + ) + .join("\n") + ); + + this.name = "WebpackOptionsValidationError"; + this.validationErrors = validationErrors; + + Error.captureStackTrace(this, this.constructor); + } + + static formatSchema(schema, prevSchemas) { + prevSchemas = prevSchemas || []; + + const formatInnerSchema = (innerSchema, addSelf) => { + if (!addSelf) { + return WebpackOptionsValidationError.formatSchema( + innerSchema, + prevSchemas + ); + } + if (prevSchemas.includes(innerSchema)) { + return "(recursive)"; + } + return WebpackOptionsValidationError.formatSchema( + innerSchema, + prevSchemas.concat(schema) + ); + }; + + if (schema.type === "string") { + if (schema.minLength === 1) { + return "non-empty string"; + } + if (schema.minLength > 1) { + return `string (min length ${schema.minLength})`; + } + return "string"; + } + if (schema.type === "boolean") { + return "boolean"; + } + if (schema.type === "number") { + return "number"; + } + if (schema.type === "object") { + if (schema.properties) { + const required = schema.required || []; + return `object { ${Object.keys(schema.properties) + .map(property => { + if (!required.includes(property)) return property + "?"; + return property; + }) + .concat(schema.additionalProperties ? ["…"] : []) + .join(", ")} }`; + } + if (schema.additionalProperties) { + return `object { <key>: ${formatInnerSchema( + schema.additionalProperties + )} }`; + } + return "object"; + } + if (schema.type === "array") { + return `[${formatInnerSchema(schema.items)}]`; + } + + switch (schema.instanceof) { + case "Function": + return "function"; + case "RegExp": + return "RegExp"; + } + + if (schema.enum) { + return schema.enum.map(item => JSON.stringify(item)).join(" | "); + } + + if (schema.$ref) { + return formatInnerSchema(getSchemaPart(schema.$ref), true); + } + if (schema.allOf) { + return schema.allOf.map(formatInnerSchema).join(" & "); + } + if (schema.oneOf) { + return schema.oneOf.map(formatInnerSchema).join(" | "); + } + if (schema.anyOf) { + return schema.anyOf.map(formatInnerSchema).join(" | "); + } + return JSON.stringify(schema, null, 2); + } + + static formatValidationError(err) { + const dataPath = `configuration${err.dataPath}`; + if (err.keyword === "additionalProperties") { + const baseMessage = `${dataPath} has an unknown property '${ + err.params.additionalProperty + }'. These properties are valid:\n${getSchemaPartText(err.parentSchema)}`; + if (!err.dataPath) { + switch (err.params.additionalProperty) { + case "debug": + return ( + `${baseMessage}\n` + + "The 'debug' property was removed in webpack 2.0.0.\n" + + "Loaders should be updated to allow passing this option via loader options in module.rules.\n" + + "Until loaders are updated one can use the LoaderOptionsPlugin to switch loaders into debug mode:\n" + + "plugins: [\n" + + " new webpack.LoaderOptionsPlugin({\n" + + " debug: true\n" + + " })\n" + + "]" + ); + } + return ( + `${baseMessage}\n` + + "For typos: please correct them.\n" + + "For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.\n" + + " Loaders should be updated to allow passing options via loader options in module.rules.\n" + + " Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:\n" + + " plugins: [\n" + + " new webpack.LoaderOptionsPlugin({\n" + + " // test: /\\.xxx$/, // may apply this only for some modules\n" + + " options: {\n" + + ` ${err.params.additionalProperty}: …\n` + + " }\n" + + " })\n" + + " ]" + ); + } + return baseMessage; + } else if (err.keyword === "oneOf" || err.keyword === "anyOf") { + if (err.children && err.children.length > 0) { + if (err.schema.length === 1) { + const lastChild = err.children[err.children.length - 1]; + const remainingChildren = err.children.slice( + 0, + err.children.length - 1 + ); + return WebpackOptionsValidationError.formatValidationError( + Object.assign({}, lastChild, { + children: remainingChildren, + parentSchema: Object.assign( + {}, + err.parentSchema, + lastChild.parentSchema + ) + }) + ); + } + const children = filterChildren(err.children); + if (children.length === 1) { + return WebpackOptionsValidationError.formatValidationError( + children[0] + ); + } + return ( + `${dataPath} should be one of these:\n${getSchemaPartText( + err.parentSchema + )}\n` + + `Details:\n${children + .map( + err => + " * " + + indent( + WebpackOptionsValidationError.formatValidationError(err), + " ", + false + ) + ) + .join("\n")}` + ); + } + return `${dataPath} should be one of these:\n${getSchemaPartText( + err.parentSchema + )}`; + } else if (err.keyword === "enum") { + if ( + err.parentSchema && + err.parentSchema.enum && + err.parentSchema.enum.length === 1 + ) { + return `${dataPath} should be ${getSchemaPartText(err.parentSchema)}`; + } + return `${dataPath} should be one of these:\n${getSchemaPartText( + err.parentSchema + )}`; + } else if (err.keyword === "allOf") { + return `${dataPath} should be:\n${getSchemaPartText(err.parentSchema)}`; + } else if (err.keyword === "type") { + switch (err.params.type) { + case "object": + return `${dataPath} should be an object.${getSchemaPartDescription( + err.parentSchema + )}`; + case "string": + return `${dataPath} should be a string.${getSchemaPartDescription( + err.parentSchema + )}`; + case "boolean": + return `${dataPath} should be a boolean.${getSchemaPartDescription( + err.parentSchema + )}`; + case "number": + return `${dataPath} should be a number.${getSchemaPartDescription( + err.parentSchema + )}`; + case "array": + return `${dataPath} should be an array:\n${getSchemaPartText( + err.parentSchema + )}`; + } + return `${dataPath} should be ${err.params.type}:\n${getSchemaPartText( + err.parentSchema + )}`; + } else if (err.keyword === "instanceof") { + return `${dataPath} should be an instance of ${getSchemaPartText( + err.parentSchema + )}`; + } else if (err.keyword === "required") { + const missingProperty = err.params.missingProperty.replace(/^\./, ""); + return `${dataPath} misses the property '${missingProperty}'.\n${getSchemaPartText( + err.parentSchema, + ["properties", missingProperty] + )}`; + } else if (err.keyword === "minimum") { + return `${dataPath} ${err.message}.${getSchemaPartDescription( + err.parentSchema + )}`; + } else if (err.keyword === "uniqueItems") { + return `${dataPath} should not contain the item '${ + err.data[err.params.i] + }' twice.${getSchemaPartDescription(err.parentSchema)}`; + } else if ( + err.keyword === "minLength" || + err.keyword === "minItems" || + err.keyword === "minProperties" + ) { + if (err.params.limit === 1) { + switch (err.keyword) { + case "minLength": + return `${dataPath} should be an non-empty string.${getSchemaPartDescription( + err.parentSchema + )}`; + case "minItems": + return `${dataPath} should be an non-empty array.${getSchemaPartDescription( + err.parentSchema + )}`; + case "minProperties": + return `${dataPath} should be an non-empty object.${getSchemaPartDescription( + err.parentSchema + )}`; + } + return `${dataPath} should be not empty.${getSchemaPartDescription( + err.parentSchema + )}`; + } else { + return `${dataPath} ${err.message}${getSchemaPartDescription( + err.parentSchema + )}`; + } + } else if (err.keyword === "not") { + return `${dataPath} should not be ${getSchemaPartText( + err.schema + )}\n${getSchemaPartText(err.parentSchema)}`; + } else if (err.keyword === "absolutePath") { + const baseMessage = `${dataPath}: ${ + err.message + }${getSchemaPartDescription(err.parentSchema)}`; + if (dataPath === "configuration.output.filename") { + return ( + `${baseMessage}\n` + + "Please use output.path to specify absolute path and output.filename for the file name." + ); + } + return baseMessage; + } else { + return `${dataPath} ${err.message} (${JSON.stringify( + err, + null, + 2 + )}).\n${getSchemaPartText(err.parentSchema)}`; + } + } +} + +module.exports = WebpackOptionsValidationError; diff --git a/node_modules/webpack/lib/buildChunkGraph.js b/node_modules/webpack/lib/buildChunkGraph.js new file mode 100644 index 0000000..4198441 --- /dev/null +++ b/node_modules/webpack/lib/buildChunkGraph.js @@ -0,0 +1,712 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError"); +const GraphHelpers = require("./GraphHelpers"); + +/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */ +/** @typedef {import("./Chunk")} Chunk */ +/** @typedef {import("./ChunkGroup")} ChunkGroup */ +/** @typedef {import("./Compilation")} Compilation */ +/** @typedef {import("./DependenciesBlock")} DependenciesBlock */ +/** @typedef {import("./Dependency")} Dependency */ +/** @typedef {import("./Entrypoint")} Entrypoint */ +/** @typedef {import("./Module")} Module */ + +/** + * @typedef {Object} QueueItem + * @property {number} action + * @property {DependenciesBlock} block + * @property {Module} module + * @property {Chunk} chunk + * @property {ChunkGroup} chunkGroup + */ + +/** + * @typedef {Object} ChunkGroupInfo + * @property {ChunkGroup} chunkGroup the chunk group + * @property {Set<Module>} minAvailableModules current minimal set of modules available at this point + * @property {boolean} minAvailableModulesOwned true, if minAvailableModules is owned and can be modified + * @property {Set<Module>[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules + * @property {QueueItem[]} skippedItems queue items that were skipped because module is already available in parent chunks (need to reconsider when minAvailableModules is shrinking) + * @property {Set<Module>} resultingAvailableModules set of modules available including modules from this chunk group + * @property {Set<ChunkGroup>} children set of children chunk groups, that will be revisited when availableModules shrink + */ + +/** + * @typedef {Object} BlockChunkGroupConnection + * @property {ChunkGroupInfo} originChunkGroupInfo origin chunk group + * @property {ChunkGroup} chunkGroup referenced chunk group + */ + +/** + * @template T + * @param {Set<T>} a first set + * @param {Set<T>} b second set + * @returns {number} cmp + */ +const bySetSize = (a, b) => { + return b.size - a.size; +}; + +/** + * Extracts simplified info from the modules and their dependencies + * @param {Compilation} compilation the compilation + * @returns {Map<DependenciesBlock, { modules: Iterable<Module>, blocks: AsyncDependenciesBlock[]}>} the mapping block to modules and inner blocks + */ +const extraceBlockInfoMap = compilation => { + /** @type {Map<DependenciesBlock, { modules: Iterable<Module>, blocks: AsyncDependenciesBlock[]}>} */ + const blockInfoMap = new Map(); + + /** + * @param {Dependency} d dependency to iterate over + * @returns {void} + */ + const iteratorDependency = d => { + // We skip Dependencies without Reference + const ref = compilation.getDependencyReference(currentModule, d); + if (!ref) { + return; + } + // We skip Dependencies without Module pointer + const refModule = ref.module; + if (!refModule) { + return; + } + // We skip weak Dependencies + if (ref.weak) { + return; + } + + blockInfoModules.add(refModule); + }; + + /** + * @param {AsyncDependenciesBlock} b blocks to prepare + * @returns {void} + */ + const iteratorBlockPrepare = b => { + blockInfoBlocks.push(b); + blockQueue.push(b); + }; + + /** @type {Module} */ + let currentModule; + /** @type {DependenciesBlock} */ + let block; + /** @type {DependenciesBlock[]} */ + let blockQueue; + /** @type {Set<Module>} */ + let blockInfoModules; + /** @type {AsyncDependenciesBlock[]} */ + let blockInfoBlocks; + + for (const module of compilation.modules) { + blockQueue = [module]; + currentModule = module; + while (blockQueue.length > 0) { + block = blockQueue.pop(); + blockInfoModules = new Set(); + blockInfoBlocks = []; + + if (block.variables) { + for (const variable of block.variables) { + for (const dep of variable.dependencies) iteratorDependency(dep); + } + } + + if (block.dependencies) { + for (const dep of block.dependencies) iteratorDependency(dep); + } + + if (block.blocks) { + for (const b of block.blocks) iteratorBlockPrepare(b); + } + + const blockInfo = { + modules: blockInfoModules, + blocks: blockInfoBlocks + }; + blockInfoMap.set(block, blockInfo); + } + } + + return blockInfoMap; +}; + +/** + * + * @param {Compilation} compilation the compilation + * @param {Entrypoint[]} inputChunkGroups input groups + * @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules + * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks + * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks + * @param {Set<ChunkGroup>} allCreatedChunkGroups filled with all chunk groups that are created here + */ +const visitModules = ( + compilation, + inputChunkGroups, + chunkGroupInfoMap, + blockConnections, + blocksWithNestedBlocks, + allCreatedChunkGroups +) => { + const logger = compilation.getLogger("webpack.buildChunkGraph.visitModules"); + const { namedChunkGroups } = compilation; + + logger.time("prepare"); + const blockInfoMap = extraceBlockInfoMap(compilation); + + /** @type {Map<ChunkGroup, { index: number, index2: number }>} */ + const chunkGroupCounters = new Map(); + for (const chunkGroup of inputChunkGroups) { + chunkGroupCounters.set(chunkGroup, { + index: 0, + index2: 0 + }); + } + + let nextFreeModuleIndex = 0; + let nextFreeModuleIndex2 = 0; + + /** @type {Map<DependenciesBlock, ChunkGroup>} */ + const blockChunkGroups = new Map(); + + const ADD_AND_ENTER_MODULE = 0; + const ENTER_MODULE = 1; + const PROCESS_BLOCK = 2; + const LEAVE_MODULE = 3; + + /** + * @param {QueueItem[]} queue the queue array (will be mutated) + * @param {ChunkGroup} chunkGroup chunk group + * @returns {QueueItem[]} the queue array again + */ + const reduceChunkGroupToQueueItem = (queue, chunkGroup) => { + for (const chunk of chunkGroup.chunks) { + const module = chunk.entryModule; + queue.push({ + action: ENTER_MODULE, + block: module, + module, + chunk, + chunkGroup + }); + } + chunkGroupInfoMap.set(chunkGroup, { + chunkGroup, + minAvailableModules: new Set(), + minAvailableModulesOwned: true, + availableModulesToBeMerged: [], + skippedItems: [], + resultingAvailableModules: undefined, + children: undefined + }); + return queue; + }; + + // Start with the provided modules/chunks + /** @type {QueueItem[]} */ + let queue = inputChunkGroups + .reduce(reduceChunkGroupToQueueItem, []) + .reverse(); + /** @type {Map<ChunkGroup, Set<ChunkGroup>>} */ + const queueConnect = new Map(); + /** @type {Set<ChunkGroupInfo>} */ + const outdatedChunkGroupInfo = new Set(); + /** @type {QueueItem[]} */ + let queueDelayed = []; + + logger.timeEnd("prepare"); + + /** @type {Module} */ + let module; + /** @type {Chunk} */ + let chunk; + /** @type {ChunkGroup} */ + let chunkGroup; + /** @type {ChunkGroupInfo} */ + let chunkGroupInfo; + /** @type {DependenciesBlock} */ + let block; + /** @type {Set<Module>} */ + let minAvailableModules; + /** @type {QueueItem[]} */ + let skippedItems; + + // For each async Block in graph + /** + * @param {AsyncDependenciesBlock} b iterating over each Async DepBlock + * @returns {void} + */ + const iteratorBlock = b => { + // 1. We create a chunk for this Block + // but only once (blockChunkGroups map) + let c = blockChunkGroups.get(b); + if (c === undefined) { + c = namedChunkGroups.get(b.chunkName); + if (c && c.isInitial()) { + compilation.errors.push( + new AsyncDependencyToInitialChunkError(b.chunkName, module, b.loc) + ); + c = chunkGroup; + } else { + c = compilation.addChunkInGroup( + b.groupOptions || b.chunkName, + module, + b.loc, + b.request + ); + chunkGroupCounters.set(c, { index: 0, index2: 0 }); + blockChunkGroups.set(b, c); + allCreatedChunkGroups.add(c); + } + blockConnections.set(b, []); + } else { + // TODO webpack 5 remove addOptions check + if (c.addOptions) c.addOptions(b.groupOptions); + c.addOrigin(module, b.loc, b.request); + } + + // 2. We store the connection for the block + // to connect it later if needed + blockConnections.get(b).push({ + originChunkGroupInfo: chunkGroupInfo, + chunkGroup: c + }); + + // 3. We create/update the chunk group info + let connectList = queueConnect.get(chunkGroup); + if (connectList === undefined) { + connectList = new Set(); + queueConnect.set(chunkGroup, connectList); + } + connectList.add(c); + + // 4. We enqueue the DependenciesBlock for traversal + queueDelayed.push({ + action: PROCESS_BLOCK, + block: b, + module: module, + chunk: c.chunks[0], + chunkGroup: c + }); + }; + + // Iterative traversal of the Module graph + // Recursive would be simpler to write but could result in Stack Overflows + while (queue.length) { + logger.time("visiting"); + while (queue.length) { + const queueItem = queue.pop(); + module = queueItem.module; + block = queueItem.block; + chunk = queueItem.chunk; + if (chunkGroup !== queueItem.chunkGroup) { + chunkGroup = queueItem.chunkGroup; + chunkGroupInfo = chunkGroupInfoMap.get(chunkGroup); + minAvailableModules = chunkGroupInfo.minAvailableModules; + skippedItems = chunkGroupInfo.skippedItems; + } + + switch (queueItem.action) { + case ADD_AND_ENTER_MODULE: { + if (minAvailableModules.has(module)) { + // already in parent chunks + // skip it for now, but enqueue for rechecking when minAvailableModules shrinks + skippedItems.push(queueItem); + break; + } + // We connect Module and Chunk when not already done + if (chunk.addModule(module)) { + module.addChunk(chunk); + } else { + // already connected, skip it + break; + } + } + // fallthrough + case ENTER_MODULE: { + if (chunkGroup !== undefined) { + const index = chunkGroup.getModuleIndex(module); + if (index === undefined) { + chunkGroup.setModuleIndex( + module, + chunkGroupCounters.get(chunkGroup).index++ + ); + } + } + + if (module.index === null) { + module.index = nextFreeModuleIndex++; + } + + queue.push({ + action: LEAVE_MODULE, + block, + module, + chunk, + chunkGroup + }); + } + // fallthrough + case PROCESS_BLOCK: { + // get prepared block info + const blockInfo = blockInfoMap.get(block); + + // Buffer items because order need to be reverse to get indicies correct + const skipBuffer = []; + const queueBuffer = []; + // Traverse all referenced modules + for (const refModule of blockInfo.modules) { + if (chunk.containsModule(refModule)) { + // skip early if already connected + continue; + } + if (minAvailableModules.has(refModule)) { + // already in parent chunks, skip it for now + skipBuffer.push({ + action: ADD_AND_ENTER_MODULE, + block: refModule, + module: refModule, + chunk, + chunkGroup + }); + continue; + } + // enqueue the add and enter to enter in the correct order + // this is relevant with circular dependencies + queueBuffer.push({ + action: ADD_AND_ENTER_MODULE, + block: refModule, + module: refModule, + chunk, + chunkGroup + }); + } + // Add buffered items in reversed order + for (let i = skipBuffer.length - 1; i >= 0; i--) { + skippedItems.push(skipBuffer[i]); + } + for (let i = queueBuffer.length - 1; i >= 0; i--) { + queue.push(queueBuffer[i]); + } + + // Traverse all Blocks + for (const block of blockInfo.blocks) iteratorBlock(block); + + if (blockInfo.blocks.length > 0 && module !== block) { + blocksWithNestedBlocks.add(block); + } + break; + } + case LEAVE_MODULE: { + if (chunkGroup !== undefined) { + const index = chunkGroup.getModuleIndex2(module); + if (index === undefined) { + chunkGroup.setModuleIndex2( + module, + chunkGroupCounters.get(chunkGroup).index2++ + ); + } + } + + if (module.index2 === null) { + module.index2 = nextFreeModuleIndex2++; + } + break; + } + } + } + logger.timeEnd("visiting"); + + while (queueConnect.size > 0) { + logger.time("calculating available modules"); + + // Figure out new parents for chunk groups + // to get new available modules for these children + for (const [chunkGroup, targets] of queueConnect) { + const info = chunkGroupInfoMap.get(chunkGroup); + let minAvailableModules = info.minAvailableModules; + + // 1. Create a new Set of available modules at this points + const resultingAvailableModules = new Set(minAvailableModules); + for (const chunk of chunkGroup.chunks) { + for (const m of chunk.modulesIterable) { + resultingAvailableModules.add(m); + } + } + info.resultingAvailableModules = resultingAvailableModules; + if (info.children === undefined) { + info.children = targets; + } else { + for (const target of targets) { + info.children.add(target); + } + } + + // 2. Update chunk group info + for (const target of targets) { + let chunkGroupInfo = chunkGroupInfoMap.get(target); + if (chunkGroupInfo === undefined) { + chunkGroupInfo = { + chunkGroup: target, + minAvailableModules: undefined, + minAvailableModulesOwned: undefined, + availableModulesToBeMerged: [], + skippedItems: [], + resultingAvailableModules: undefined, + children: undefined + }; + chunkGroupInfoMap.set(target, chunkGroupInfo); + } + chunkGroupInfo.availableModulesToBeMerged.push( + resultingAvailableModules + ); + outdatedChunkGroupInfo.add(chunkGroupInfo); + } + } + queueConnect.clear(); + logger.timeEnd("calculating available modules"); + + if (outdatedChunkGroupInfo.size > 0) { + logger.time("merging available modules"); + // Execute the merge + for (const info of outdatedChunkGroupInfo) { + const availableModulesToBeMerged = info.availableModulesToBeMerged; + let cachedMinAvailableModules = info.minAvailableModules; + + // 1. Get minimal available modules + // It doesn't make sense to traverse a chunk again with more available modules. + // This step calculates the minimal available modules and skips traversal when + // the list didn't shrink. + if (availableModulesToBeMerged.length > 1) { + availableModulesToBeMerged.sort(bySetSize); + } + let changed = false; + for (const availableModules of availableModulesToBeMerged) { + if (cachedMinAvailableModules === undefined) { + cachedMinAvailableModules = availableModules; + info.minAvailableModules = cachedMinAvailableModules; + info.minAvailableModulesOwned = false; + changed = true; + } else { + if (info.minAvailableModulesOwned) { + // We own it and can modify it + for (const m of cachedMinAvailableModules) { + if (!availableModules.has(m)) { + cachedMinAvailableModules.delete(m); + changed = true; + } + } + } else { + for (const m of cachedMinAvailableModules) { + if (!availableModules.has(m)) { + // cachedMinAvailableModules need to be modified + // but we don't own it + // construct a new Set as intersection of cachedMinAvailableModules and availableModules + /** @type {Set<Module>} */ + const newSet = new Set(); + const iterator = cachedMinAvailableModules[ + Symbol.iterator + ](); + /** @type {IteratorResult<Module>} */ + let it; + while (!(it = iterator.next()).done) { + const module = it.value; + if (module === m) break; + newSet.add(module); + } + while (!(it = iterator.next()).done) { + const module = it.value; + if (availableModules.has(module)) { + newSet.add(module); + } + } + cachedMinAvailableModules = newSet; + info.minAvailableModulesOwned = true; + info.minAvailableModules = newSet; + + // Update the cache from the first queue + // if the chunkGroup is currently cached + if (chunkGroup === info.chunkGroup) { + minAvailableModules = cachedMinAvailableModules; + } + + changed = true; + break; + } + } + } + } + } + availableModulesToBeMerged.length = 0; + if (!changed) continue; + + // 2. Reconsider skipped items + for (const queueItem of info.skippedItems) { + queue.push(queueItem); + } + info.skippedItems.length = 0; + + // 3. Reconsider children chunk groups + if (info.children !== undefined) { + const chunkGroup = info.chunkGroup; + for (const c of info.children) { + let connectList = queueConnect.get(chunkGroup); + if (connectList === undefined) { + connectList = new Set(); + queueConnect.set(chunkGroup, connectList); + } + connectList.add(c); + } + } + } + outdatedChunkGroupInfo.clear(); + logger.timeEnd("merging available modules"); + } + } + + // Run queueDelayed when all items of the queue are processed + // This is important to get the global indicing correct + // Async blocks should be processed after all sync blocks are processed + if (queue.length === 0) { + const tempQueue = queue; + queue = queueDelayed.reverse(); + queueDelayed = tempQueue; + } + } +}; + +/** + * + * @param {Set<DependenciesBlock>} blocksWithNestedBlocks flag for blocks that have nested blocks + * @param {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} blockConnections connection for blocks + * @param {Map<ChunkGroup, ChunkGroupInfo>} chunkGroupInfoMap mapping from chunk group to available modules + */ +const connectChunkGroups = ( + blocksWithNestedBlocks, + blockConnections, + chunkGroupInfoMap +) => { + /** + * Helper function to check if all modules of a chunk are available + * + * @param {ChunkGroup} chunkGroup the chunkGroup to scan + * @param {Set<Module>} availableModules the comparitor set + * @returns {boolean} return true if all modules of a chunk are available + */ + const areModulesAvailable = (chunkGroup, availableModules) => { + for (const chunk of chunkGroup.chunks) { + for (const module of chunk.modulesIterable) { + if (!availableModules.has(module)) return false; + } + } + return true; + }; + + // For each edge in the basic chunk graph + for (const [block, connections] of blockConnections) { + // 1. Check if connection is needed + // When none of the dependencies need to be connected + // we can skip all of them + // It's not possible to filter each item so it doesn't create inconsistent + // connections and modules can only create one version + // TODO maybe decide this per runtime + if ( + // TODO is this needed? + !blocksWithNestedBlocks.has(block) && + connections.every(({ chunkGroup, originChunkGroupInfo }) => + areModulesAvailable( + chunkGroup, + originChunkGroupInfo.resultingAvailableModules + ) + ) + ) { + continue; + } + + // 2. Foreach edge + for (let i = 0; i < connections.length; i++) { + const { chunkGroup, originChunkGroupInfo } = connections[i]; + + // 3. Connect block with chunk + GraphHelpers.connectDependenciesBlockAndChunkGroup(block, chunkGroup); + + // 4. Connect chunk with parent + GraphHelpers.connectChunkGroupParentAndChild( + originChunkGroupInfo.chunkGroup, + chunkGroup + ); + } + } +}; + +/** + * Remove all unconnected chunk groups + * @param {Compilation} compilation the compilation + * @param {Iterable<ChunkGroup>} allCreatedChunkGroups all chunk groups that where created before + */ +const cleanupUnconnectedGroups = (compilation, allCreatedChunkGroups) => { + for (const chunkGroup of allCreatedChunkGroups) { + if (chunkGroup.getNumberOfParents() === 0) { + for (const chunk of chunkGroup.chunks) { + const idx = compilation.chunks.indexOf(chunk); + if (idx >= 0) compilation.chunks.splice(idx, 1); + chunk.remove("unconnected"); + } + chunkGroup.remove("unconnected"); + } + } +}; + +/** + * This method creates the Chunk graph from the Module graph + * @param {Compilation} compilation the compilation + * @param {Entrypoint[]} inputChunkGroups chunk groups which are processed + * @returns {void} + */ +const buildChunkGraph = (compilation, inputChunkGroups) => { + // SHARED STATE + + /** @type {Map<AsyncDependenciesBlock, BlockChunkGroupConnection[]>} */ + const blockConnections = new Map(); + + /** @type {Set<ChunkGroup>} */ + const allCreatedChunkGroups = new Set(); + + /** @type {Map<ChunkGroup, ChunkGroupInfo>} */ + const chunkGroupInfoMap = new Map(); + + /** @type {Set<DependenciesBlock>} */ + const blocksWithNestedBlocks = new Set(); + + // PART ONE + + visitModules( + compilation, + inputChunkGroups, + chunkGroupInfoMap, + blockConnections, + blocksWithNestedBlocks, + allCreatedChunkGroups + ); + + // PART TWO + + connectChunkGroups( + blocksWithNestedBlocks, + blockConnections, + chunkGroupInfoMap + ); + + // Cleaup work + + cleanupUnconnectedGroups(compilation, allCreatedChunkGroups); +}; + +module.exports = buildChunkGraph; diff --git a/node_modules/webpack/lib/compareLocations.js b/node_modules/webpack/lib/compareLocations.js new file mode 100644 index 0000000..3840eb8 --- /dev/null +++ b/node_modules/webpack/lib/compareLocations.js @@ -0,0 +1,52 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ + +// TODO webpack 5 remove string type from a and b +/** + * Compare two locations + * @param {string|DependencyLocation} a A location node + * @param {string|DependencyLocation} b A location node + * @returns {-1|0|1} sorting comparator value + */ +module.exports = (a, b) => { + if (typeof a === "string") { + if (typeof b === "string") { + if (a < b) return -1; + if (a > b) return 1; + return 0; + } else if (typeof b === "object") { + return 1; + } else { + return 0; + } + } else if (typeof a === "object") { + if (typeof b === "string") { + return -1; + } else if (typeof b === "object") { + if ("start" in a && "start" in b) { + const ap = a.start; + const bp = b.start; + if (ap.line < bp.line) return -1; + if (ap.line > bp.line) return 1; + if (ap.column < bp.column) return -1; + if (ap.column > bp.column) return 1; + } + if ("name" in a && "name" in b) { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + } + if ("index" in a && "index" in b) { + if (a.index < b.index) return -1; + if (a.index > b.index) return 1; + } + return 0; + } else { + return 0; + } + } +}; diff --git a/node_modules/webpack/lib/debug/ProfilingPlugin.js b/node_modules/webpack/lib/debug/ProfilingPlugin.js new file mode 100644 index 0000000..0ba10ae --- /dev/null +++ b/node_modules/webpack/lib/debug/ProfilingPlugin.js @@ -0,0 +1,442 @@ +const fs = require("fs"); +const path = require("path"); +const mkdirp = require("mkdirp"); +const { Tracer } = require("chrome-trace-event"); +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/debug/ProfilingPlugin.json"); + +/** @typedef {import("../../declarations/plugins/debug/ProfilingPlugin").ProfilingPluginOptions} ProfilingPluginOptions */ + +let inspector = undefined; + +try { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + inspector = require("inspector"); +} catch (e) { + console.log("Unable to CPU profile in < node 8.0"); +} + +class Profiler { + constructor(inspector) { + this.session = undefined; + this.inspector = inspector; + } + + hasSession() { + return this.session !== undefined; + } + + startProfiling() { + if (this.inspector === undefined) { + return Promise.resolve(); + } + + try { + this.session = new inspector.Session(); + this.session.connect(); + } catch (_) { + this.session = undefined; + return Promise.resolve(); + } + + return Promise.all([ + this.sendCommand("Profiler.setSamplingInterval", { + interval: 100 + }), + this.sendCommand("Profiler.enable"), + this.sendCommand("Profiler.start") + ]); + } + + sendCommand(method, params) { + if (this.hasSession()) { + return new Promise((res, rej) => { + return this.session.post(method, params, (err, params) => { + if (err !== null) { + rej(err); + } else { + res(params); + } + }); + }); + } else { + return Promise.resolve(); + } + } + + destroy() { + if (this.hasSession()) { + this.session.disconnect(); + } + + return Promise.resolve(); + } + + stopProfiling() { + return this.sendCommand("Profiler.stop"); + } +} + +/** + * an object that wraps Tracer and Profiler with a counter + * @typedef {Object} Trace + * @property {Tracer} trace instance of Tracer + * @property {number} counter Counter + * @property {Profiler} profiler instance of Profiler + * @property {Function} end the end function + */ + +/** + * @param {string} outputPath The location where to write the log. + * @returns {Trace} The trace object + */ +const createTrace = outputPath => { + const trace = new Tracer({ + noStream: true + }); + const profiler = new Profiler(inspector); + if (/\/|\\/.test(outputPath)) { + const dirPath = path.dirname(outputPath); + mkdirp.sync(dirPath); + } + const fsStream = fs.createWriteStream(outputPath); + + let counter = 0; + + trace.pipe(fsStream); + // These are critical events that need to be inserted so that tools like + // chrome dev tools can load the profile. + trace.instantEvent({ + name: "TracingStartedInPage", + id: ++counter, + cat: ["disabled-by-default-devtools.timeline"], + args: { + data: { + sessionId: "-1", + page: "0xfff", + frames: [ + { + frame: "0xfff", + url: "webpack", + name: "" + } + ] + } + } + }); + + trace.instantEvent({ + name: "TracingStartedInBrowser", + id: ++counter, + cat: ["disabled-by-default-devtools.timeline"], + args: { + data: { + sessionId: "-1" + } + } + }); + + return { + trace, + counter, + profiler, + end: callback => { + // Wait until the write stream finishes. + fsStream.on("finish", () => { + callback(); + }); + // Tear down the readable trace stream. + trace.push(null); + } + }; +}; + +const pluginName = "ProfilingPlugin"; + +class ProfilingPlugin { + /** + * @param {ProfilingPluginOptions=} opts options object + */ + constructor(opts) { + validateOptions(schema, opts || {}, "Profiling plugin"); + opts = opts || {}; + this.outputPath = opts.outputPath || "events.json"; + } + + apply(compiler) { + const tracer = createTrace(this.outputPath); + tracer.profiler.startProfiling(); + + // Compiler Hooks + Object.keys(compiler.hooks).forEach(hookName => { + compiler.hooks[hookName].intercept( + makeInterceptorFor("Compiler", tracer)(hookName) + ); + }); + + Object.keys(compiler.resolverFactory.hooks).forEach(hookName => { + compiler.resolverFactory.hooks[hookName].intercept( + makeInterceptorFor("Resolver", tracer)(hookName) + ); + }); + + compiler.hooks.compilation.tap( + pluginName, + (compilation, { normalModuleFactory, contextModuleFactory }) => { + interceptAllHooksFor(compilation, tracer, "Compilation"); + interceptAllHooksFor( + normalModuleFactory, + tracer, + "Normal Module Factory" + ); + interceptAllHooksFor( + contextModuleFactory, + tracer, + "Context Module Factory" + ); + interceptAllParserHooks(normalModuleFactory, tracer); + interceptTemplateInstancesFrom(compilation, tracer); + } + ); + + // We need to write out the CPU profile when we are all done. + compiler.hooks.done.tapAsync( + { + name: pluginName, + stage: Infinity + }, + (stats, callback) => { + tracer.profiler.stopProfiling().then(parsedResults => { + if (parsedResults === undefined) { + tracer.profiler.destroy(); + tracer.trace.flush(); + tracer.end(callback); + return; + } + + const cpuStartTime = parsedResults.profile.startTime; + const cpuEndTime = parsedResults.profile.endTime; + + tracer.trace.completeEvent({ + name: "TaskQueueManager::ProcessTaskFromWorkQueue", + id: ++tracer.counter, + cat: ["toplevel"], + ts: cpuStartTime, + args: { + src_file: "../../ipc/ipc_moji_bootstrap.cc", + src_func: "Accept" + } + }); + + tracer.trace.completeEvent({ + name: "EvaluateScript", + id: ++tracer.counter, + cat: ["devtools.timeline"], + ts: cpuStartTime, + dur: cpuEndTime - cpuStartTime, + args: { + data: { + url: "webpack", + lineNumber: 1, + columnNumber: 1, + frame: "0xFFF" + } + } + }); + + tracer.trace.instantEvent({ + name: "CpuProfile", + id: ++tracer.counter, + cat: ["disabled-by-default-devtools.timeline"], + ts: cpuEndTime, + args: { + data: { + cpuProfile: parsedResults.profile + } + } + }); + + tracer.profiler.destroy(); + tracer.trace.flush(); + tracer.end(callback); + }); + } + ); + } +} + +const interceptTemplateInstancesFrom = (compilation, tracer) => { + const { + mainTemplate, + chunkTemplate, + hotUpdateChunkTemplate, + moduleTemplates + } = compilation; + + const { javascript, webassembly } = moduleTemplates; + + [ + { + instance: mainTemplate, + name: "MainTemplate" + }, + { + instance: chunkTemplate, + name: "ChunkTemplate" + }, + { + instance: hotUpdateChunkTemplate, + name: "HotUpdateChunkTemplate" + }, + { + instance: javascript, + name: "JavaScriptModuleTemplate" + }, + { + instance: webassembly, + name: "WebAssemblyModuleTemplate" + } + ].forEach(templateObject => { + Object.keys(templateObject.instance.hooks).forEach(hookName => { + templateObject.instance.hooks[hookName].intercept( + makeInterceptorFor(templateObject.name, tracer)(hookName) + ); + }); + }); +}; + +const interceptAllHooksFor = (instance, tracer, logLabel) => { + if (Reflect.has(instance, "hooks")) { + Object.keys(instance.hooks).forEach(hookName => { + instance.hooks[hookName].intercept( + makeInterceptorFor(logLabel, tracer)(hookName) + ); + }); + } +}; + +const interceptAllParserHooks = (moduleFactory, tracer) => { + const moduleTypes = [ + "javascript/auto", + "javascript/dynamic", + "javascript/esm", + "json", + "webassembly/experimental" + ]; + + moduleTypes.forEach(moduleType => { + moduleFactory.hooks.parser + .for(moduleType) + .tap("ProfilingPlugin", (parser, parserOpts) => { + interceptAllHooksFor(parser, tracer, "Parser"); + }); + }); +}; + +const makeInterceptorFor = (instance, tracer) => hookName => ({ + register: ({ name, type, context, fn }) => { + const newFn = makeNewProfiledTapFn(hookName, tracer, { + name, + type, + fn + }); + return { + name, + type, + context, + fn: newFn + }; + } +}); + +// TODO improve typing +/** @typedef {(...args: TODO[]) => void | Promise<TODO>} PluginFunction */ + +/** + * @param {string} hookName Name of the hook to profile. + * @param {Trace} tracer The trace object. + * @param {object} options Options for the profiled fn. + * @param {string} options.name Plugin name + * @param {string} options.type Plugin type (sync | async | promise) + * @param {PluginFunction} options.fn Plugin function + * @returns {PluginFunction} Chainable hooked function. + */ +const makeNewProfiledTapFn = (hookName, tracer, { name, type, fn }) => { + const defaultCategory = ["blink.user_timing"]; + + switch (type) { + case "promise": + return (...args) => { + const id = ++tracer.counter; + tracer.trace.begin({ + name, + id, + cat: defaultCategory + }); + const promise = /** @type {Promise<*>} */ (fn(...args)); + return promise.then(r => { + tracer.trace.end({ + name, + id, + cat: defaultCategory + }); + return r; + }); + }; + case "async": + return (...args) => { + const id = ++tracer.counter; + tracer.trace.begin({ + name, + id, + cat: defaultCategory + }); + const callback = args.pop(); + fn(...args, (...r) => { + tracer.trace.end({ + name, + id, + cat: defaultCategory + }); + callback(...r); + }); + }; + case "sync": + return (...args) => { + const id = ++tracer.counter; + // Do not instrument ourself due to the CPU + // profile needing to be the last event in the trace. + if (name === pluginName) { + return fn(...args); + } + + tracer.trace.begin({ + name, + id, + cat: defaultCategory + }); + let r; + try { + r = fn(...args); + } catch (error) { + tracer.trace.end({ + name, + id, + cat: defaultCategory + }); + throw error; + } + tracer.trace.end({ + name, + id, + cat: defaultCategory + }); + return r; + }; + default: + break; + } +}; + +module.exports = ProfilingPlugin; +module.exports.Profiler = Profiler; diff --git a/node_modules/webpack/lib/dependencies/AMDDefineDependency.js b/node_modules/webpack/lib/dependencies/AMDDefineDependency.js new file mode 100644 index 0000000..fcec365 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDDefineDependency.js @@ -0,0 +1,137 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class AMDDefineDependency extends NullDependency { + constructor(range, arrayRange, functionRange, objectRange, namedModule) { + super(); + this.range = range; + this.arrayRange = arrayRange; + this.functionRange = functionRange; + this.objectRange = objectRange; + this.namedModule = namedModule; + this.localModule = null; + } + + get type() { + return "amd define"; + } +} + +AMDDefineDependency.Template = class AMDDefineDependencyTemplate { + get definitions() { + return { + f: [ + "var __WEBPACK_AMD_DEFINE_RESULT__;", + `!(__WEBPACK_AMD_DEFINE_RESULT__ = (#).call(exports, __webpack_require__, exports, module), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))` + ], + o: ["", "!(module.exports = #)"], + of: [ + "var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;", + `!(__WEBPACK_AMD_DEFINE_FACTORY__ = (#), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))` + ], + af: [ + "var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;", + `!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_RESULT__ = (#).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))` + ], + ao: ["", "!(#, module.exports = #)"], + aof: [ + "var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;", + `!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_FACTORY__ = (#), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))` + ], + lf: [ + "var XXX, XXXmodule;", + "!(XXXmodule = { id: YYY, exports: {}, loaded: false }, XXX = #.call(XXXmodule.exports, __webpack_require__, XXXmodule.exports, XXXmodule), XXXmodule.loaded = true, XXX === undefined && (XXX = XXXmodule.exports))" + ], + lo: ["var XXX;", "!(XXX = #)"], + lof: [ + "var XXX, XXXfactory, XXXmodule;", + "!(XXXfactory = (#), (XXXmodule = { id: YYY, exports: {}, loaded: false }), XXX = (typeof XXXfactory === 'function' ? (XXXfactory.call(XXXmodule.exports, __webpack_require__, XXXmodule.exports, XXXmodule)) : XXXfactory), (XXXmodule.loaded = true), XXX === undefined && (XXX = XXXmodule.exports))" + ], + laf: [ + "var __WEBPACK_AMD_DEFINE_ARRAY__, XXX;", + "!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, XXX = ((#).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)))" + ], + lao: ["var XXX;", "!(#, XXX = #)"], + laof: [ + "var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_FACTORY__, XXX;", + `!(__WEBPACK_AMD_DEFINE_ARRAY__ = #, __WEBPACK_AMD_DEFINE_FACTORY__ = (#), + XXX = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__))` + ] + }; + } + + apply(dependency, source) { + const branch = this.branch(dependency); + const defAndText = this.definitions[branch]; + const definitions = defAndText[0]; + const text = defAndText[1]; + this.replace(dependency, source, definitions, text); + } + + localModuleVar(dependency) { + return ( + dependency.localModule && + dependency.localModule.used && + dependency.localModule.variableName() + ); + } + + branch(dependency) { + const localModuleVar = this.localModuleVar(dependency) ? "l" : ""; + const arrayRange = dependency.arrayRange ? "a" : ""; + const objectRange = dependency.objectRange ? "o" : ""; + const functionRange = dependency.functionRange ? "f" : ""; + return localModuleVar + arrayRange + objectRange + functionRange; + } + + replace(dependency, source, definition, text) { + const localModuleVar = this.localModuleVar(dependency); + if (localModuleVar) { + text = text.replace(/XXX/g, localModuleVar.replace(/\$/g, "$$$$")); + definition = definition.replace( + /XXX/g, + localModuleVar.replace(/\$/g, "$$$$") + ); + } + + if (dependency.namedModule) { + text = text.replace(/YYY/g, JSON.stringify(dependency.namedModule)); + } + + const texts = text.split("#"); + + if (definition) source.insert(0, definition); + + let current = dependency.range[0]; + if (dependency.arrayRange) { + source.replace(current, dependency.arrayRange[0] - 1, texts.shift()); + current = dependency.arrayRange[1]; + } + + if (dependency.objectRange) { + source.replace(current, dependency.objectRange[0] - 1, texts.shift()); + current = dependency.objectRange[1]; + } else if (dependency.functionRange) { + source.replace(current, dependency.functionRange[0] - 1, texts.shift()); + current = dependency.functionRange[1]; + } + source.replace(current, dependency.range[1] - 1, texts.shift()); + if (texts.length > 0) throw new Error("Implementation error"); + } +}; + +module.exports = AMDDefineDependency; diff --git a/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js new file mode 100644 index 0000000..99a1528 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js @@ -0,0 +1,336 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AMDRequireItemDependency = require("./AMDRequireItemDependency"); +const AMDRequireContextDependency = require("./AMDRequireContextDependency"); +const ConstDependency = require("./ConstDependency"); +const AMDDefineDependency = require("./AMDDefineDependency"); +const AMDRequireArrayDependency = require("./AMDRequireArrayDependency"); +const LocalModuleDependency = require("./LocalModuleDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const LocalModulesHelpers = require("./LocalModulesHelpers"); + +const isBoundFunctionExpression = expr => { + if (expr.type !== "CallExpression") return false; + if (expr.callee.type !== "MemberExpression") return false; + if (expr.callee.computed) return false; + if (expr.callee.object.type !== "FunctionExpression") return false; + if (expr.callee.property.type !== "Identifier") return false; + if (expr.callee.property.name !== "bind") return false; + return true; +}; + +const isUnboundFunctionExpression = expr => { + if (expr.type === "FunctionExpression") return true; + if (expr.type === "ArrowFunctionExpression") return true; + return false; +}; + +const isCallable = expr => { + if (isUnboundFunctionExpression(expr)) return true; + if (isBoundFunctionExpression(expr)) return true; + return false; +}; + +class AMDDefineDependencyParserPlugin { + constructor(options) { + this.options = options; + } + + apply(parser) { + parser.hooks.call + .for("define") + .tap( + "AMDDefineDependencyParserPlugin", + this.processCallDefine.bind(this, parser) + ); + } + + processArray(parser, expr, param, identifiers, namedModule) { + if (param.isArray()) { + param.items.forEach((param, idx) => { + if ( + param.isString() && + ["require", "module", "exports"].includes(param.string) + ) + identifiers[idx] = param.string; + const result = this.processItem(parser, expr, param, namedModule); + if (result === undefined) { + this.processContext(parser, expr, param); + } + }); + return true; + } else if (param.isConstArray()) { + const deps = []; + param.array.forEach((request, idx) => { + let dep; + let localModule; + if (request === "require") { + identifiers[idx] = request; + dep = "__webpack_require__"; + } else if (["exports", "module"].includes(request)) { + identifiers[idx] = request; + dep = request; + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + request + )) + ) { + dep = new LocalModuleDependency(localModule, undefined, false); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + } else { + dep = this.newRequireItemDependency(request); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + } + deps.push(dep); + }); + const dep = this.newRequireArrayDependency(deps, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processItem(parser, expr, param, namedModule) { + if (param.isConditional()) { + param.options.forEach(param => { + const result = this.processItem(parser, expr, param); + if (result === undefined) { + this.processContext(parser, expr, param); + } + }); + return true; + } else if (param.isString()) { + let dep, localModule; + if (param.string === "require") { + dep = new ConstDependency("__webpack_require__", param.range); + } else if (["require", "exports", "module"].includes(param.string)) { + dep = new ConstDependency(param.string, param.range); + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + param.string, + namedModule + )) + ) { + dep = new LocalModuleDependency(localModule, param.range, false); + } else { + dep = this.newRequireItemDependency(param.string, param.range); + } + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processContext(parser, expr, param) { + const dep = ContextDependencyHelpers.create( + AMDRequireContextDependency, + param.range, + param, + expr, + this.options, + {}, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + + processCallDefine(parser, expr) { + let array, fn, obj, namedModule; + switch (expr.arguments.length) { + case 1: + if (isCallable(expr.arguments[0])) { + // define(f() {…}) + fn = expr.arguments[0]; + } else if (expr.arguments[0].type === "ObjectExpression") { + // define({…}) + obj = expr.arguments[0]; + } else { + // define(expr) + // unclear if function or object + obj = fn = expr.arguments[0]; + } + break; + case 2: + if (expr.arguments[0].type === "Literal") { + namedModule = expr.arguments[0].value; + // define("…", …) + if (isCallable(expr.arguments[1])) { + // define("…", f() {…}) + fn = expr.arguments[1]; + } else if (expr.arguments[1].type === "ObjectExpression") { + // define("…", {…}) + obj = expr.arguments[1]; + } else { + // define("…", expr) + // unclear if function or object + obj = fn = expr.arguments[1]; + } + } else { + array = expr.arguments[0]; + if (isCallable(expr.arguments[1])) { + // define([…], f() {}) + fn = expr.arguments[1]; + } else if (expr.arguments[1].type === "ObjectExpression") { + // define([…], {…}) + obj = expr.arguments[1]; + } else { + // define([…], expr) + // unclear if function or object + obj = fn = expr.arguments[1]; + } + } + break; + case 3: + // define("…", […], f() {…}) + namedModule = expr.arguments[0].value; + array = expr.arguments[1]; + if (isCallable(expr.arguments[2])) { + // define("…", […], f() {}) + fn = expr.arguments[2]; + } else if (expr.arguments[2].type === "ObjectExpression") { + // define("…", […], {…}) + obj = expr.arguments[2]; + } else { + // define("…", […], expr) + // unclear if function or object + obj = fn = expr.arguments[2]; + } + break; + default: + return; + } + let fnParams = null; + let fnParamsOffset = 0; + if (fn) { + if (isUnboundFunctionExpression(fn)) { + fnParams = fn.params; + } else if (isBoundFunctionExpression(fn)) { + fnParams = fn.callee.object.params; + fnParamsOffset = fn.arguments.length - 1; + if (fnParamsOffset < 0) { + fnParamsOffset = 0; + } + } + } + let fnRenames = parser.scope.renames.createChild(); + if (array) { + const identifiers = {}; + const param = parser.evaluateExpression(array); + const result = this.processArray( + parser, + expr, + param, + identifiers, + namedModule + ); + if (!result) return; + if (fnParams) { + fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { + if (identifiers[idx]) { + fnRenames.set(param.name, identifiers[idx]); + return false; + } + return true; + }); + } + } else { + const identifiers = ["require", "exports", "module"]; + if (fnParams) { + fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { + if (identifiers[idx]) { + fnRenames.set(param.name, identifiers[idx]); + return false; + } + return true; + }); + } + } + let inTry; + if (fn && isUnboundFunctionExpression(fn)) { + inTry = parser.scope.inTry; + parser.inScope(fnParams, () => { + parser.scope.renames = fnRenames; + parser.scope.inTry = inTry; + if (fn.body.type === "BlockStatement") { + parser.walkStatement(fn.body); + } else { + parser.walkExpression(fn.body); + } + }); + } else if (fn && isBoundFunctionExpression(fn)) { + inTry = parser.scope.inTry; + parser.inScope( + fn.callee.object.params.filter( + i => !["require", "module", "exports"].includes(i.name) + ), + () => { + parser.scope.renames = fnRenames; + parser.scope.inTry = inTry; + if (fn.callee.object.body.type === "BlockStatement") { + parser.walkStatement(fn.callee.object.body); + } else { + parser.walkExpression(fn.callee.object.body); + } + } + ); + if (fn.arguments) { + parser.walkExpressions(fn.arguments); + } + } else if (fn || obj) { + parser.walkExpression(fn || obj); + } + + const dep = this.newDefineDependency( + expr.range, + array ? array.range : null, + fn ? fn.range : null, + obj ? obj.range : null, + namedModule ? namedModule : null + ); + dep.loc = expr.loc; + if (namedModule) { + dep.localModule = LocalModulesHelpers.addLocalModule( + parser.state, + namedModule + ); + } + parser.state.current.addDependency(dep); + return true; + } + + newDefineDependency( + range, + arrayRange, + functionRange, + objectRange, + namedModule + ) { + return new AMDDefineDependency( + range, + arrayRange, + functionRange, + objectRange, + namedModule + ); + } + newRequireArrayDependency(depsArray, range) { + return new AMDRequireArrayDependency(depsArray, range); + } + newRequireItemDependency(request, range) { + return new AMDRequireItemDependency(request, range); + } +} +module.exports = AMDDefineDependencyParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/AMDPlugin.js b/node_modules/webpack/lib/dependencies/AMDPlugin.js new file mode 100644 index 0000000..d113491 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDPlugin.js @@ -0,0 +1,249 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const path = require("path"); +const AMDRequireDependency = require("./AMDRequireDependency"); +const AMDRequireItemDependency = require("./AMDRequireItemDependency"); +const AMDRequireArrayDependency = require("./AMDRequireArrayDependency"); +const AMDRequireContextDependency = require("./AMDRequireContextDependency"); +const AMDDefineDependency = require("./AMDDefineDependency"); +const UnsupportedDependency = require("./UnsupportedDependency"); +const LocalModuleDependency = require("./LocalModuleDependency"); + +const NullFactory = require("../NullFactory"); + +const AMDRequireDependenciesBlockParserPlugin = require("./AMDRequireDependenciesBlockParserPlugin"); +const AMDDefineDependencyParserPlugin = require("./AMDDefineDependencyParserPlugin"); + +const AliasPlugin = require("enhanced-resolve/lib/AliasPlugin"); + +const ParserHelpers = require("../ParserHelpers"); + +class AMDPlugin { + constructor(options, amdOptions) { + this.amdOptions = amdOptions; + this.options = options; + } + + apply(compiler) { + const options = this.options; + const amdOptions = this.amdOptions; + compiler.hooks.compilation.tap( + "AMDPlugin", + (compilation, { contextModuleFactory, normalModuleFactory }) => { + compilation.dependencyFactories.set( + AMDRequireDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + AMDRequireDependency, + new AMDRequireDependency.Template() + ); + + compilation.dependencyFactories.set( + AMDRequireItemDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + AMDRequireItemDependency, + new AMDRequireItemDependency.Template() + ); + + compilation.dependencyFactories.set( + AMDRequireArrayDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + AMDRequireArrayDependency, + new AMDRequireArrayDependency.Template() + ); + + compilation.dependencyFactories.set( + AMDRequireContextDependency, + contextModuleFactory + ); + compilation.dependencyTemplates.set( + AMDRequireContextDependency, + new AMDRequireContextDependency.Template() + ); + + compilation.dependencyFactories.set( + AMDDefineDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + AMDDefineDependency, + new AMDDefineDependency.Template() + ); + + compilation.dependencyFactories.set( + UnsupportedDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + UnsupportedDependency, + new UnsupportedDependency.Template() + ); + + compilation.dependencyFactories.set( + LocalModuleDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + LocalModuleDependency, + new LocalModuleDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if (parserOptions.amd !== undefined && !parserOptions.amd) return; + + const setExpressionToModule = (outerExpr, module) => { + parser.hooks.expression.for(outerExpr).tap("AMDPlugin", expr => { + const dep = new AMDRequireItemDependency(module, expr.range); + dep.userRequest = outerExpr; + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + }); + }; + + new AMDRequireDependenciesBlockParserPlugin(options).apply(parser); + new AMDDefineDependencyParserPlugin(options).apply(parser); + + setExpressionToModule("require.amd", "!!webpack amd options"); + setExpressionToModule("define.amd", "!!webpack amd options"); + setExpressionToModule("define", "!!webpack amd define"); + + parser.hooks.expression + .for("__webpack_amd_options__") + .tap("AMDPlugin", () => + parser.state.current.addVariable( + "__webpack_amd_options__", + JSON.stringify(amdOptions) + ) + ); + parser.hooks.evaluateTypeof + .for("define.amd") + .tap( + "AMDPlugin", + ParserHelpers.evaluateToString(typeof amdOptions) + ); + parser.hooks.evaluateTypeof + .for("require.amd") + .tap( + "AMDPlugin", + ParserHelpers.evaluateToString(typeof amdOptions) + ); + parser.hooks.evaluateIdentifier + .for("define.amd") + .tap( + "AMDPlugin", + ParserHelpers.evaluateToIdentifier("define.amd", true) + ); + parser.hooks.evaluateIdentifier + .for("require.amd") + .tap( + "AMDPlugin", + ParserHelpers.evaluateToIdentifier("require.amd", true) + ); + parser.hooks.typeof + .for("define") + .tap( + "AMDPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + parser.hooks.evaluateTypeof + .for("define") + .tap("AMDPlugin", ParserHelpers.evaluateToString("function")); + parser.hooks.canRename + .for("define") + .tap("AMDPlugin", ParserHelpers.approve); + parser.hooks.rename.for("define").tap("AMDPlugin", expr => { + const dep = new AMDRequireItemDependency( + "!!webpack amd define", + expr.range + ); + dep.userRequest = "define"; + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return false; + }); + parser.hooks.typeof + .for("require") + .tap( + "AMDPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + parser.hooks.evaluateTypeof + .for("require") + .tap("AMDPlugin", ParserHelpers.evaluateToString("function")); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("AMDPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("AMDPlugin", handler); + } + ); + compiler.hooks.afterResolvers.tap("AMDPlugin", () => { + compiler.resolverFactory.hooks.resolver + .for("normal") + .tap("AMDPlugin", resolver => { + new AliasPlugin( + "described-resolve", + { + name: "amdefine", + alias: path.join( + __dirname, + "..", + "..", + "buildin", + "amd-define.js" + ) + }, + "resolve" + ).apply(resolver); + new AliasPlugin( + "described-resolve", + { + name: "webpack amd options", + alias: path.join( + __dirname, + "..", + "..", + "buildin", + "amd-options.js" + ) + }, + "resolve" + ).apply(resolver); + new AliasPlugin( + "described-resolve", + { + name: "webpack amd define", + alias: path.join( + __dirname, + "..", + "..", + "buildin", + "amd-define.js" + ) + }, + "resolve" + ).apply(resolver); + }); + }); + } +} +module.exports = AMDPlugin; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireArrayDependency.js b/node_modules/webpack/lib/dependencies/AMDRequireArrayDependency.js new file mode 100644 index 0000000..ddb9c29 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireArrayDependency.js @@ -0,0 +1,49 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const Dependency = require("../Dependency"); + +class AMDRequireArrayDependency extends Dependency { + constructor(depsArray, range) { + super(); + this.depsArray = depsArray; + this.range = range; + } + + get type() { + return "amd require array"; + } +} + +AMDRequireArrayDependency.Template = class AMDRequireArrayDependencyTemplate { + apply(dep, source, runtime) { + const content = this.getContent(dep, runtime); + source.replace(dep.range[0], dep.range[1] - 1, content); + } + + getContent(dep, runtime) { + const requires = dep.depsArray.map(dependency => { + return this.contentForDependency(dependency, runtime); + }); + return `[${requires.join(", ")}]`; + } + + contentForDependency(dep, runtime) { + if (typeof dep === "string") { + return dep; + } + + if (dep.localModule) { + return dep.localModule.variableName(); + } else { + return runtime.moduleExports({ + module: dep.module, + request: dep.request + }); + } + } +}; + +module.exports = AMDRequireArrayDependency; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireContextDependency.js b/node_modules/webpack/lib/dependencies/AMDRequireContextDependency.js new file mode 100644 index 0000000..b2e60b5 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireContextDependency.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ContextDependency = require("./ContextDependency"); +class AMDRequireContextDependency extends ContextDependency { + constructor(options, range, valueRange) { + super(options); + this.range = range; + this.valueRange = valueRange; + } + + get type() { + return "amd require context"; + } +} +AMDRequireContextDependency.Template = require("./ContextDependencyTemplateAsRequireCall"); +module.exports = AMDRequireContextDependency; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlock.js b/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlock.js new file mode 100644 index 0000000..bd7e7b8 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlock.js @@ -0,0 +1,47 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const AsyncDependenciesBlock = require("../AsyncDependenciesBlock"); +const AMDRequireDependency = require("./AMDRequireDependency"); + +module.exports = class AMDRequireDependenciesBlock extends AsyncDependenciesBlock { + constructor( + expr, + arrayRange, + functionRange, + errorCallbackRange, + module, + loc, + request + ) { + super(null, module, loc, request); + this.expr = expr; + this.outerRange = expr.range; + this.arrayRange = arrayRange; + this.functionBindThis = false; + this.functionRange = functionRange; + this.errorCallbackBindThis = false; + this.errorCallbackRange = errorCallbackRange; + this.bindThis = true; + if (arrayRange && functionRange && errorCallbackRange) { + this.range = [arrayRange[0], errorCallbackRange[1]]; + } else if (arrayRange && functionRange) { + this.range = [arrayRange[0], functionRange[1]]; + } else if (arrayRange) { + this.range = arrayRange; + } else if (functionRange) { + this.range = functionRange; + } else { + this.range = expr.range; + } + const dep = this.newRequireDependency(); + dep.loc = loc; + this.addDependency(dep); + } + + newRequireDependency() { + return new AMDRequireDependency(this); + } +}; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js b/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js new file mode 100644 index 0000000..ea52d81 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js @@ -0,0 +1,274 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AMDRequireItemDependency = require("./AMDRequireItemDependency"); +const AMDRequireArrayDependency = require("./AMDRequireArrayDependency"); +const AMDRequireContextDependency = require("./AMDRequireContextDependency"); +const AMDRequireDependenciesBlock = require("./AMDRequireDependenciesBlock"); +const UnsupportedDependency = require("./UnsupportedDependency"); +const LocalModuleDependency = require("./LocalModuleDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const LocalModulesHelpers = require("./LocalModulesHelpers"); +const ConstDependency = require("./ConstDependency"); +const getFunctionExpression = require("./getFunctionExpression"); +const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); + +class AMDRequireDependenciesBlockParserPlugin { + constructor(options) { + this.options = options; + } + + processFunctionArgument(parser, expression) { + let bindThis = true; + const fnData = getFunctionExpression(expression); + if (fnData) { + parser.inScope( + fnData.fn.params.filter(i => { + return !["require", "module", "exports"].includes(i.name); + }), + () => { + if (fnData.fn.body.type === "BlockStatement") { + parser.walkStatement(fnData.fn.body); + } else { + parser.walkExpression(fnData.fn.body); + } + } + ); + parser.walkExpressions(fnData.expressions); + if (fnData.needThis === false) { + bindThis = false; + } + } else { + parser.walkExpression(expression); + } + return bindThis; + } + + apply(parser) { + parser.hooks.call + .for("require") + .tap( + "AMDRequireDependenciesBlockParserPlugin", + this.processCallRequire.bind(this, parser) + ); + } + + processArray(parser, expr, param) { + if (param.isArray()) { + for (const p of param.items) { + const result = this.processItem(parser, expr, p); + if (result === undefined) { + this.processContext(parser, expr, p); + } + } + return true; + } else if (param.isConstArray()) { + const deps = []; + for (const request of param.array) { + let dep, localModule; + if (request === "require") { + dep = "__webpack_require__"; + } else if (["exports", "module"].includes(request)) { + dep = request; + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + request + )) + ) { + dep = new LocalModuleDependency(localModule, undefined, false); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + } else { + dep = this.newRequireItemDependency(request); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + } + deps.push(dep); + } + const dep = this.newRequireArrayDependency(deps, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processItem(parser, expr, param) { + if (param.isConditional()) { + for (const p of param.options) { + const result = this.processItem(parser, expr, p); + if (result === undefined) { + this.processContext(parser, expr, p); + } + } + return true; + } else if (param.isString()) { + let dep, localModule; + if (param.string === "require") { + dep = new ConstDependency("__webpack_require__", param.string); + } else if (param.string === "module") { + dep = new ConstDependency( + parser.state.module.buildInfo.moduleArgument, + param.range + ); + } else if (param.string === "exports") { + dep = new ConstDependency( + parser.state.module.buildInfo.exportsArgument, + param.range + ); + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + param.string + )) + ) { + dep = new LocalModuleDependency(localModule, param.range, false); + } else { + dep = this.newRequireItemDependency(param.string, param.range); + } + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processContext(parser, expr, param) { + const dep = ContextDependencyHelpers.create( + AMDRequireContextDependency, + param.range, + param, + expr, + this.options, + {}, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + + processArrayForRequestString(param) { + if (param.isArray()) { + const result = param.items.map(item => + this.processItemForRequestString(item) + ); + if (result.every(Boolean)) return result.join(" "); + } else if (param.isConstArray()) { + return param.array.join(" "); + } + } + + processItemForRequestString(param) { + if (param.isConditional()) { + const result = param.options.map(item => + this.processItemForRequestString(item) + ); + if (result.every(Boolean)) return result.join("|"); + } else if (param.isString()) { + return param.string; + } + } + + processCallRequire(parser, expr) { + let param; + let dep; + let result; + + const old = parser.state.current; + + if (expr.arguments.length >= 1) { + param = parser.evaluateExpression(expr.arguments[0]); + dep = this.newRequireDependenciesBlock( + expr, + param.range, + expr.arguments.length > 1 ? expr.arguments[1].range : null, + expr.arguments.length > 2 ? expr.arguments[2].range : null, + parser.state.module, + expr.loc, + this.processArrayForRequestString(param) + ); + parser.state.current = dep; + } + + if (expr.arguments.length === 1) { + parser.inScope([], () => { + result = this.processArray(parser, expr, param); + }); + parser.state.current = old; + if (!result) return; + parser.state.current.addBlock(dep); + return true; + } + + if (expr.arguments.length === 2 || expr.arguments.length === 3) { + try { + parser.inScope([], () => { + result = this.processArray(parser, expr, param); + }); + if (!result) { + dep = new UnsupportedDependency("unsupported", expr.range); + old.addDependency(dep); + if (parser.state.module) { + parser.state.module.errors.push( + new UnsupportedFeatureWarning( + parser.state.module, + "Cannot statically analyse 'require(…, …)' in line " + + expr.loc.start.line, + expr.loc + ) + ); + } + dep = null; + return true; + } + dep.functionBindThis = this.processFunctionArgument( + parser, + expr.arguments[1] + ); + if (expr.arguments.length === 3) { + dep.errorCallbackBindThis = this.processFunctionArgument( + parser, + expr.arguments[2] + ); + } + } finally { + parser.state.current = old; + if (dep) parser.state.current.addBlock(dep); + } + return true; + } + } + + newRequireDependenciesBlock( + expr, + arrayRange, + functionRange, + errorCallbackRange, + module, + loc, + request + ) { + return new AMDRequireDependenciesBlock( + expr, + arrayRange, + functionRange, + errorCallbackRange, + module, + loc, + request + ); + } + newRequireItemDependency(request, range) { + return new AMDRequireItemDependency(request, range); + } + newRequireArrayDependency(depsArray, range) { + return new AMDRequireArrayDependency(depsArray, range); + } +} +module.exports = AMDRequireDependenciesBlockParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireDependency.js b/node_modules/webpack/lib/dependencies/AMDRequireDependency.js new file mode 100644 index 0000000..fd514e2 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireDependency.js @@ -0,0 +1,135 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class AMDRequireDependency extends NullDependency { + constructor(block) { + super(); + this.block = block; + } +} + +AMDRequireDependency.Template = class AMDRequireDependencyTemplate { + apply(dep, source, runtime) { + const depBlock = dep.block; + const promise = runtime.blockPromise({ + block: depBlock, + message: "AMD require" + }); + + // has array range but no function range + if (depBlock.arrayRange && !depBlock.functionRange) { + const startBlock = `${promise}.then(function() {`; + const endBlock = `;}).catch(${runtime.onError()})`; + source.replace( + depBlock.outerRange[0], + depBlock.arrayRange[0] - 1, + startBlock + ); + source.replace( + depBlock.arrayRange[1], + depBlock.outerRange[1] - 1, + endBlock + ); + return; + } + + // has function range but no array range + if (depBlock.functionRange && !depBlock.arrayRange) { + const startBlock = `${promise}.then((`; + const endBlock = `).bind(exports, __webpack_require__, exports, module)).catch(${runtime.onError()})`; + source.replace( + depBlock.outerRange[0], + depBlock.functionRange[0] - 1, + startBlock + ); + source.replace( + depBlock.functionRange[1], + depBlock.outerRange[1] - 1, + endBlock + ); + return; + } + + // has array range, function range, and errorCallbackRange + if ( + depBlock.arrayRange && + depBlock.functionRange && + depBlock.errorCallbackRange + ) { + const startBlock = `${promise}.then(function() { `; + const errorRangeBlock = `}${ + depBlock.functionBindThis ? ".bind(this)" : "" + }).catch(`; + const endBlock = `${ + depBlock.errorCallbackBindThis ? ".bind(this)" : "" + })`; + + source.replace( + depBlock.outerRange[0], + depBlock.arrayRange[0] - 1, + startBlock + ); + source.insert( + depBlock.arrayRange[0] + 0.9, + "var __WEBPACK_AMD_REQUIRE_ARRAY__ = " + ); + source.replace( + depBlock.arrayRange[1], + depBlock.functionRange[0] - 1, + "; (" + ); + source.insert( + depBlock.functionRange[1], + ").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__);" + ); + source.replace( + depBlock.functionRange[1], + depBlock.errorCallbackRange[0] - 1, + errorRangeBlock + ); + source.replace( + depBlock.errorCallbackRange[1], + depBlock.outerRange[1] - 1, + endBlock + ); + return; + } + + // has array range, function range, but no errorCallbackRange + if (depBlock.arrayRange && depBlock.functionRange) { + const startBlock = `${promise}.then(function() { `; + const endBlock = `}${ + depBlock.functionBindThis ? ".bind(this)" : "" + }).catch(${runtime.onError()})`; + source.replace( + depBlock.outerRange[0], + depBlock.arrayRange[0] - 1, + startBlock + ); + source.insert( + depBlock.arrayRange[0] + 0.9, + "var __WEBPACK_AMD_REQUIRE_ARRAY__ = " + ); + source.replace( + depBlock.arrayRange[1], + depBlock.functionRange[0] - 1, + "; (" + ); + source.insert( + depBlock.functionRange[1], + ").apply(null, __WEBPACK_AMD_REQUIRE_ARRAY__);" + ); + source.replace( + depBlock.functionRange[1], + depBlock.outerRange[1] - 1, + endBlock + ); + } + } +}; + +module.exports = AMDRequireDependency; diff --git a/node_modules/webpack/lib/dependencies/AMDRequireItemDependency.js b/node_modules/webpack/lib/dependencies/AMDRequireItemDependency.js new file mode 100644 index 0000000..d033a90 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/AMDRequireItemDependency.js @@ -0,0 +1,22 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const ModuleDependencyTemplateAsRequireId = require("./ModuleDependencyTemplateAsRequireId"); + +class AMDRequireItemDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + } + + get type() { + return "amd require"; + } +} + +AMDRequireItemDependency.Template = ModuleDependencyTemplateAsRequireId; + +module.exports = AMDRequireItemDependency; diff --git a/node_modules/webpack/lib/dependencies/CommonJsPlugin.js b/node_modules/webpack/lib/dependencies/CommonJsPlugin.js new file mode 100644 index 0000000..6d441a8 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/CommonJsPlugin.js @@ -0,0 +1,158 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ConstDependency = require("./ConstDependency"); +const CommonJsRequireDependency = require("./CommonJsRequireDependency"); +const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); +const RequireResolveDependency = require("./RequireResolveDependency"); +const RequireResolveContextDependency = require("./RequireResolveContextDependency"); +const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); +const RequireHeaderDependency = require("./RequireHeaderDependency"); + +const NullFactory = require("../NullFactory"); + +const RequireResolveDependencyParserPlugin = require("./RequireResolveDependencyParserPlugin"); +const CommonJsRequireDependencyParserPlugin = require("./CommonJsRequireDependencyParserPlugin"); + +const ParserHelpers = require("../ParserHelpers"); + +class CommonJsPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap( + "CommonJsPlugin", + (compilation, { contextModuleFactory, normalModuleFactory }) => { + compilation.dependencyFactories.set( + CommonJsRequireDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + CommonJsRequireDependency, + new CommonJsRequireDependency.Template() + ); + + compilation.dependencyFactories.set( + CommonJsRequireContextDependency, + contextModuleFactory + ); + compilation.dependencyTemplates.set( + CommonJsRequireContextDependency, + new CommonJsRequireContextDependency.Template() + ); + + compilation.dependencyFactories.set( + RequireResolveDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + RequireResolveDependency, + new RequireResolveDependency.Template() + ); + + compilation.dependencyFactories.set( + RequireResolveContextDependency, + contextModuleFactory + ); + compilation.dependencyTemplates.set( + RequireResolveContextDependency, + new RequireResolveContextDependency.Template() + ); + + compilation.dependencyFactories.set( + RequireResolveHeaderDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + RequireResolveHeaderDependency, + new RequireResolveHeaderDependency.Template() + ); + + compilation.dependencyFactories.set( + RequireHeaderDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + RequireHeaderDependency, + new RequireHeaderDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if (parserOptions.commonjs !== undefined && !parserOptions.commonjs) + return; + + const requireExpressions = [ + "require", + "require.resolve", + "require.resolveWeak" + ]; + for (let expression of requireExpressions) { + parser.hooks.typeof + .for(expression) + .tap( + "CommonJsPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + parser.hooks.evaluateTypeof + .for(expression) + .tap( + "CommonJsPlugin", + ParserHelpers.evaluateToString("function") + ); + parser.hooks.evaluateIdentifier + .for(expression) + .tap( + "CommonJsPlugin", + ParserHelpers.evaluateToIdentifier(expression, true) + ); + } + + parser.hooks.evaluateTypeof + .for("module") + .tap("CommonJsPlugin", ParserHelpers.evaluateToString("object")); + parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => { + // to not leak to global "require", we need to define a local require here. + const dep = new ConstDependency("var require;", 0); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + parser.scope.definitions.add("require"); + return true; + }); + parser.hooks.canRename + .for("require") + .tap("CommonJsPlugin", () => true); + parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => { + // define the require variable. It's still undefined, but not "not defined". + const dep = new ConstDependency("var require;", 0); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return false; + }); + parser.hooks.typeof.for("module").tap("CommonJsPlugin", () => true); + parser.hooks.evaluateTypeof + .for("exports") + .tap("CommonJsPlugin", ParserHelpers.evaluateToString("object")); + + new CommonJsRequireDependencyParserPlugin(options).apply(parser); + new RequireResolveDependencyParserPlugin(options).apply(parser); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("CommonJsPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("CommonJsPlugin", handler); + } + ); + } +} +module.exports = CommonJsPlugin; diff --git a/node_modules/webpack/lib/dependencies/CommonJsRequireContextDependency.js b/node_modules/webpack/lib/dependencies/CommonJsRequireContextDependency.js new file mode 100644 index 0000000..723a849 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/CommonJsRequireContextDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ContextDependency = require("./ContextDependency"); +const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall"); + +class CommonJsRequireContextDependency extends ContextDependency { + constructor(options, range, valueRange) { + super(options); + this.range = range; + this.valueRange = valueRange; + } + + get type() { + return "cjs require context"; + } +} + +CommonJsRequireContextDependency.Template = ContextDependencyTemplateAsRequireCall; + +module.exports = CommonJsRequireContextDependency; diff --git a/node_modules/webpack/lib/dependencies/CommonJsRequireDependency.js b/node_modules/webpack/lib/dependencies/CommonJsRequireDependency.js new file mode 100644 index 0000000..29a30f3 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/CommonJsRequireDependency.js @@ -0,0 +1,22 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const ModuleDependencyTemplateAsId = require("./ModuleDependencyTemplateAsId"); + +class CommonJsRequireDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + } + + get type() { + return "cjs require"; + } +} + +CommonJsRequireDependency.Template = ModuleDependencyTemplateAsId; + +module.exports = CommonJsRequireDependency; diff --git a/node_modules/webpack/lib/dependencies/CommonJsRequireDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/CommonJsRequireDependencyParserPlugin.js new file mode 100644 index 0000000..b0faa1a --- /dev/null +++ b/node_modules/webpack/lib/dependencies/CommonJsRequireDependencyParserPlugin.js @@ -0,0 +1,138 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const CommonJsRequireDependency = require("./CommonJsRequireDependency"); +const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); +const RequireHeaderDependency = require("./RequireHeaderDependency"); +const LocalModuleDependency = require("./LocalModuleDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const LocalModulesHelpers = require("./LocalModulesHelpers"); +const ParserHelpers = require("../ParserHelpers"); + +class CommonJsRequireDependencyParserPlugin { + constructor(options) { + this.options = options; + } + + apply(parser) { + const options = this.options; + + const processItem = (expr, param) => { + if (param.isString()) { + const dep = new CommonJsRequireDependency(param.string, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + }; + const processContext = (expr, param) => { + const dep = ContextDependencyHelpers.create( + CommonJsRequireContextDependency, + expr.range, + param, + expr, + options, + {}, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }; + + parser.hooks.expression + .for("require.cache") + .tap( + "CommonJsRequireDependencyParserPlugin", + ParserHelpers.toConstantDependencyWithWebpackRequire( + parser, + "__webpack_require__.c" + ) + ); + parser.hooks.expression + .for("require") + .tap("CommonJsRequireDependencyParserPlugin", expr => { + const dep = new CommonJsRequireContextDependency( + { + request: options.unknownContextRequest, + recursive: options.unknownContextRecursive, + regExp: options.unknownContextRegExp, + mode: "sync" + }, + expr.range + ); + dep.critical = + options.unknownContextCritical && + "require function is used in a way in which dependencies cannot be statically extracted"; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }); + + const createHandler = callNew => expr => { + if (expr.arguments.length !== 1) return; + let localModule; + const param = parser.evaluateExpression(expr.arguments[0]); + if (param.isConditional()) { + let isExpression = false; + const prevLength = parser.state.current.dependencies.length; + const dep = new RequireHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + for (const p of param.options) { + const result = processItem(expr, p); + if (result === undefined) { + isExpression = true; + } + } + if (isExpression) { + parser.state.current.dependencies.length = prevLength; + } else { + return true; + } + } + if ( + param.isString() && + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + param.string + )) + ) { + const dep = new LocalModuleDependency(localModule, expr.range, callNew); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + } else { + const result = processItem(expr, param); + if (result === undefined) { + processContext(expr, param); + } else { + const dep = new RequireHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + } + return true; + } + }; + parser.hooks.call + .for("require") + .tap("CommonJsRequireDependencyParserPlugin", createHandler(false)); + parser.hooks.new + .for("require") + .tap("CommonJsRequireDependencyParserPlugin", createHandler(true)); + parser.hooks.call + .for("module.require") + .tap("CommonJsRequireDependencyParserPlugin", createHandler(false)); + parser.hooks.new + .for("module.require") + .tap("CommonJsRequireDependencyParserPlugin", createHandler(true)); + } +} +module.exports = CommonJsRequireDependencyParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/ConstDependency.js b/node_modules/webpack/lib/dependencies/ConstDependency.js new file mode 100644 index 0000000..22edb8e --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ConstDependency.js @@ -0,0 +1,33 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class ConstDependency extends NullDependency { + constructor(expression, range, requireWebpackRequire) { + super(); + this.expression = expression; + this.range = range; + this.requireWebpackRequire = requireWebpackRequire; + } + + updateHash(hash) { + hash.update(this.range + ""); + hash.update(this.expression + ""); + } +} + +ConstDependency.Template = class ConstDependencyTemplate { + apply(dep, source) { + if (typeof dep.range === "number") { + source.insert(dep.range, dep.expression); + return; + } + + source.replace(dep.range[0], dep.range[1] - 1, dep.expression); + } +}; + +module.exports = ConstDependency; diff --git a/node_modules/webpack/lib/dependencies/ContextDependency.js b/node_modules/webpack/lib/dependencies/ContextDependency.js new file mode 100644 index 0000000..10c2fea --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ContextDependency.js @@ -0,0 +1,68 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const Dependency = require("../Dependency"); +const CriticalDependencyWarning = require("./CriticalDependencyWarning"); + +const regExpToString = r => (r ? r + "" : ""); + +class ContextDependency extends Dependency { + // options: { request, recursive, regExp, include, exclude, mode, chunkName, groupOptions } + constructor(options) { + super(); + this.options = options; + this.userRequest = this.options.request; + /** @type {false | string} */ + this.critical = false; + this.hadGlobalOrStickyRegExp = false; + if (this.options.regExp.global || this.options.regExp.sticky) { + this.options.regExp = null; + this.hadGlobalOrStickyRegExp = true; + } + } + + getResourceIdentifier() { + return ( + `context${this.options.request} ${this.options.recursive} ` + + `${regExpToString(this.options.regExp)} ${regExpToString( + this.options.include + )} ${regExpToString(this.options.exclude)} ` + + `${this.options.mode} ${this.options.chunkName} ` + + `${JSON.stringify(this.options.groupOptions)}` + ); + } + + getWarnings() { + let warnings = super.getWarnings() || []; + if (this.critical) { + warnings.push(new CriticalDependencyWarning(this.critical)); + } + if (this.hadGlobalOrStickyRegExp) { + warnings.push( + new CriticalDependencyWarning( + "Contexts can't use RegExps with the 'g' or 'y' flags." + ) + ); + } + return warnings; + } +} + +// TODO remove in webpack 5 +Object.defineProperty(ContextDependency.prototype, "async", { + configurable: false, + get() { + throw new Error( + "ContextDependency.async was removed. Use ContextDependency.options.mode instead." + ); + }, + set() { + throw new Error( + "ContextDependency.async was removed. Pass options.mode to constructor instead" + ); + } +}); + +module.exports = ContextDependency; diff --git a/node_modules/webpack/lib/dependencies/ContextDependencyHelpers.js b/node_modules/webpack/lib/dependencies/ContextDependencyHelpers.js new file mode 100644 index 0000000..377425b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ContextDependencyHelpers.js @@ -0,0 +1,232 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ContextDependencyHelpers = exports; + +/** + * Escapes regular expression metacharacters + * @param {string} str String to quote + * @returns {string} Escaped string + */ +const quotemeta = str => { + return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&"); +}; + +const splitContextFromPrefix = prefix => { + const idx = prefix.lastIndexOf("/"); + let context = "."; + if (idx >= 0) { + context = prefix.substr(0, idx); + prefix = `.${prefix.substr(idx)}`; + } + return { + context, + prefix + }; +}; + +const splitQueryFromPostfix = postfix => { + const idx = postfix.indexOf("?"); + let query = ""; + if (idx >= 0) { + query = postfix.substr(idx); + postfix = postfix.substr(0, idx); + } + return { + postfix, + query + }; +}; + +ContextDependencyHelpers.create = ( + Dep, + range, + param, + expr, + options, + contextOptions, + // when parser is not passed in, expressions won't be walked + parser = null +) => { + if (param.isTemplateString()) { + let prefixRaw = param.quasis[0].string; + let postfixRaw = + param.quasis.length > 1 + ? param.quasis[param.quasis.length - 1].string + : ""; + + const valueRange = param.range; + const { context, prefix } = splitContextFromPrefix(prefixRaw); + const { postfix, query } = splitQueryFromPostfix(postfixRaw); + + // When there are more than two quasis, the generated RegExp can be more precise + // We join the quasis with the expression regexp + const innerQuasis = param.quasis.slice(1, param.quasis.length - 1); + const innerRegExp = + options.wrappedContextRegExp.source + + innerQuasis + .map(q => quotemeta(q.string) + options.wrappedContextRegExp.source) + .join(""); + + // Example: `./context/pre${e}inner${e}inner2${e}post?query` + // context: "./context" + // prefix: "./pre" + // innerQuasis: [BEE("inner"), BEE("inner2")] + // (BEE = BasicEvaluatedExpression) + // postfix: "post" + // query: "?query" + // regExp: /^\.\/pre.*inner.*inner2.*post$/ + const regExp = new RegExp( + `^${quotemeta(prefix)}${innerRegExp}${quotemeta(postfix)}$` + ); + const dep = new Dep( + Object.assign( + { + request: context + query, + recursive: options.wrappedContextRecursive, + regExp, + mode: "sync" + }, + contextOptions + ), + range, + valueRange + ); + dep.loc = expr.loc; + const replaces = []; + + param.parts.forEach((part, i) => { + if (i % 2 === 0) { + // Quasis or merged quasi + let range = part.range; + let value = part.string; + if (param.templateStringKind === "cooked") { + value = JSON.stringify(value); + value = value.slice(1, value.length - 1); + } + if (i === 0) { + // prefix + value = prefix; + range = [param.range[0], part.range[1]]; + value = + (param.templateStringKind === "cooked" ? "`" : "String.raw`") + + value; + } else if (i === param.parts.length - 1) { + // postfix + value = postfix; + range = [part.range[0], param.range[1]]; + value = value + "`"; + } else if ( + part.expression && + part.expression.type === "TemplateElement" && + part.expression.value.raw === value + ) { + // Shortcut when it's a single quasi and doesn't need to be replaced + return; + } + replaces.push({ + range, + value + }); + } else { + // Expression + if (parser) { + parser.walkExpression(part.expression); + } + } + }); + + dep.replaces = replaces; + dep.critical = + options.wrappedContextCritical && + "a part of the request of a dependency is an expression"; + return dep; + } else if ( + param.isWrapped() && + ((param.prefix && param.prefix.isString()) || + (param.postfix && param.postfix.isString())) + ) { + let prefixRaw = + param.prefix && param.prefix.isString() ? param.prefix.string : ""; + let postfixRaw = + param.postfix && param.postfix.isString() ? param.postfix.string : ""; + const prefixRange = + param.prefix && param.prefix.isString() ? param.prefix.range : null; + const postfixRange = + param.postfix && param.postfix.isString() ? param.postfix.range : null; + const valueRange = param.range; + const { context, prefix } = splitContextFromPrefix(prefixRaw); + const { postfix, query } = splitQueryFromPostfix(postfixRaw); + const regExp = new RegExp( + `^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta( + postfix + )}$` + ); + const dep = new Dep( + Object.assign( + { + request: context + query, + recursive: options.wrappedContextRecursive, + regExp, + mode: "sync" + }, + contextOptions + ), + range, + valueRange + ); + dep.loc = expr.loc; + const replaces = []; + if (prefixRange) { + replaces.push({ + range: prefixRange, + value: JSON.stringify(prefix) + }); + } + if (postfixRange) { + replaces.push({ + range: postfixRange, + value: JSON.stringify(postfix) + }); + } + dep.replaces = replaces; + dep.critical = + options.wrappedContextCritical && + "a part of the request of a dependency is an expression"; + + if (parser && param.wrappedInnerExpressions) { + for (const part of param.wrappedInnerExpressions) { + if (part.expression) parser.walkExpression(part.expression); + } + } + + return dep; + } else { + const dep = new Dep( + Object.assign( + { + request: options.exprContextRequest, + recursive: options.exprContextRecursive, + regExp: options.exprContextRegExp, + mode: "sync" + }, + contextOptions + ), + range, + param.range + ); + dep.loc = expr.loc; + dep.critical = + options.exprContextCritical && + "the request of a dependency is an expression"; + + if (parser) { + parser.walkExpression(param.expression); + } + + return dep; + } +}; diff --git a/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsId.js b/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsId.js new file mode 100644 index 0000000..1ee83ff --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsId.js @@ -0,0 +1,43 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class ContextDependencyTemplateAsId { + apply(dep, source, runtime) { + const moduleExports = runtime.moduleExports({ + module: dep.module, + request: dep.request + }); + + if (dep.module) { + if (dep.valueRange) { + if (Array.isArray(dep.replaces)) { + for (let i = 0; i < dep.replaces.length; i++) { + const rep = dep.replaces[i]; + source.replace(rep.range[0], rep.range[1] - 1, rep.value); + } + } + source.replace(dep.valueRange[1], dep.range[1] - 1, ")"); + // TODO webpack 5 remove `prepend` it's no longer used + source.replace( + dep.range[0], + dep.valueRange[0] - 1, + `${moduleExports}.resolve(${ + typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "" + }` + ); + } else { + source.replace( + dep.range[0], + dep.range[1] - 1, + `${moduleExports}.resolve` + ); + } + } else { + source.replace(dep.range[0], dep.range[1] - 1, moduleExports); + } + } +} +module.exports = ContextDependencyTemplateAsId; diff --git a/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsRequireCall.js b/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsRequireCall.js new file mode 100644 index 0000000..6d833ac --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ContextDependencyTemplateAsRequireCall.js @@ -0,0 +1,39 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class ContextDependencyTemplateAsRequireCall { + apply(dep, source, runtime) { + const moduleExports = runtime.moduleExports({ + module: dep.module, + request: dep.request + }); + + if (dep.module) { + if (dep.valueRange) { + if (Array.isArray(dep.replaces)) { + for (let i = 0; i < dep.replaces.length; i++) { + const rep = dep.replaces[i]; + source.replace(rep.range[0], rep.range[1] - 1, rep.value); + } + } + source.replace(dep.valueRange[1], dep.range[1] - 1, ")"); + // TODO webpack 5 remove `prepend` it's no longer used + source.replace( + dep.range[0], + dep.valueRange[0] - 1, + `${moduleExports}(${ + typeof dep.prepend === "string" ? JSON.stringify(dep.prepend) : "" + }` + ); + } else { + source.replace(dep.range[0], dep.range[1] - 1, moduleExports); + } + } else { + source.replace(dep.range[0], dep.range[1] - 1, moduleExports); + } + } +} +module.exports = ContextDependencyTemplateAsRequireCall; diff --git a/node_modules/webpack/lib/dependencies/ContextElementDependency.js b/node_modules/webpack/lib/dependencies/ContextElementDependency.js new file mode 100644 index 0000000..2587704 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ContextElementDependency.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class ContextElementDependency extends ModuleDependency { + constructor(request, userRequest) { + super(request); + if (userRequest) { + this.userRequest = userRequest; + } + } + + get type() { + return "context element"; + } +} + +module.exports = ContextElementDependency; diff --git a/node_modules/webpack/lib/dependencies/CriticalDependencyWarning.js b/node_modules/webpack/lib/dependencies/CriticalDependencyWarning.js new file mode 100644 index 0000000..43bd568 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/CriticalDependencyWarning.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); + +class CriticalDependencyWarning extends WebpackError { + constructor(message) { + super(); + + this.name = "CriticalDependencyWarning"; + this.message = "Critical dependency: " + message; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = CriticalDependencyWarning; diff --git a/node_modules/webpack/lib/dependencies/DelegatedExportsDependency.js b/node_modules/webpack/lib/dependencies/DelegatedExportsDependency.js new file mode 100644 index 0000000..fcacedb --- /dev/null +++ b/node_modules/webpack/lib/dependencies/DelegatedExportsDependency.js @@ -0,0 +1,33 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const NullDependency = require("./NullDependency"); + +class DelegatedExportsDependency extends NullDependency { + constructor(originModule, exports) { + super(); + this.originModule = originModule; + this.exports = exports; + } + + get type() { + return "delegated exports"; + } + + getReference() { + return new DependencyReference(this.originModule, true, false); + } + + getExports() { + return { + exports: this.exports, + dependencies: undefined + }; + } +} + +module.exports = DelegatedExportsDependency; diff --git a/node_modules/webpack/lib/dependencies/DelegatedSourceDependency.js b/node_modules/webpack/lib/dependencies/DelegatedSourceDependency.js new file mode 100644 index 0000000..7b0b9de --- /dev/null +++ b/node_modules/webpack/lib/dependencies/DelegatedSourceDependency.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class DelegatedSourceDependency extends ModuleDependency { + constructor(request) { + super(request); + } + + get type() { + return "delegated source"; + } +} + +module.exports = DelegatedSourceDependency; diff --git a/node_modules/webpack/lib/dependencies/DependencyReference.js b/node_modules/webpack/lib/dependencies/DependencyReference.js new file mode 100644 index 0000000..a8f6afa --- /dev/null +++ b/node_modules/webpack/lib/dependencies/DependencyReference.js @@ -0,0 +1,64 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Florent Cailhol @ooflorent +*/ +"use strict"; + +/** @typedef {import("../Module")} Module */ + +class DependencyReference { + // TODO webpack 5: module must be dynamic, you must pass a function returning a module + // This is needed to remove the hack in ConcatenatedModule + // The problem is that the `module` in Dependency could be replaced i. e. because of Scope Hoisting + /** + * + * @param {Module} module the referenced module + * @param {string[] | boolean} importedNames imported named from the module + * @param {boolean=} weak if this is a weak reference + * @param {number} order the order information or NaN if don't care + */ + constructor(module, importedNames, weak = false, order = NaN) { + // TODO webpack 5: make it a getter + this.module = module; + // true: full object + // false: only sideeffects/no export + // array of strings: the exports with this names + this.importedNames = importedNames; + this.weak = !!weak; + this.order = order; + } + + /** + * @param {DependencyReference[]} array an array (will be modified) + * @returns {DependencyReference[]} the array again + */ + static sort(array) { + /** @type {WeakMap<DependencyReference, number>} */ + const originalOrder = new WeakMap(); + let i = 0; + for (const ref of array) { + originalOrder.set(ref, i++); + } + return array.sort((a, b) => { + const aOrder = a.order; + const bOrder = b.order; + if (isNaN(aOrder)) { + if (!isNaN(bOrder)) { + return 1; + } + } else { + if (isNaN(bOrder)) { + return -1; + } + if (aOrder !== bOrder) { + return aOrder - bOrder; + } + } + const aOrg = originalOrder.get(a); + const bOrg = originalOrder.get(b); + return aOrg - bOrg; + }); + } +} + +module.exports = DependencyReference; diff --git a/node_modules/webpack/lib/dependencies/DllEntryDependency.js b/node_modules/webpack/lib/dependencies/DllEntryDependency.js new file mode 100644 index 0000000..47c6acc --- /dev/null +++ b/node_modules/webpack/lib/dependencies/DllEntryDependency.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const Dependency = require("../Dependency"); + +class DllEntryDependency extends Dependency { + constructor(dependencies, name) { + super(); + this.dependencies = dependencies; + this.name = name; + } + + get type() { + return "dll entry"; + } +} + +module.exports = DllEntryDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyAcceptDependency.js b/node_modules/webpack/lib/dependencies/HarmonyAcceptDependency.js new file mode 100644 index 0000000..edb7b01 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyAcceptDependency.js @@ -0,0 +1,48 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const NullDependency = require("./NullDependency"); +const HarmonyImportDependency = require("./HarmonyImportDependency"); + +class HarmonyAcceptDependency extends NullDependency { + constructor(range, dependencies, hasCallback) { + super(); + this.range = range; + this.dependencies = dependencies; + this.hasCallback = hasCallback; + } + + get type() { + return "accepted harmony modules"; + } +} + +HarmonyAcceptDependency.Template = class HarmonyAcceptDependencyTemplate { + apply(dep, source, runtime) { + const content = dep.dependencies + .filter(dependency => + HarmonyImportDependency.Template.isImportEmitted(dependency, source) + ) + .map(dependency => dependency.getImportStatement(true, runtime)) + .join(""); + + if (dep.hasCallback) { + source.insert( + dep.range[0], + `function(__WEBPACK_OUTDATED_DEPENDENCIES__) { ${content}(` + ); + source.insert( + dep.range[1], + ")(__WEBPACK_OUTDATED_DEPENDENCIES__); }.bind(this)" + ); + return; + } + + source.insert(dep.range[1] - 0.5, `, function() { ${content} }`); + } +}; + +module.exports = HarmonyAcceptDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyAcceptImportDependency.js b/node_modules/webpack/lib/dependencies/HarmonyAcceptImportDependency.js new file mode 100644 index 0000000..62bd00c --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyAcceptImportDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const HarmonyImportDependency = require("./HarmonyImportDependency"); + +class HarmonyAcceptImportDependency extends HarmonyImportDependency { + constructor(request, originModule, parserScope) { + super(request, originModule, NaN, parserScope); + this.weak = true; + } + + get type() { + return "harmony accept"; + } +} + +HarmonyAcceptImportDependency.Template = class HarmonyAcceptImportDependencyTemplate extends HarmonyImportDependency.Template { + apply(dep, source, runtime) {} +}; + +module.exports = HarmonyAcceptImportDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyCompatibilityDependency.js b/node_modules/webpack/lib/dependencies/HarmonyCompatibilityDependency.js new file mode 100644 index 0000000..d6febb5 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyCompatibilityDependency.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class HarmonyCompatibilityDependency extends NullDependency { + constructor(originModule) { + super(); + this.originModule = originModule; + } + + get type() { + return "harmony export header"; + } +} + +HarmonyCompatibilityDependency.Template = class HarmonyExportDependencyTemplate { + apply(dep, source, runtime) { + const usedExports = dep.originModule.usedExports; + if (usedExports !== false && !Array.isArray(usedExports)) { + const content = runtime.defineEsModuleFlagStatement({ + exportsArgument: dep.originModule.exportsArgument + }); + source.insert(-10, content); + } + } +}; + +module.exports = HarmonyCompatibilityDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyDetectionParserPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyDetectionParserPlugin.js new file mode 100644 index 0000000..1a0872f --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyDetectionParserPlugin.js @@ -0,0 +1,96 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency"); +const HarmonyInitDependency = require("./HarmonyInitDependency"); + +module.exports = class HarmonyDetectionParserPlugin { + apply(parser) { + parser.hooks.program.tap("HarmonyDetectionParserPlugin", ast => { + const isStrictHarmony = parser.state.module.type === "javascript/esm"; + const isHarmony = + isStrictHarmony || + ast.body.some( + statement => + statement.type === "ImportDeclaration" || + statement.type === "ExportDefaultDeclaration" || + statement.type === "ExportNamedDeclaration" || + statement.type === "ExportAllDeclaration" + ); + if (isHarmony) { + const module = parser.state.module; + const compatDep = new HarmonyCompatibilityDependency(module); + compatDep.loc = { + start: { + line: -1, + column: 0 + }, + end: { + line: -1, + column: 0 + }, + index: -3 + }; + module.addDependency(compatDep); + const initDep = new HarmonyInitDependency(module); + initDep.loc = { + start: { + line: -1, + column: 0 + }, + end: { + line: -1, + column: 0 + }, + index: -2 + }; + module.addDependency(initDep); + parser.state.harmonyParserScope = parser.state.harmonyParserScope || {}; + parser.scope.isStrict = true; + module.buildMeta.exportsType = "namespace"; + module.buildInfo.strict = true; + module.buildInfo.exportsArgument = "__webpack_exports__"; + if (isStrictHarmony) { + module.buildMeta.strictHarmonyModule = true; + module.buildInfo.moduleArgument = "__webpack_module__"; + } + } + }); + + const skipInHarmony = () => { + const module = parser.state.module; + if (module && module.buildMeta && module.buildMeta.exportsType) { + return true; + } + }; + + const nullInHarmony = () => { + const module = parser.state.module; + if (module && module.buildMeta && module.buildMeta.exportsType) { + return null; + } + }; + + const nonHarmonyIdentifiers = ["define", "exports"]; + for (const identifer of nonHarmonyIdentifiers) { + parser.hooks.evaluateTypeof + .for(identifer) + .tap("HarmonyDetectionParserPlugin", nullInHarmony); + parser.hooks.typeof + .for(identifer) + .tap("HarmonyDetectionParserPlugin", skipInHarmony); + parser.hooks.evaluate + .for(identifer) + .tap("HarmonyDetectionParserPlugin", nullInHarmony); + parser.hooks.expression + .for(identifer) + .tap("HarmonyDetectionParserPlugin", skipInHarmony); + parser.hooks.call + .for(identifer) + .tap("HarmonyDetectionParserPlugin", skipInHarmony); + } + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyExportDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyExportDependencyParserPlugin.js new file mode 100644 index 0000000..6ab0c0f --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyExportDependencyParserPlugin.js @@ -0,0 +1,154 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency"); +const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency"); +const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency"); +const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency"); +const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency"); +const ConstDependency = require("./ConstDependency"); + +module.exports = class HarmonyExportDependencyParserPlugin { + constructor(moduleOptions) { + this.strictExportPresence = moduleOptions.strictExportPresence; + } + + apply(parser) { + parser.hooks.export.tap( + "HarmonyExportDependencyParserPlugin", + statement => { + const dep = new HarmonyExportHeaderDependency( + statement.declaration && statement.declaration.range, + statement.range + ); + dep.loc = Object.create(statement.loc); + dep.loc.index = -1; + parser.state.current.addDependency(dep); + return true; + } + ); + parser.hooks.exportImport.tap( + "HarmonyExportDependencyParserPlugin", + (statement, source) => { + parser.state.lastHarmonyImportOrder = + (parser.state.lastHarmonyImportOrder || 0) + 1; + const clearDep = new ConstDependency("", statement.range); + clearDep.loc = Object.create(statement.loc); + clearDep.loc.index = -1; + parser.state.current.addDependency(clearDep); + const sideEffectDep = new HarmonyImportSideEffectDependency( + source, + parser.state.module, + parser.state.lastHarmonyImportOrder, + parser.state.harmonyParserScope + ); + sideEffectDep.loc = Object.create(statement.loc); + sideEffectDep.loc.index = -1; + parser.state.current.addDependency(sideEffectDep); + return true; + } + ); + parser.hooks.exportExpression.tap( + "HarmonyExportDependencyParserPlugin", + (statement, expr) => { + const comments = parser.getComments([ + statement.range[0], + expr.range[0] + ]); + const dep = new HarmonyExportExpressionDependency( + parser.state.module, + expr.range, + statement.range, + comments + .map(c => { + switch (c.type) { + case "Block": + return `/*${c.value}*/`; + case "Line": + return `//${c.value}\n`; + } + return ""; + }) + .join("") + ); + dep.loc = Object.create(statement.loc); + dep.loc.index = -1; + parser.state.current.addDependency(dep); + return true; + } + ); + parser.hooks.exportDeclaration.tap( + "HarmonyExportDependencyParserPlugin", + statement => {} + ); + parser.hooks.exportSpecifier.tap( + "HarmonyExportDependencyParserPlugin", + (statement, id, name, idx) => { + const rename = parser.scope.renames.get(id); + let dep; + const harmonyNamedExports = (parser.state.harmonyNamedExports = + parser.state.harmonyNamedExports || new Set()); + harmonyNamedExports.add(name); + if (rename === "imported var") { + const settings = parser.state.harmonySpecifier.get(id); + dep = new HarmonyExportImportedSpecifierDependency( + settings.source, + parser.state.module, + settings.sourceOrder, + parser.state.harmonyParserScope, + settings.id, + name, + harmonyNamedExports, + null, + this.strictExportPresence + ); + } else { + dep = new HarmonyExportSpecifierDependency( + parser.state.module, + id, + name + ); + } + dep.loc = Object.create(statement.loc); + dep.loc.index = idx; + parser.state.current.addDependency(dep); + return true; + } + ); + parser.hooks.exportImportSpecifier.tap( + "HarmonyExportDependencyParserPlugin", + (statement, source, id, name, idx) => { + const harmonyNamedExports = (parser.state.harmonyNamedExports = + parser.state.harmonyNamedExports || new Set()); + let harmonyStarExports = null; + if (name) { + harmonyNamedExports.add(name); + } else { + harmonyStarExports = parser.state.harmonyStarExports = + parser.state.harmonyStarExports || []; + } + const dep = new HarmonyExportImportedSpecifierDependency( + source, + parser.state.module, + parser.state.lastHarmonyImportOrder, + parser.state.harmonyParserScope, + id, + name, + harmonyNamedExports, + harmonyStarExports && harmonyStarExports.slice(), + this.strictExportPresence + ); + if (harmonyStarExports) { + harmonyStarExports.push(dep); + } + dep.loc = Object.create(statement.loc); + dep.loc.index = idx; + parser.state.current.addDependency(dep); + return true; + } + ); + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyExportExpressionDependency.js b/node_modules/webpack/lib/dependencies/HarmonyExportExpressionDependency.js new file mode 100644 index 0000000..dfb499a --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyExportExpressionDependency.js @@ -0,0 +1,58 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class HarmonyExportExpressionDependency extends NullDependency { + constructor(originModule, range, rangeStatement, prefix) { + super(); + this.originModule = originModule; + this.range = range; + this.rangeStatement = rangeStatement; + this.prefix = prefix; + } + + get type() { + return "harmony export expression"; + } + + getExports() { + return { + exports: ["default"], + dependencies: undefined + }; + } +} + +HarmonyExportExpressionDependency.Template = class HarmonyExportDependencyTemplate { + apply(dep, source) { + const used = dep.originModule.isUsed("default"); + const content = this.getContent(dep.originModule, used); + + if (dep.range) { + source.replace( + dep.rangeStatement[0], + dep.range[0] - 1, + content + "(" + dep.prefix + ); + source.replace(dep.range[1], dep.rangeStatement[1] - 1, ");"); + return; + } + + source.replace(dep.rangeStatement[0], dep.rangeStatement[1] - 1, content); + } + + getContent(module, used) { + const exportsName = module.exportsArgument; + if (used) { + return `/* harmony default export */ ${exportsName}[${JSON.stringify( + used + )}] = `; + } + return "/* unused harmony default export */ var _unused_webpack_default_export = "; + } +}; + +module.exports = HarmonyExportExpressionDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyExportHeaderDependency.js b/node_modules/webpack/lib/dependencies/HarmonyExportHeaderDependency.js new file mode 100644 index 0000000..a0e9918 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyExportHeaderDependency.js @@ -0,0 +1,30 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class HarmonyExportHeaderDependency extends NullDependency { + constructor(range, rangeStatement) { + super(); + this.range = range; + this.rangeStatement = rangeStatement; + } + + get type() { + return "harmony export header"; + } +} + +HarmonyExportHeaderDependency.Template = class HarmonyExportDependencyTemplate { + apply(dep, source) { + const content = ""; + const replaceUntil = dep.range + ? dep.range[0] - 1 + : dep.rangeStatement[1] - 1; + source.replace(dep.rangeStatement[0], replaceUntil, content); + } +}; + +module.exports = HarmonyExportHeaderDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency.js b/node_modules/webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency.js new file mode 100644 index 0000000..bca61a0 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyExportImportedSpecifierDependency.js @@ -0,0 +1,659 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const HarmonyImportDependency = require("./HarmonyImportDependency"); +const Template = require("../Template"); +const HarmonyLinkingError = require("../HarmonyLinkingError"); + +/** @typedef {import("../Module")} Module */ + +/** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-non-harmony-default-strict"|"reexport-fake-namespace-object"|"rexport-non-harmony-undefined"|"safe-reexport"|"checked-reexport"|"dynamic-reexport"} ExportModeType */ + +/** @type {Map<string, string>} */ +const EMPTY_MAP = new Map(); + +class ExportMode { + /** + * @param {ExportModeType} type type of the mode + */ + constructor(type) { + /** @type {ExportModeType} */ + this.type = type; + /** @type {string|null} */ + this.name = null; + /** @type {Map<string, string>} */ + this.map = EMPTY_MAP; + /** @type {Set<string>|null} */ + this.ignored = null; + /** @type {Module|null} */ + this.module = null; + /** @type {string|null} */ + this.userRequest = null; + } +} + +const EMPTY_STAR_MODE = new ExportMode("empty-star"); + +class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { + constructor( + request, + originModule, + sourceOrder, + parserScope, + id, + name, + activeExports, + otherStarExports, + strictExportPresence + ) { + super(request, originModule, sourceOrder, parserScope); + this.id = id; + this.redirectedId = undefined; + this.name = name; + this.activeExports = activeExports; + this.otherStarExports = otherStarExports; + this.strictExportPresence = strictExportPresence; + } + + get type() { + return "harmony export imported specifier"; + } + + get _id() { + return this.redirectedId || this.id; + } + + getMode(ignoreUnused) { + const name = this.name; + const id = this._id; + const used = this.originModule.isUsed(name); + const importedModule = this._module; + + if (!importedModule) { + const mode = new ExportMode("missing"); + mode.userRequest = this.userRequest; + return mode; + } + + if ( + !ignoreUnused && + (name ? !used : this.originModule.usedExports === false) + ) { + const mode = new ExportMode("unused"); + mode.name = name || "*"; + return mode; + } + + const strictHarmonyModule = this.originModule.buildMeta.strictHarmonyModule; + if (name && id === "default" && importedModule.buildMeta) { + if (!importedModule.buildMeta.exportsType) { + const mode = new ExportMode( + strictHarmonyModule + ? "reexport-non-harmony-default-strict" + : "reexport-non-harmony-default" + ); + mode.name = name; + mode.module = importedModule; + return mode; + } else if (importedModule.buildMeta.exportsType === "named") { + const mode = new ExportMode("reexport-named-default"); + mode.name = name; + mode.module = importedModule; + return mode; + } + } + + const isNotAHarmonyModule = + importedModule.buildMeta && !importedModule.buildMeta.exportsType; + if (name) { + let mode; + if (id) { + // export { name as name } + if (isNotAHarmonyModule && strictHarmonyModule) { + mode = new ExportMode("rexport-non-harmony-undefined"); + mode.name = name; + } else { + mode = new ExportMode("safe-reexport"); + mode.map = new Map([[name, id]]); + } + } else { + // export { * as name } + if (isNotAHarmonyModule && strictHarmonyModule) { + mode = new ExportMode("reexport-fake-namespace-object"); + mode.name = name; + } else { + mode = new ExportMode("reexport-namespace-object"); + mode.name = name; + } + } + mode.module = importedModule; + return mode; + } + + const hasUsedExports = Array.isArray(this.originModule.usedExports); + const hasProvidedExports = Array.isArray( + importedModule.buildMeta.providedExports + ); + const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports(); + + // export * + if (hasUsedExports) { + // reexport * with known used exports + if (hasProvidedExports) { + const map = new Map( + this.originModule.usedExports + .filter(id => { + if (id === "default") return false; + if (this.activeExports.has(id)) return false; + if (activeFromOtherStarExports.has(id)) return false; + if (!importedModule.buildMeta.providedExports.includes(id)) + return false; + return true; + }) + .map(item => [item, item]) + ); + + if (map.size === 0) { + return EMPTY_STAR_MODE; + } + + const mode = new ExportMode("safe-reexport"); + mode.module = importedModule; + mode.map = map; + return mode; + } + + const map = new Map( + this.originModule.usedExports + .filter(id => { + if (id === "default") return false; + if (this.activeExports.has(id)) return false; + if (activeFromOtherStarExports.has(id)) return false; + + return true; + }) + .map(item => [item, item]) + ); + + if (map.size === 0) { + return EMPTY_STAR_MODE; + } + + const mode = new ExportMode("checked-reexport"); + mode.module = importedModule; + mode.map = map; + return mode; + } + + if (hasProvidedExports) { + const map = new Map( + importedModule.buildMeta.providedExports + .filter(id => { + if (id === "default") return false; + if (this.activeExports.has(id)) return false; + if (activeFromOtherStarExports.has(id)) return false; + + return true; + }) + .map(item => [item, item]) + ); + + if (map.size === 0) { + return EMPTY_STAR_MODE; + } + + const mode = new ExportMode("safe-reexport"); + mode.module = importedModule; + mode.map = map; + return mode; + } + + const mode = new ExportMode("dynamic-reexport"); + mode.module = importedModule; + mode.ignored = new Set([ + "default", + ...this.activeExports, + ...activeFromOtherStarExports + ]); + return mode; + } + + getReference() { + const mode = this.getMode(false); + + switch (mode.type) { + case "missing": + case "unused": + case "empty-star": + return null; + + case "reexport-non-harmony-default": + case "reexport-named-default": + return new DependencyReference( + mode.module, + ["default"], + false, + this.sourceOrder + ); + + case "reexport-namespace-object": + case "reexport-non-harmony-default-strict": + case "reexport-fake-namespace-object": + case "rexport-non-harmony-undefined": + return new DependencyReference( + mode.module, + true, + false, + this.sourceOrder + ); + + case "safe-reexport": + case "checked-reexport": + return new DependencyReference( + mode.module, + Array.from(mode.map.values()), + false, + this.sourceOrder + ); + + case "dynamic-reexport": + return new DependencyReference( + mode.module, + true, + false, + this.sourceOrder + ); + + default: + throw new Error(`Unknown mode ${mode.type}`); + } + } + + _discoverActiveExportsFromOtherStartExports() { + if (!this.otherStarExports) return new Set(); + const result = new Set(); + // try to learn impossible exports from other star exports with provided exports + for (const otherStarExport of this.otherStarExports) { + const otherImportedModule = otherStarExport._module; + if ( + otherImportedModule && + Array.isArray(otherImportedModule.buildMeta.providedExports) + ) { + for (const exportName of otherImportedModule.buildMeta + .providedExports) { + result.add(exportName); + } + } + } + return result; + } + + getExports() { + if (this.name) { + return { + exports: [this.name], + dependencies: undefined + }; + } + + const importedModule = this._module; + + if (!importedModule) { + // no imported module available + return { + exports: null, + dependencies: undefined + }; + } + + if (Array.isArray(importedModule.buildMeta.providedExports)) { + const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports(); + return { + exports: importedModule.buildMeta.providedExports.filter( + id => + id !== "default" && + !activeFromOtherStarExports.has(id) && + !this.activeExports.has(id) + ), + dependencies: [importedModule] + }; + } + + if (importedModule.buildMeta.providedExports) { + return { + exports: true, + dependencies: undefined + }; + } + + return { + exports: null, + dependencies: [importedModule] + }; + } + + getWarnings() { + if ( + this.strictExportPresence || + this.originModule.buildMeta.strictHarmonyModule + ) { + return []; + } + return this._getErrors(); + } + + getErrors() { + if ( + this.strictExportPresence || + this.originModule.buildMeta.strictHarmonyModule + ) { + return this._getErrors(); + } + return []; + } + + _getErrors() { + const importedModule = this._module; + if (!importedModule) { + return; + } + + if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) { + // It's not an harmony module + if ( + this.originModule.buildMeta.strictHarmonyModule && + this._id && + this._id !== "default" + ) { + // In strict harmony modules we only support the default export + return [ + new HarmonyLinkingError( + `Can't reexport the named export '${this._id}' from non EcmaScript module (only default export is available)` + ) + ]; + } + return; + } + + if (!this._id) { + return; + } + + if (importedModule.isProvided(this._id) !== false) { + // It's provided or we are not sure + return; + } + + // We are sure that it's not provided + const idIsNotNameMessage = + this._id !== this.name ? ` (reexported as '${this.name}')` : ""; + const errorMessage = `"export '${this._id}'${idIsNotNameMessage} was not found in '${this.userRequest}'`; + return [new HarmonyLinkingError(errorMessage)]; + } + + updateHash(hash) { + super.updateHash(hash); + const hashValue = this.getHashValue(this._module); + hash.update(hashValue); + } + + getHashValue(importedModule) { + if (!importedModule) { + return ""; + } + + const stringifiedUsedExport = JSON.stringify(importedModule.usedExports); + const stringifiedProvidedExport = JSON.stringify( + importedModule.buildMeta.providedExports + ); + return ( + importedModule.used + stringifiedUsedExport + stringifiedProvidedExport + ); + } + + disconnect() { + super.disconnect(); + this.redirectedId = undefined; + } +} + +module.exports = HarmonyExportImportedSpecifierDependency; + +HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends HarmonyImportDependency.Template { + harmonyInit(dep, source, runtime, dependencyTemplates) { + super.harmonyInit(dep, source, runtime, dependencyTemplates); + const content = this.getContent(dep); + source.insert(-1, content); + } + + getHarmonyInitOrder(dep) { + if (dep.name) { + const used = dep.originModule.isUsed(dep.name); + if (!used) return NaN; + } else { + const importedModule = dep._module; + + const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports(); + + if (Array.isArray(dep.originModule.usedExports)) { + // we know which exports are used + + const unused = dep.originModule.usedExports.every(id => { + if (id === "default") return true; + if (dep.activeExports.has(id)) return true; + if (importedModule.isProvided(id) === false) return true; + if (activeFromOtherStarExports.has(id)) return true; + return false; + }); + if (unused) return NaN; + } else if ( + dep.originModule.usedExports && + importedModule && + Array.isArray(importedModule.buildMeta.providedExports) + ) { + // not sure which exports are used, but we know which are provided + + const unused = importedModule.buildMeta.providedExports.every(id => { + if (id === "default") return true; + if (dep.activeExports.has(id)) return true; + if (activeFromOtherStarExports.has(id)) return true; + return false; + }); + if (unused) return NaN; + } + } + return super.getHarmonyInitOrder(dep); + } + + getContent(dep) { + const mode = dep.getMode(false); + const module = dep.originModule; + const importedModule = dep._module; + const importVar = dep.getImportVar(); + + switch (mode.type) { + case "missing": + return `throw new Error(${JSON.stringify( + `Cannot find module '${mode.userRequest}'` + )});\n`; + + case "unused": + return `${Template.toNormalComment( + `unused harmony reexport ${mode.name}` + )}\n`; + + case "reexport-non-harmony-default": + return ( + "/* harmony reexport (default from non-harmony) */ " + + this.getReexportStatement( + module, + module.isUsed(mode.name), + importVar, + null + ) + ); + + case "reexport-named-default": + return ( + "/* harmony reexport (default from named exports) */ " + + this.getReexportStatement( + module, + module.isUsed(mode.name), + importVar, + "" + ) + ); + + case "reexport-fake-namespace-object": + return ( + "/* harmony reexport (fake namespace object from non-harmony) */ " + + this.getReexportFakeNamespaceObjectStatement( + module, + module.isUsed(mode.name), + importVar + ) + ); + + case "rexport-non-harmony-undefined": + return ( + "/* harmony reexport (non default export from non-harmony) */ " + + this.getReexportStatement( + module, + module.isUsed(mode.name), + "undefined", + "" + ) + ); + + case "reexport-non-harmony-default-strict": + return ( + "/* harmony reexport (default from non-harmony) */ " + + this.getReexportStatement( + module, + module.isUsed(mode.name), + importVar, + "" + ) + ); + + case "reexport-namespace-object": + return ( + "/* harmony reexport (module object) */ " + + this.getReexportStatement( + module, + module.isUsed(mode.name), + importVar, + "" + ) + ); + + case "empty-star": + return "/* empty/unused harmony star reexport */"; + + case "safe-reexport": + return Array.from(mode.map.entries()) + .map(item => { + return ( + "/* harmony reexport (safe) */ " + + this.getReexportStatement( + module, + module.isUsed(item[0]), + importVar, + importedModule.isUsed(item[1]) + ) + + "\n" + ); + }) + .join(""); + + case "checked-reexport": + return Array.from(mode.map.entries()) + .map(item => { + return ( + "/* harmony reexport (checked) */ " + + this.getConditionalReexportStatement( + module, + item[0], + importVar, + item[1] + ) + + "\n" + ); + }) + .join(""); + + case "dynamic-reexport": { + const ignoredExports = mode.ignored; + let content = + "/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " + + importVar + + ") "; + + // Filter out exports which are defined by other exports + // and filter out default export because it cannot be reexported with * + if (ignoredExports.size > 0) { + content += + "if(" + + JSON.stringify(Array.from(ignoredExports)) + + ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) "; + } else { + content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') "; + } + const exportsName = dep.originModule.exportsArgument; + return ( + content + + `(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n` + ); + } + + default: + throw new Error(`Unknown mode ${mode.type}`); + } + } + + getReexportStatement(module, key, name, valueKey) { + const exportsName = module.exportsArgument; + const returnValue = this.getReturnValue(name, valueKey); + return `__webpack_require__.d(${exportsName}, ${JSON.stringify( + key + )}, function() { return ${returnValue}; });\n`; + } + + getReexportFakeNamespaceObjectStatement(module, key, name) { + const exportsName = module.exportsArgument; + return `__webpack_require__.d(${exportsName}, ${JSON.stringify( + key + )}, function() { return __webpack_require__.t(${name}); });\n`; + } + + getConditionalReexportStatement(module, key, name, valueKey) { + if (valueKey === false) { + return "/* unused export */\n"; + } + const exportsName = module.exportsArgument; + const returnValue = this.getReturnValue(name, valueKey); + return `if(__webpack_require__.o(${name}, ${JSON.stringify( + valueKey + )})) __webpack_require__.d(${exportsName}, ${JSON.stringify( + key + )}, function() { return ${returnValue}; });\n`; + } + + getReturnValue(name, valueKey) { + if (valueKey === null) { + return `${name}_default.a`; + } + if (valueKey === "") { + return name; + } + if (valueKey === false) { + return "/* unused export */ undefined"; + } + + return `${name}[${JSON.stringify(valueKey)}]`; + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyExportSpecifierDependency.js b/node_modules/webpack/lib/dependencies/HarmonyExportSpecifierDependency.js new file mode 100644 index 0000000..1bf6a3f --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyExportSpecifierDependency.js @@ -0,0 +1,54 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class HarmonyExportSpecifierDependency extends NullDependency { + constructor(originModule, id, name) { + super(); + this.originModule = originModule; + this.id = id; + this.name = name; + } + + get type() { + return "harmony export specifier"; + } + + getExports() { + return { + exports: [this.name], + dependencies: undefined + }; + } +} + +HarmonyExportSpecifierDependency.Template = class HarmonyExportSpecifierDependencyTemplate { + apply(dep, source) {} + + getHarmonyInitOrder(dep) { + return 0; + } + + harmonyInit(dep, source, runtime) { + const content = this.getContent(dep); + source.insert(-1, content); + } + + getContent(dep) { + const used = dep.originModule.isUsed(dep.name); + if (!used) { + return `/* unused harmony export ${dep.name || "namespace"} */\n`; + } + + const exportsName = dep.originModule.exportsArgument; + + return `/* harmony export (binding) */ __webpack_require__.d(${exportsName}, ${JSON.stringify( + used + )}, function() { return ${dep.id}; });\n`; + } +}; + +module.exports = HarmonyExportSpecifierDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyImportDependency.js b/node_modules/webpack/lib/dependencies/HarmonyImportDependency.js new file mode 100644 index 0000000..97fd9bf --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyImportDependency.js @@ -0,0 +1,109 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const ModuleDependency = require("./ModuleDependency"); +const Template = require("../Template"); + +class HarmonyImportDependency extends ModuleDependency { + constructor(request, originModule, sourceOrder, parserScope) { + super(request); + this.redirectedModule = undefined; + this.originModule = originModule; + this.sourceOrder = sourceOrder; + this.parserScope = parserScope; + } + + get _module() { + return this.redirectedModule || this.module; + } + + getReference() { + if (!this._module) return null; + return new DependencyReference( + this._module, + false, + this.weak, + this.sourceOrder + ); + } + + getImportVar() { + let importVarMap = this.parserScope.importVarMap; + if (!importVarMap) this.parserScope.importVarMap = importVarMap = new Map(); + let importVar = importVarMap.get(this._module); + if (importVar) return importVar; + importVar = `${Template.toIdentifier( + `${this.userRequest}` + )}__WEBPACK_IMPORTED_MODULE_${importVarMap.size}__`; + importVarMap.set(this._module, importVar); + return importVar; + } + + getImportStatement(update, runtime) { + return runtime.importStatement({ + update, + module: this._module, + importVar: this.getImportVar(), + request: this.request, + originModule: this.originModule + }); + } + + updateHash(hash) { + super.updateHash(hash); + const importedModule = this._module; + hash.update( + (importedModule && + (!importedModule.buildMeta || importedModule.buildMeta.exportsType)) + + "" + ); + hash.update((importedModule && importedModule.id) + ""); + } + + disconnect() { + super.disconnect(); + this.redirectedModule = undefined; + } +} + +module.exports = HarmonyImportDependency; + +const importEmittedMap = new WeakMap(); + +HarmonyImportDependency.Template = class HarmonyImportDependencyTemplate { + apply(dep, source, runtime) { + // no-op + } + + getHarmonyInitOrder(dep) { + return dep.sourceOrder; + } + + static isImportEmitted(dep, source) { + let sourceInfo = importEmittedMap.get(source); + if (!sourceInfo) return false; + const key = dep._module || dep.request; + return key && sourceInfo.emittedImports.get(key); + } + + harmonyInit(dep, source, runtime, dependencyTemplates) { + let sourceInfo = importEmittedMap.get(source); + if (!sourceInfo) { + importEmittedMap.set( + source, + (sourceInfo = { + emittedImports: new Map() + }) + ); + } + const key = dep._module || dep.request; + if (key && sourceInfo.emittedImports.get(key)) return; + sourceInfo.emittedImports.set(key, true); + const content = dep.getImportStatement(false, runtime); + source.insert(-1, content); + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js new file mode 100644 index 0000000..7f9fcde --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js @@ -0,0 +1,222 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { SyncBailHook } = require("tapable"); +const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency"); +const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency"); +const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency"); +const HarmonyAcceptDependency = require("./HarmonyAcceptDependency"); +const ConstDependency = require("./ConstDependency"); + +module.exports = class HarmonyImportDependencyParserPlugin { + constructor(moduleOptions) { + this.strictExportPresence = moduleOptions.strictExportPresence; + this.strictThisContextOnImports = moduleOptions.strictThisContextOnImports; + } + + apply(parser) { + parser.hooks.import.tap( + "HarmonyImportDependencyParserPlugin", + (statement, source) => { + parser.state.lastHarmonyImportOrder = + (parser.state.lastHarmonyImportOrder || 0) + 1; + const clearDep = new ConstDependency("", statement.range); + clearDep.loc = statement.loc; + parser.state.module.addDependency(clearDep); + const sideEffectDep = new HarmonyImportSideEffectDependency( + source, + parser.state.module, + parser.state.lastHarmonyImportOrder, + parser.state.harmonyParserScope + ); + sideEffectDep.loc = statement.loc; + parser.state.module.addDependency(sideEffectDep); + return true; + } + ); + parser.hooks.importSpecifier.tap( + "HarmonyImportDependencyParserPlugin", + (statement, source, id, name) => { + parser.scope.definitions.delete(name); + parser.scope.renames.set(name, "imported var"); + if (!parser.state.harmonySpecifier) { + parser.state.harmonySpecifier = new Map(); + } + parser.state.harmonySpecifier.set(name, { + source, + id, + sourceOrder: parser.state.lastHarmonyImportOrder + }); + return true; + } + ); + parser.hooks.expression + .for("imported var") + .tap("HarmonyImportDependencyParserPlugin", expr => { + const name = expr.name; + const settings = parser.state.harmonySpecifier.get(name); + const dep = new HarmonyImportSpecifierDependency( + settings.source, + parser.state.module, + settings.sourceOrder, + parser.state.harmonyParserScope, + settings.id, + name, + expr.range, + this.strictExportPresence + ); + dep.shorthand = parser.scope.inShorthand; + dep.directImport = true; + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.expressionAnyMember + .for("imported var") + .tap("HarmonyImportDependencyParserPlugin", expr => { + const name = expr.object.name; + const settings = parser.state.harmonySpecifier.get(name); + if (settings.id !== null) return false; + const dep = new HarmonyImportSpecifierDependency( + settings.source, + parser.state.module, + settings.sourceOrder, + parser.state.harmonyParserScope, + expr.property.name || expr.property.value, + name, + expr.range, + this.strictExportPresence + ); + dep.shorthand = parser.scope.inShorthand; + dep.directImport = false; + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + if (this.strictThisContextOnImports) { + // only in case when we strictly follow the spec we need a special case here + parser.hooks.callAnyMember + .for("imported var") + .tap("HarmonyImportDependencyParserPlugin", expr => { + if (expr.callee.type !== "MemberExpression") return; + if (expr.callee.object.type !== "Identifier") return; + const name = expr.callee.object.name; + const settings = parser.state.harmonySpecifier.get(name); + if (settings.id !== null) return false; + const dep = new HarmonyImportSpecifierDependency( + settings.source, + parser.state.module, + settings.sourceOrder, + parser.state.harmonyParserScope, + expr.callee.property.name || expr.callee.property.value, + name, + expr.callee.range, + this.strictExportPresence + ); + dep.shorthand = parser.scope.inShorthand; + dep.directImport = false; + dep.namespaceObjectAsContext = true; + dep.loc = expr.callee.loc; + parser.state.module.addDependency(dep); + if (expr.arguments) parser.walkExpressions(expr.arguments); + return true; + }); + } + parser.hooks.call + .for("imported var") + .tap("HarmonyImportDependencyParserPlugin", expr => { + const args = expr.arguments; + const fullExpr = expr; + expr = expr.callee; + if (expr.type !== "Identifier") return; + const name = expr.name; + const settings = parser.state.harmonySpecifier.get(name); + const dep = new HarmonyImportSpecifierDependency( + settings.source, + parser.state.module, + settings.sourceOrder, + parser.state.harmonyParserScope, + settings.id, + name, + expr.range, + this.strictExportPresence + ); + dep.directImport = true; + dep.callArgs = args; + dep.call = fullExpr; + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + if (args) parser.walkExpressions(args); + return true; + }); + // TODO webpack 5: refactor this, no custom hooks + if (!parser.hooks.hotAcceptCallback) { + parser.hooks.hotAcceptCallback = new SyncBailHook([ + "expression", + "requests" + ]); + } + if (!parser.hooks.hotAcceptWithoutCallback) { + parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([ + "expression", + "requests" + ]); + } + parser.hooks.hotAcceptCallback.tap( + "HarmonyImportDependencyParserPlugin", + (expr, requests) => { + const harmonyParserScope = parser.state.harmonyParserScope; + if (!harmonyParserScope) { + // This is not a harmony module, skip it + return; + } + const dependencies = requests.map(request => { + const dep = new HarmonyAcceptImportDependency( + request, + parser.state.module, + harmonyParserScope + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return dep; + }); + if (dependencies.length > 0) { + const dep = new HarmonyAcceptDependency( + expr.range, + dependencies, + true + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + } + } + ); + parser.hooks.hotAcceptWithoutCallback.tap( + "HarmonyImportDependencyParserPlugin", + (expr, requests) => { + const dependencies = requests.map(request => { + const dep = new HarmonyAcceptImportDependency( + request, + parser.state.module, + parser.state.harmonyParserScope + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return dep; + }); + if (dependencies.length > 0) { + const dep = new HarmonyAcceptDependency( + expr.range, + dependencies, + false + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + } + } + ); + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyImportSideEffectDependency.js b/node_modules/webpack/lib/dependencies/HarmonyImportSideEffectDependency.js new file mode 100644 index 0000000..a41c1b9 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyImportSideEffectDependency.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const HarmonyImportDependency = require("./HarmonyImportDependency"); + +class HarmonyImportSideEffectDependency extends HarmonyImportDependency { + constructor(request, originModule, sourceOrder, parserScope) { + super(request, originModule, sourceOrder, parserScope); + } + + getReference() { + if (this._module && this._module.factoryMeta.sideEffectFree) return null; + + return super.getReference(); + } + + get type() { + return "harmony side effect evaluation"; + } +} + +HarmonyImportSideEffectDependency.Template = class HarmonyImportSideEffectDependencyTemplate extends HarmonyImportDependency.Template { + getHarmonyInitOrder(dep) { + if (dep._module && dep._module.factoryMeta.sideEffectFree) return NaN; + return super.getHarmonyInitOrder(dep); + } +}; + +module.exports = HarmonyImportSideEffectDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyImportSpecifierDependency.js b/node_modules/webpack/lib/dependencies/HarmonyImportSpecifierDependency.js new file mode 100644 index 0000000..d07fbf1 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyImportSpecifierDependency.js @@ -0,0 +1,163 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const HarmonyImportDependency = require("./HarmonyImportDependency"); +const HarmonyLinkingError = require("../HarmonyLinkingError"); + +class HarmonyImportSpecifierDependency extends HarmonyImportDependency { + constructor( + request, + originModule, + sourceOrder, + parserScope, + id, + name, + range, + strictExportPresence + ) { + super(request, originModule, sourceOrder, parserScope); + this.id = id === null ? null : `${id}`; + this.redirectedId = undefined; + this.name = name; + this.range = range; + this.strictExportPresence = strictExportPresence; + this.namespaceObjectAsContext = false; + this.callArgs = undefined; + this.call = undefined; + this.directImport = undefined; + this.shorthand = undefined; + } + + get type() { + return "harmony import specifier"; + } + + get _id() { + return this.redirectedId || this.id; + } + + getReference() { + if (!this._module) return null; + return new DependencyReference( + this._module, + this._id && !this.namespaceObjectAsContext ? [this._id] : true, + false, + this.sourceOrder + ); + } + + getWarnings() { + if ( + this.strictExportPresence || + this.originModule.buildMeta.strictHarmonyModule + ) { + return []; + } + return this._getErrors(); + } + + getErrors() { + if ( + this.strictExportPresence || + this.originModule.buildMeta.strictHarmonyModule + ) { + return this._getErrors(); + } + return []; + } + + _getErrors() { + const importedModule = this._module; + if (!importedModule) { + return; + } + + if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) { + // It's not an harmony module + if ( + this.originModule.buildMeta.strictHarmonyModule && + this._id && + this._id !== "default" + ) { + // In strict harmony modules we only support the default export + return [ + new HarmonyLinkingError( + `Can't import the named export '${this._id}' from non EcmaScript module (only default export is available)` + ) + ]; + } + return; + } + + if (!this._id) { + return; + } + + if (importedModule.isProvided(this._id) !== false) { + // It's provided or we are not sure + return; + } + + // We are sure that it's not provided + const idIsNotNameMessage = + this._id !== this.name ? ` (imported as '${this.name}')` : ""; + const errorMessage = `"export '${this._id}'${idIsNotNameMessage} was not found in '${this.userRequest}'`; + return [new HarmonyLinkingError(errorMessage)]; + } + + // implement this method to allow the occurrence order plugin to count correctly + getNumberOfIdOccurrences() { + return 0; + } + + updateHash(hash) { + super.updateHash(hash); + const importedModule = this._module; + hash.update((importedModule && this._id) + ""); + hash.update( + (importedModule && this._id && importedModule.isUsed(this._id)) + "" + ); + hash.update( + (importedModule && + (!importedModule.buildMeta || importedModule.buildMeta.exportsType)) + + "" + ); + hash.update( + (importedModule && + importedModule.used + JSON.stringify(importedModule.usedExports)) + "" + ); + } + + disconnect() { + super.disconnect(); + this.redirectedId = undefined; + } +} + +HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependencyTemplate extends HarmonyImportDependency.Template { + apply(dep, source, runtime) { + super.apply(dep, source, runtime); + const content = this.getContent(dep, runtime); + source.replace(dep.range[0], dep.range[1] - 1, content); + } + + getContent(dep, runtime) { + const exportExpr = runtime.exportFromImport({ + module: dep._module, + request: dep.request, + exportName: dep._id, + originModule: dep.originModule, + asiSafe: dep.shorthand, + isCall: dep.call, + callContext: !dep.directImport, + importVar: dep.getImportVar() + }); + return dep.shorthand ? `${dep.name}: ${exportExpr}` : exportExpr; + } +}; + +module.exports = HarmonyImportSpecifierDependency; diff --git a/node_modules/webpack/lib/dependencies/HarmonyInitDependency.js b/node_modules/webpack/lib/dependencies/HarmonyInitDependency.js new file mode 100644 index 0000000..73239c8 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyInitDependency.js @@ -0,0 +1,60 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const NullDependency = require("./NullDependency"); + +class HarmonyInitDependency extends NullDependency { + constructor(originModule) { + super(); + this.originModule = originModule; + } + + get type() { + return "harmony init"; + } +} + +module.exports = HarmonyInitDependency; + +HarmonyInitDependency.Template = class HarmonyInitDependencyTemplate { + apply(dep, source, runtime, dependencyTemplates) { + const module = dep.originModule; + const list = []; + for (const dependency of module.dependencies) { + const template = dependencyTemplates.get(dependency.constructor); + if ( + template && + typeof template.harmonyInit === "function" && + typeof template.getHarmonyInitOrder === "function" + ) { + const order = template.getHarmonyInitOrder(dependency); + if (!isNaN(order)) { + list.push({ + order, + listOrder: list.length, + dependency, + template + }); + } + } + } + + list.sort((a, b) => { + const x = a.order - b.order; + if (x) return x; + return a.listOrder - b.listOrder; + }); + + for (const item of list) { + item.template.harmonyInit( + item.dependency, + source, + runtime, + dependencyTemplates + ); + } + } +}; diff --git a/node_modules/webpack/lib/dependencies/HarmonyModulesPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyModulesPlugin.js new file mode 100644 index 0000000..43a8d4c --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyModulesPlugin.js @@ -0,0 +1,143 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency"); +const HarmonyInitDependency = require("./HarmonyInitDependency"); +const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency"); +const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency"); +const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency"); +const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency"); +const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency"); +const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency"); +const HarmonyAcceptDependency = require("./HarmonyAcceptDependency"); +const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency"); + +const NullFactory = require("../NullFactory"); + +const HarmonyDetectionParserPlugin = require("./HarmonyDetectionParserPlugin"); +const HarmonyImportDependencyParserPlugin = require("./HarmonyImportDependencyParserPlugin"); +const HarmonyExportDependencyParserPlugin = require("./HarmonyExportDependencyParserPlugin"); +const HarmonyTopLevelThisParserPlugin = require("./HarmonyTopLevelThisParserPlugin"); + +class HarmonyModulesPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "HarmonyModulesPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + HarmonyCompatibilityDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyCompatibilityDependency, + new HarmonyCompatibilityDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyInitDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyInitDependency, + new HarmonyInitDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyImportSideEffectDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + HarmonyImportSideEffectDependency, + new HarmonyImportSideEffectDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyImportSpecifierDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + HarmonyImportSpecifierDependency, + new HarmonyImportSpecifierDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyExportHeaderDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyExportHeaderDependency, + new HarmonyExportHeaderDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyExportExpressionDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyExportExpressionDependency, + new HarmonyExportExpressionDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyExportSpecifierDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyExportSpecifierDependency, + new HarmonyExportSpecifierDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyExportImportedSpecifierDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + HarmonyExportImportedSpecifierDependency, + new HarmonyExportImportedSpecifierDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyAcceptDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + HarmonyAcceptDependency, + new HarmonyAcceptDependency.Template() + ); + + compilation.dependencyFactories.set( + HarmonyAcceptImportDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + HarmonyAcceptImportDependency, + new HarmonyAcceptImportDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if (parserOptions.harmony !== undefined && !parserOptions.harmony) + return; + + new HarmonyDetectionParserPlugin().apply(parser); + new HarmonyImportDependencyParserPlugin(this.options).apply(parser); + new HarmonyExportDependencyParserPlugin(this.options).apply(parser); + new HarmonyTopLevelThisParserPlugin().apply(parser); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("HarmonyModulesPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("HarmonyModulesPlugin", handler); + } + ); + } +} +module.exports = HarmonyModulesPlugin; diff --git a/node_modules/webpack/lib/dependencies/HarmonyTopLevelThisParserPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyTopLevelThisParserPlugin.js new file mode 100644 index 0000000..f036009 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/HarmonyTopLevelThisParserPlugin.js @@ -0,0 +1,26 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Florent Cailhol @ooflorent +*/ +"use strict"; + +const ConstDependency = require("./ConstDependency"); + +class HarmonyTopLevelThisParserPlugin { + apply(parser) { + parser.hooks.expression + .for("this") + .tap("HarmonyTopLevelThisParserPlugin", node => { + if (!parser.scope.topLevelScope) return; + const module = parser.state.module; + const isHarmony = !!(module.buildMeta && module.buildMeta.exportsType); + if (isHarmony) { + const dep = new ConstDependency("undefined", node.range, false); + dep.loc = node.loc; + parser.state.current.addDependency(dep); + } + }); + } +} + +module.exports = HarmonyTopLevelThisParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/ImportContextDependency.js b/node_modules/webpack/lib/dependencies/ImportContextDependency.js new file mode 100644 index 0000000..f25a28a --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportContextDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ContextDependency = require("./ContextDependency"); +const ContextDependencyTemplateAsRequireCall = require("./ContextDependencyTemplateAsRequireCall"); + +class ImportContextDependency extends ContextDependency { + constructor(options, range, valueRange) { + super(options); + this.range = range; + this.valueRange = valueRange; + } + + get type() { + return `import() context ${this.options.mode}`; + } +} + +ImportContextDependency.Template = ContextDependencyTemplateAsRequireCall; + +module.exports = ImportContextDependency; diff --git a/node_modules/webpack/lib/dependencies/ImportDependenciesBlock.js b/node_modules/webpack/lib/dependencies/ImportDependenciesBlock.js new file mode 100644 index 0000000..61e6bb2 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportDependenciesBlock.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const AsyncDependenciesBlock = require("../AsyncDependenciesBlock"); +const ImportDependency = require("./ImportDependency"); + +module.exports = class ImportDependenciesBlock extends AsyncDependenciesBlock { + // TODO webpack 5 reorganize arguments + constructor(request, range, groupOptions, module, loc, originModule) { + super(groupOptions, module, loc, request); + this.range = range; + const dep = new ImportDependency(request, originModule, this); + dep.loc = loc; + this.addDependency(dep); + } +}; diff --git a/node_modules/webpack/lib/dependencies/ImportDependency.js b/node_modules/webpack/lib/dependencies/ImportDependency.js new file mode 100644 index 0000000..520bed2 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportDependency.js @@ -0,0 +1,34 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class ImportDependency extends ModuleDependency { + constructor(request, originModule, block) { + super(request); + this.originModule = originModule; + this.block = block; + } + + get type() { + return "import()"; + } +} + +ImportDependency.Template = class ImportDependencyTemplate { + apply(dep, source, runtime) { + const content = runtime.moduleNamespacePromise({ + block: dep.block, + module: dep.module, + request: dep.request, + strict: dep.originModule.buildMeta.strictHarmonyModule, + message: "import()" + }); + + source.replace(dep.block.range[0], dep.block.range[1] - 1, content); + } +}; + +module.exports = ImportDependency; diff --git a/node_modules/webpack/lib/dependencies/ImportEagerDependency.js b/node_modules/webpack/lib/dependencies/ImportEagerDependency.js new file mode 100644 index 0000000..0671d5d --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportEagerDependency.js @@ -0,0 +1,32 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class ImportEagerDependency extends ModuleDependency { + constructor(request, originModule, range) { + super(request); + this.originModule = originModule; + this.range = range; + } + + get type() { + return "import() eager"; + } +} + +ImportEagerDependency.Template = class ImportEagerDependencyTemplate { + apply(dep, source, runtime) { + const content = runtime.moduleNamespacePromise({ + module: dep.module, + request: dep.request, + strict: dep.originModule.buildMeta.strictHarmonyModule, + message: "import() eager" + }); + source.replace(dep.range[0], dep.range[1] - 1, content); + } +}; + +module.exports = ImportEagerDependency; diff --git a/node_modules/webpack/lib/dependencies/ImportParserPlugin.js b/node_modules/webpack/lib/dependencies/ImportParserPlugin.js new file mode 100644 index 0000000..cb751a8 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportParserPlugin.js @@ -0,0 +1,248 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ImportContextDependency = require("./ImportContextDependency"); +const ImportWeakDependency = require("./ImportWeakDependency"); +const ImportDependenciesBlock = require("./ImportDependenciesBlock"); +const ImportEagerDependency = require("./ImportEagerDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); +const CommentCompilationWarning = require("../CommentCompilationWarning"); + +class ImportParserPlugin { + constructor(options) { + this.options = options; + } + + apply(parser) { + parser.hooks.importCall.tap("ImportParserPlugin", expr => { + if (expr.arguments.length !== 1) { + throw new Error( + "Incorrect number of arguments provided to 'import(module: string) -> Promise'." + ); + } + + const param = parser.evaluateExpression(expr.arguments[0]); + + let chunkName = null; + let mode = "lazy"; + let include = null; + let exclude = null; + const groupOptions = {}; + + const { + options: importOptions, + errors: commentErrors + } = parser.parseCommentOptions(expr.range); + + if (commentErrors) { + for (const e of commentErrors) { + const { comment } = e; + parser.state.module.warnings.push( + new CommentCompilationWarning( + `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, + parser.state.module, + comment.loc + ) + ); + } + } + + if (importOptions) { + if (importOptions.webpackIgnore !== undefined) { + if (typeof importOptions.webpackIgnore !== "boolean") { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackIgnore\` expected a boolean, but received: ${importOptions.webpackIgnore}.`, + expr.loc + ) + ); + } else { + // Do not instrument `import()` if `webpackIgnore` is `true` + if (importOptions.webpackIgnore) { + return false; + } + } + } + if (importOptions.webpackChunkName !== undefined) { + if (typeof importOptions.webpackChunkName !== "string") { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackChunkName\` expected a string, but received: ${importOptions.webpackChunkName}.`, + expr.loc + ) + ); + } else { + chunkName = importOptions.webpackChunkName; + } + } + if (importOptions.webpackMode !== undefined) { + if (typeof importOptions.webpackMode !== "string") { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackMode\` expected a string, but received: ${importOptions.webpackMode}.`, + expr.loc + ) + ); + } else { + mode = importOptions.webpackMode; + } + } + if (importOptions.webpackPrefetch !== undefined) { + if (importOptions.webpackPrefetch === true) { + groupOptions.prefetchOrder = 0; + } else if (typeof importOptions.webpackPrefetch === "number") { + groupOptions.prefetchOrder = importOptions.webpackPrefetch; + } else { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackPrefetch\` expected true or a number, but received: ${importOptions.webpackPrefetch}.`, + expr.loc + ) + ); + } + } + if (importOptions.webpackPreload !== undefined) { + if (importOptions.webpackPreload === true) { + groupOptions.preloadOrder = 0; + } else if (typeof importOptions.webpackPreload === "number") { + groupOptions.preloadOrder = importOptions.webpackPreload; + } else { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackPreload\` expected true or a number, but received: ${importOptions.webpackPreload}.`, + expr.loc + ) + ); + } + } + if (importOptions.webpackInclude !== undefined) { + if ( + !importOptions.webpackInclude || + importOptions.webpackInclude.constructor.name !== "RegExp" + ) { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackInclude\` expected a regular expression, but received: ${importOptions.webpackInclude}.`, + expr.loc + ) + ); + } else { + include = new RegExp(importOptions.webpackInclude); + } + } + if (importOptions.webpackExclude !== undefined) { + if ( + !importOptions.webpackExclude || + importOptions.webpackExclude.constructor.name !== "RegExp" + ) { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackExclude\` expected a regular expression, but received: ${importOptions.webpackExclude}.`, + expr.loc + ) + ); + } else { + exclude = new RegExp(importOptions.webpackExclude); + } + } + } + + if (param.isString()) { + if (mode !== "lazy" && mode !== "eager" && mode !== "weak") { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackMode\` expected 'lazy', 'eager' or 'weak', but received: ${mode}.`, + expr.loc + ) + ); + } + + if (mode === "eager") { + const dep = new ImportEagerDependency( + param.string, + parser.state.module, + expr.range + ); + parser.state.current.addDependency(dep); + } else if (mode === "weak") { + const dep = new ImportWeakDependency( + param.string, + parser.state.module, + expr.range + ); + parser.state.current.addDependency(dep); + } else { + const depBlock = new ImportDependenciesBlock( + param.string, + expr.range, + Object.assign(groupOptions, { + name: chunkName + }), + parser.state.module, + expr.loc, + parser.state.module + ); + parser.state.current.addBlock(depBlock); + } + return true; + } else { + if ( + mode !== "lazy" && + mode !== "lazy-once" && + mode !== "eager" && + mode !== "weak" + ) { + parser.state.module.warnings.push( + new UnsupportedFeatureWarning( + parser.state.module, + `\`webpackMode\` expected 'lazy', 'lazy-once', 'eager' or 'weak', but received: ${mode}.`, + expr.loc + ) + ); + mode = "lazy"; + } + + if (mode === "weak") { + mode = "async-weak"; + } + const dep = ContextDependencyHelpers.create( + ImportContextDependency, + expr.range, + param, + expr, + this.options, + { + chunkName, + groupOptions, + include, + exclude, + mode, + namespaceObject: parser.state.module.buildMeta.strictHarmonyModule + ? "strict" + : true + }, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + }); + } +} + +module.exports = ImportParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/ImportPlugin.js b/node_modules/webpack/lib/dependencies/ImportPlugin.js new file mode 100644 index 0000000..1647192 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportPlugin.js @@ -0,0 +1,79 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ImportDependency = require("./ImportDependency"); +const ImportEagerDependency = require("./ImportEagerDependency"); +const ImportWeakDependency = require("./ImportWeakDependency"); +const ImportContextDependency = require("./ImportContextDependency"); +const ImportParserPlugin = require("./ImportParserPlugin"); + +class ImportPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap( + "ImportPlugin", + (compilation, { contextModuleFactory, normalModuleFactory }) => { + compilation.dependencyFactories.set( + ImportDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + ImportDependency, + new ImportDependency.Template() + ); + + compilation.dependencyFactories.set( + ImportEagerDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + ImportEagerDependency, + new ImportEagerDependency.Template() + ); + + compilation.dependencyFactories.set( + ImportWeakDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + ImportWeakDependency, + new ImportWeakDependency.Template() + ); + + compilation.dependencyFactories.set( + ImportContextDependency, + contextModuleFactory + ); + compilation.dependencyTemplates.set( + ImportContextDependency, + new ImportContextDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if (parserOptions.import !== undefined && !parserOptions.import) + return; + + new ImportParserPlugin(options).apply(parser); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("ImportPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("ImportPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("ImportPlugin", handler); + } + ); + } +} +module.exports = ImportPlugin; diff --git a/node_modules/webpack/lib/dependencies/ImportWeakDependency.js b/node_modules/webpack/lib/dependencies/ImportWeakDependency.js new file mode 100644 index 0000000..d484000 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ImportWeakDependency.js @@ -0,0 +1,34 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class ImportWeakDependency extends ModuleDependency { + constructor(request, originModule, range) { + super(request); + this.originModule = originModule; + this.range = range; + this.weak = true; + } + + get type() { + return "import() weak"; + } +} + +ImportWeakDependency.Template = class ImportDependencyTemplate { + apply(dep, source, runtime) { + const content = runtime.moduleNamespacePromise({ + module: dep.module, + request: dep.request, + strict: dep.originModule.buildMeta.strictHarmonyModule, + message: "import() weak", + weak: true + }); + source.replace(dep.range[0], dep.range[1] - 1, content); + } +}; + +module.exports = ImportWeakDependency; diff --git a/node_modules/webpack/lib/dependencies/JsonExportsDependency.js b/node_modules/webpack/lib/dependencies/JsonExportsDependency.js new file mode 100644 index 0000000..9e17bfb --- /dev/null +++ b/node_modules/webpack/lib/dependencies/JsonExportsDependency.js @@ -0,0 +1,26 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class JsonExportsDependency extends NullDependency { + constructor(exports) { + super(); + this.exports = exports; + } + + get type() { + return "json exports"; + } + + getExports() { + return { + exports: this.exports, + dependencies: undefined + }; + } +} + +module.exports = JsonExportsDependency; diff --git a/node_modules/webpack/lib/dependencies/LoaderDependency.js b/node_modules/webpack/lib/dependencies/LoaderDependency.js new file mode 100644 index 0000000..9d0876b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/LoaderDependency.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class LoaderDependency extends ModuleDependency { + /** + * @param {string} request request string + */ + constructor(request) { + super(request); + } + + get type() { + return "loader"; + } +} + +module.exports = LoaderDependency; diff --git a/node_modules/webpack/lib/dependencies/LoaderPlugin.js b/node_modules/webpack/lib/dependencies/LoaderPlugin.js new file mode 100644 index 0000000..e46f593 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/LoaderPlugin.js @@ -0,0 +1,115 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const LoaderDependency = require("./LoaderDependency"); +const NormalModule = require("../NormalModule"); + +/** @typedef {import("../Module")} Module */ + +/** + * @callback LoadModuleCallback + * @param {Error=} err error object + * @param {string=} source source code + * @param {object=} map source map + * @param {Module=} module loaded module if successful + */ + +class LoaderPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "LoaderPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + LoaderDependency, + normalModuleFactory + ); + } + ); + + compiler.hooks.compilation.tap("LoaderPlugin", compilation => { + compilation.hooks.normalModuleLoader.tap( + "LoaderPlugin", + (loaderContext, module) => { + /** + * @param {string} request the request string to load the module from + * @param {LoadModuleCallback} callback callback returning the loaded module or error + * @returns {void} + */ + loaderContext.loadModule = (request, callback) => { + const dep = new LoaderDependency(request); + dep.loc = { + name: request + }; + const factory = compilation.dependencyFactories.get( + dep.constructor + ); + if (factory === undefined) { + return callback( + new Error( + `No module factory available for dependency type: ${dep.constructor.name}` + ) + ); + } + compilation.semaphore.release(); + compilation.addModuleDependencies( + module, + [ + { + factory, + dependencies: [dep] + } + ], + true, + "lm", + true, + err => { + compilation.semaphore.acquire(() => { + if (err) { + return callback(err); + } + if (!dep.module) { + return callback(new Error("Cannot load the module")); + } + // TODO consider removing this in webpack 5 + if (dep.module instanceof NormalModule && dep.module.error) { + return callback(dep.module.error); + } + if (!dep.module._source) { + throw new Error( + "The module created for a LoaderDependency must have a property _source" + ); + } + let source, map; + const moduleSource = dep.module._source; + if (moduleSource.sourceAndMap) { + const sourceAndMap = moduleSource.sourceAndMap(); + map = sourceAndMap.map; + source = sourceAndMap.source; + } else { + map = moduleSource.map(); + source = moduleSource.source(); + } + if (dep.module.buildInfo.fileDependencies) { + for (const d of dep.module.buildInfo.fileDependencies) { + loaderContext.addDependency(d); + } + } + if (dep.module.buildInfo.contextDependencies) { + for (const d of dep.module.buildInfo.contextDependencies) { + loaderContext.addContextDependency(d); + } + } + return callback(null, source, map, dep.module); + }); + } + ); + }; + } + ); + }); + } +} +module.exports = LoaderPlugin; diff --git a/node_modules/webpack/lib/dependencies/LocalModule.js b/node_modules/webpack/lib/dependencies/LocalModule.js new file mode 100644 index 0000000..06e5385 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/LocalModule.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class LocalModule { + constructor(module, name, idx) { + this.module = module; + this.name = name; + this.idx = idx; + this.used = false; + } + + flagUsed() { + this.used = true; + } + + variableName() { + return "__WEBPACK_LOCAL_MODULE_" + this.idx + "__"; + } +} +module.exports = LocalModule; diff --git a/node_modules/webpack/lib/dependencies/LocalModuleDependency.js b/node_modules/webpack/lib/dependencies/LocalModuleDependency.js new file mode 100644 index 0000000..5d1e56b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/LocalModuleDependency.js @@ -0,0 +1,28 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class LocalModuleDependency extends NullDependency { + constructor(localModule, range, callNew) { + super(); + localModule.flagUsed(); + this.localModule = localModule; + this.range = range; + this.callNew = callNew; + } +} + +LocalModuleDependency.Template = class LocalModuleDependencyTemplate { + apply(dep, source) { + if (!dep.range) return; + const moduleInstance = dep.callNew + ? `new (function () { return ${dep.localModule.variableName()}; })()` + : dep.localModule.variableName(); + source.replace(dep.range[0], dep.range[1] - 1, moduleInstance); + } +}; + +module.exports = LocalModuleDependency; diff --git a/node_modules/webpack/lib/dependencies/LocalModulesHelpers.js b/node_modules/webpack/lib/dependencies/LocalModulesHelpers.js new file mode 100644 index 0000000..0566227 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/LocalModulesHelpers.js @@ -0,0 +1,52 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const LocalModule = require("./LocalModule"); +const LocalModulesHelpers = exports; + +const lookup = (parent, mod) => { + if (mod.charAt(0) !== ".") return mod; + + var path = parent.split("/"); + var segs = mod.split("/"); + path.pop(); + + for (let i = 0; i < segs.length; i++) { + const seg = segs[i]; + if (seg === "..") { + path.pop(); + } else if (seg !== ".") { + path.push(seg); + } + } + + return path.join("/"); +}; + +LocalModulesHelpers.addLocalModule = (state, name) => { + if (!state.localModules) { + state.localModules = []; + } + const m = new LocalModule(state.module, name, state.localModules.length); + state.localModules.push(m); + return m; +}; + +LocalModulesHelpers.getLocalModule = (state, name, namedModule) => { + if (!state.localModules) return null; + if (namedModule) { + // resolve dependency name relative to the defining named module + name = lookup(namedModule, name); + } + for (let i = 0; i < state.localModules.length; i++) { + if (state.localModules[i].name === name) { + return state.localModules[i]; + } + } + return null; +}; + +module.exports = LocalModulesHelpers; diff --git a/node_modules/webpack/lib/dependencies/ModuleDependency.js b/node_modules/webpack/lib/dependencies/ModuleDependency.js new file mode 100644 index 0000000..f325e7a --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ModuleDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const Dependency = require("../Dependency"); + +class ModuleDependency extends Dependency { + /** + * @param {string} request request path which needs resolving + */ + constructor(request) { + super(); + this.request = request; + this.userRequest = request; + } + + getResourceIdentifier() { + return `module${this.request}`; + } +} + +module.exports = ModuleDependency; diff --git a/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsId.js b/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsId.js new file mode 100644 index 0000000..82bc6b5 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsId.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class ModuleDependencyTemplateAsId { + apply(dep, source, runtime) { + if (!dep.range) return; + const content = runtime.moduleId({ + module: dep.module, + request: dep.request + }); + source.replace(dep.range[0], dep.range[1] - 1, content); + } +} +module.exports = ModuleDependencyTemplateAsId; diff --git a/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsRequireId.js b/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsRequireId.js new file mode 100644 index 0000000..db74b89 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ModuleDependencyTemplateAsRequireId.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class ModuleDependencyTemplateAsRequireId { + apply(dep, source, runtime) { + if (!dep.range) return; + const content = runtime.moduleExports({ + module: dep.module, + request: dep.request + }); + source.replace(dep.range[0], dep.range[1] - 1, content); + } +} +module.exports = ModuleDependencyTemplateAsRequireId; diff --git a/node_modules/webpack/lib/dependencies/ModuleHotAcceptDependency.js b/node_modules/webpack/lib/dependencies/ModuleHotAcceptDependency.js new file mode 100644 index 0000000..403f7f1 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ModuleHotAcceptDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const ModuleDependencyTemplateAsId = require("./ModuleDependencyTemplateAsId"); + +class ModuleHotAcceptDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + this.weak = true; + } + + get type() { + return "module.hot.accept"; + } +} + +ModuleHotAcceptDependency.Template = ModuleDependencyTemplateAsId; + +module.exports = ModuleHotAcceptDependency; diff --git a/node_modules/webpack/lib/dependencies/ModuleHotDeclineDependency.js b/node_modules/webpack/lib/dependencies/ModuleHotDeclineDependency.js new file mode 100644 index 0000000..49bf0af --- /dev/null +++ b/node_modules/webpack/lib/dependencies/ModuleHotDeclineDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const ModuleDependencyTemplateAsId = require("./ModuleDependencyTemplateAsId"); + +class ModuleHotDeclineDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + this.weak = true; + } + + get type() { + return "module.hot.decline"; + } +} + +ModuleHotDeclineDependency.Template = ModuleDependencyTemplateAsId; + +module.exports = ModuleHotDeclineDependency; diff --git a/node_modules/webpack/lib/dependencies/MultiEntryDependency.js b/node_modules/webpack/lib/dependencies/MultiEntryDependency.js new file mode 100644 index 0000000..712d3ff --- /dev/null +++ b/node_modules/webpack/lib/dependencies/MultiEntryDependency.js @@ -0,0 +1,25 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +/** @typedef {import("./SingleEntryDependency")} SingleEntryDependency */ +const Dependency = require("../Dependency"); + +class MultiEntryDependency extends Dependency { + /** + * @param {SingleEntryDependency[]} dependencies an array of SingleEntryDependencies + * @param {string} name entry name + */ + constructor(dependencies, name) { + super(); + this.dependencies = dependencies; + this.name = name; + } + + get type() { + return "multi entry"; + } +} + +module.exports = MultiEntryDependency; diff --git a/node_modules/webpack/lib/dependencies/NullDependency.js b/node_modules/webpack/lib/dependencies/NullDependency.js new file mode 100644 index 0000000..585f5fc --- /dev/null +++ b/node_modules/webpack/lib/dependencies/NullDependency.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const Dependency = require("../Dependency"); + +class NullDependency extends Dependency { + get type() { + return "null"; + } + + updateHash() {} +} + +NullDependency.Template = class NullDependencyTemplate { + apply() {} +}; + +module.exports = NullDependency; diff --git a/node_modules/webpack/lib/dependencies/PrefetchDependency.js b/node_modules/webpack/lib/dependencies/PrefetchDependency.js new file mode 100644 index 0000000..7107d83 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/PrefetchDependency.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class PrefetchDependency extends ModuleDependency { + constructor(request) { + super(request); + } + + get type() { + return "prefetch"; + } +} + +module.exports = PrefetchDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireContextDependency.js b/node_modules/webpack/lib/dependencies/RequireContextDependency.js new file mode 100644 index 0000000..fd2e728 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireContextDependency.js @@ -0,0 +1,22 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ContextDependency = require("./ContextDependency"); +const ModuleDependencyTemplateAsRequireId = require("./ModuleDependencyTemplateAsRequireId"); + +class RequireContextDependency extends ContextDependency { + constructor(options, range) { + super(options); + this.range = range; + } + + get type() { + return "require.context"; + } +} + +RequireContextDependency.Template = ModuleDependencyTemplateAsRequireId; + +module.exports = RequireContextDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireContextDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/RequireContextDependencyParserPlugin.js new file mode 100644 index 0000000..1071fc0 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireContextDependencyParserPlugin.js @@ -0,0 +1,56 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireContextDependency = require("./RequireContextDependency"); + +module.exports = class RequireContextDependencyParserPlugin { + apply(parser) { + parser.hooks.call + .for("require.context") + .tap("RequireContextDependencyParserPlugin", expr => { + let regExp = /^\.\/.*$/; + let recursive = true; + let mode = "sync"; + switch (expr.arguments.length) { + case 4: { + const modeExpr = parser.evaluateExpression(expr.arguments[3]); + if (!modeExpr.isString()) return; + mode = modeExpr.string; + } + // falls through + case 3: { + const regExpExpr = parser.evaluateExpression(expr.arguments[2]); + if (!regExpExpr.isRegExp()) return; + regExp = regExpExpr.regExp; + } + // falls through + case 2: { + const recursiveExpr = parser.evaluateExpression(expr.arguments[1]); + if (!recursiveExpr.isBoolean()) return; + recursive = recursiveExpr.bool; + } + // falls through + case 1: { + const requestExpr = parser.evaluateExpression(expr.arguments[0]); + if (!requestExpr.isString()) return; + const dep = new RequireContextDependency( + { + request: requestExpr.string, + recursive, + regExp, + mode + }, + expr.range + ); + dep.loc = expr.loc; + dep.optional = parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + }); + } +}; diff --git a/node_modules/webpack/lib/dependencies/RequireContextPlugin.js b/node_modules/webpack/lib/dependencies/RequireContextPlugin.js new file mode 100644 index 0000000..4e44e87 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireContextPlugin.js @@ -0,0 +1,143 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireContextDependency = require("./RequireContextDependency"); +const ContextElementDependency = require("./ContextElementDependency"); + +const RequireContextDependencyParserPlugin = require("./RequireContextDependencyParserPlugin"); + +class RequireContextPlugin { + constructor(modulesDirectories, extensions, mainFiles) { + if (!Array.isArray(modulesDirectories)) { + throw new Error("modulesDirectories must be an array"); + } + if (!Array.isArray(extensions)) { + throw new Error("extensions must be an array"); + } + this.modulesDirectories = modulesDirectories; + this.extensions = extensions; + this.mainFiles = mainFiles; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "RequireContextPlugin", + (compilation, { contextModuleFactory, normalModuleFactory }) => { + compilation.dependencyFactories.set( + RequireContextDependency, + contextModuleFactory + ); + compilation.dependencyTemplates.set( + RequireContextDependency, + new RequireContextDependency.Template() + ); + + compilation.dependencyFactories.set( + ContextElementDependency, + normalModuleFactory + ); + + const handler = (parser, parserOptions) => { + if ( + parserOptions.requireContext !== undefined && + !parserOptions.requireContext + ) + return; + + new RequireContextDependencyParserPlugin().apply(parser); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("RequireContextPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("RequireContextPlugin", handler); + + contextModuleFactory.hooks.alternatives.tap( + "RequireContextPlugin", + items => { + if (items.length === 0) return items; + return items + .map(obj => { + return this.extensions + .filter(ext => { + const l = obj.request.length; + return ( + l > ext.length && + obj.request.substr(l - ext.length, l) === ext + ); + }) + .map(ext => { + const l = obj.request.length; + return { + context: obj.context, + request: obj.request.substr(0, l - ext.length) + }; + }) + .concat(obj); + }) + .reduce((a, b) => a.concat(b), []); + } + ); + + contextModuleFactory.hooks.alternatives.tap( + "RequireContextPlugin", + items => { + if (items.length === 0) return items; + return items + .map(obj => { + return this.mainFiles + .filter(mainFile => { + const l = obj.request.length; + return ( + l > mainFile.length + 1 && + obj.request.substr(l - mainFile.length - 1, l) === + "/" + mainFile + ); + }) + .map(mainFile => { + const l = obj.request.length; + return [ + { + context: obj.context, + request: obj.request.substr(0, l - mainFile.length) + }, + { + context: obj.context, + request: obj.request.substr(0, l - mainFile.length - 1) + } + ]; + }) + .reduce((a, b) => a.concat(b), []) + .concat(obj); + }) + .reduce((a, b) => a.concat(b), []); + } + ); + + contextModuleFactory.hooks.alternatives.tap( + "RequireContextPlugin", + items => { + if (items.length === 0) return items; + return items.map(obj => { + for (let i = 0; i < this.modulesDirectories.length; i++) { + const dir = this.modulesDirectories[i]; + const idx = obj.request.indexOf("./" + dir + "/"); + if (idx === 0) { + obj.request = obj.request.slice(dir.length + 3); + break; + } + } + return obj; + }); + } + ); + } + ); + } +} +module.exports = RequireContextPlugin; diff --git a/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlock.js b/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlock.js new file mode 100644 index 0000000..2a5dde7 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlock.js @@ -0,0 +1,33 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const AsyncDependenciesBlock = require("../AsyncDependenciesBlock"); +const RequireEnsureDependency = require("./RequireEnsureDependency"); + +module.exports = class RequireEnsureDependenciesBlock extends AsyncDependenciesBlock { + constructor( + expr, + successExpression, + errorExpression, + chunkName, + chunkNameRange, + module, + loc + ) { + super(chunkName, module, loc, null); + this.expr = expr; + const successBodyRange = + successExpression && + successExpression.body && + successExpression.body.range; + if (successBodyRange) { + this.range = [successBodyRange[0] + 1, successBodyRange[1] - 1]; + } + this.chunkNameRange = chunkNameRange; + const dep = new RequireEnsureDependency(this); + dep.loc = loc; + this.addDependency(dep); + } +}; diff --git a/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js b/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js new file mode 100644 index 0000000..213eaac --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js @@ -0,0 +1,116 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireEnsureDependenciesBlock = require("./RequireEnsureDependenciesBlock"); +const RequireEnsureItemDependency = require("./RequireEnsureItemDependency"); +const getFunctionExpression = require("./getFunctionExpression"); + +module.exports = class RequireEnsureDependenciesBlockParserPlugin { + apply(parser) { + parser.hooks.call + .for("require.ensure") + .tap("RequireEnsureDependenciesBlockParserPlugin", expr => { + let chunkName = null; + let chunkNameRange = null; + let errorExpressionArg = null; + let errorExpression = null; + switch (expr.arguments.length) { + case 4: { + const chunkNameExpr = parser.evaluateExpression(expr.arguments[3]); + if (!chunkNameExpr.isString()) return; + chunkNameRange = chunkNameExpr.range; + chunkName = chunkNameExpr.string; + } + // falls through + case 3: { + errorExpressionArg = expr.arguments[2]; + errorExpression = getFunctionExpression(errorExpressionArg); + + if (!errorExpression && !chunkName) { + const chunkNameExpr = parser.evaluateExpression( + expr.arguments[2] + ); + if (!chunkNameExpr.isString()) return; + chunkNameRange = chunkNameExpr.range; + chunkName = chunkNameExpr.string; + } + } + // falls through + case 2: { + const dependenciesExpr = parser.evaluateExpression( + expr.arguments[0] + ); + const dependenciesItems = dependenciesExpr.isArray() + ? dependenciesExpr.items + : [dependenciesExpr]; + const successExpressionArg = expr.arguments[1]; + const successExpression = getFunctionExpression( + successExpressionArg + ); + + if (successExpression) { + parser.walkExpressions(successExpression.expressions); + } + if (errorExpression) { + parser.walkExpressions(errorExpression.expressions); + } + + const dep = new RequireEnsureDependenciesBlock( + expr, + successExpression ? successExpression.fn : successExpressionArg, + errorExpression ? errorExpression.fn : errorExpressionArg, + chunkName, + chunkNameRange, + parser.state.module, + expr.loc + ); + const old = parser.state.current; + parser.state.current = dep; + try { + let failed = false; + parser.inScope([], () => { + for (const ee of dependenciesItems) { + if (ee.isString()) { + const edep = new RequireEnsureItemDependency(ee.string); + edep.loc = dep.loc; + dep.addDependency(edep); + } else { + failed = true; + } + } + }); + if (failed) { + return; + } + if (successExpression) { + if (successExpression.fn.body.type === "BlockStatement") { + parser.walkStatement(successExpression.fn.body); + } else { + parser.walkExpression(successExpression.fn.body); + } + } + old.addBlock(dep); + } finally { + parser.state.current = old; + } + if (!successExpression) { + parser.walkExpression(successExpressionArg); + } + if (errorExpression) { + if (errorExpression.fn.body.type === "BlockStatement") { + parser.walkStatement(errorExpression.fn.body); + } else { + parser.walkExpression(errorExpression.fn.body); + } + } else if (errorExpressionArg) { + parser.walkExpression(errorExpressionArg); + } + return true; + } + } + }); + } +}; diff --git a/node_modules/webpack/lib/dependencies/RequireEnsureDependency.js b/node_modules/webpack/lib/dependencies/RequireEnsureDependency.js new file mode 100644 index 0000000..8401305 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireEnsureDependency.js @@ -0,0 +1,58 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class RequireEnsureDependency extends NullDependency { + constructor(block) { + super(); + this.block = block; + } + + get type() { + return "require.ensure"; + } +} + +RequireEnsureDependency.Template = class RequireEnsureDependencyTemplate { + apply(dep, source, runtime) { + const depBlock = dep.block; + const promise = runtime.blockPromise({ + block: depBlock, + message: "require.ensure" + }); + const errorCallbackExists = + depBlock.expr.arguments.length === 4 || + (!depBlock.chunkName && depBlock.expr.arguments.length === 3); + const startBlock = `${promise}.then((`; + const middleBlock = ").bind(null, __webpack_require__)).catch("; + const endBlock = `).bind(null, __webpack_require__)).catch(${runtime.onError()})`; + source.replace( + depBlock.expr.range[0], + depBlock.expr.arguments[1].range[0] - 1, + startBlock + ); + if (errorCallbackExists) { + source.replace( + depBlock.expr.arguments[1].range[1], + depBlock.expr.arguments[2].range[0] - 1, + middleBlock + ); + source.replace( + depBlock.expr.arguments[2].range[1], + depBlock.expr.range[1] - 1, + ")" + ); + } else { + source.replace( + depBlock.expr.arguments[1].range[1], + depBlock.expr.range[1] - 1, + endBlock + ); + } + } +}; + +module.exports = RequireEnsureDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireEnsureItemDependency.js b/node_modules/webpack/lib/dependencies/RequireEnsureItemDependency.js new file mode 100644 index 0000000..b4b620b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireEnsureItemDependency.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const NullDependency = require("./NullDependency"); + +class RequireEnsureItemDependency extends ModuleDependency { + constructor(request) { + super(request); + } + + get type() { + return "require.ensure item"; + } +} + +RequireEnsureItemDependency.Template = NullDependency.Template; + +module.exports = RequireEnsureItemDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireEnsurePlugin.js b/node_modules/webpack/lib/dependencies/RequireEnsurePlugin.js new file mode 100644 index 0000000..c818e91 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireEnsurePlugin.js @@ -0,0 +1,74 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireEnsureItemDependency = require("./RequireEnsureItemDependency"); +const RequireEnsureDependency = require("./RequireEnsureDependency"); + +const NullFactory = require("../NullFactory"); + +const RequireEnsureDependenciesBlockParserPlugin = require("./RequireEnsureDependenciesBlockParserPlugin"); + +const ParserHelpers = require("../ParserHelpers"); + +class RequireEnsurePlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "RequireEnsurePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + RequireEnsureItemDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + RequireEnsureItemDependency, + new RequireEnsureItemDependency.Template() + ); + + compilation.dependencyFactories.set( + RequireEnsureDependency, + new NullFactory() + ); + compilation.dependencyTemplates.set( + RequireEnsureDependency, + new RequireEnsureDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if ( + parserOptions.requireEnsure !== undefined && + !parserOptions.requireEnsure + ) + return; + + new RequireEnsureDependenciesBlockParserPlugin().apply(parser); + parser.hooks.evaluateTypeof + .for("require.ensure") + .tap( + "RequireEnsurePlugin", + ParserHelpers.evaluateToString("function") + ); + parser.hooks.typeof + .for("require.ensure") + .tap( + "RequireEnsurePlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("RequireEnsurePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("RequireEnsurePlugin", handler); + } + ); + } +} +module.exports = RequireEnsurePlugin; diff --git a/node_modules/webpack/lib/dependencies/RequireHeaderDependency.js b/node_modules/webpack/lib/dependencies/RequireHeaderDependency.js new file mode 100644 index 0000000..6dddd06 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireHeaderDependency.js @@ -0,0 +1,26 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class RequireHeaderDependency extends NullDependency { + constructor(range) { + super(); + if (!Array.isArray(range)) throw new Error("range must be valid"); + this.range = range; + } +} + +RequireHeaderDependency.Template = class RequireHeaderDependencyTemplate { + apply(dep, source) { + source.replace(dep.range[0], dep.range[1] - 1, "__webpack_require__"); + } + + applyAsTemplateArgument(name, dep, source) { + source.replace(dep.range[0], dep.range[1] - 1, "require"); + } +}; + +module.exports = RequireHeaderDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireIncludeDependency.js b/node_modules/webpack/lib/dependencies/RequireIncludeDependency.js new file mode 100644 index 0000000..9eca576 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireIncludeDependency.js @@ -0,0 +1,39 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const ModuleDependency = require("./ModuleDependency"); +const Template = require("../Template"); + +class RequireIncludeDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + } + + getReference() { + if (!this.module) return null; + // This doesn't use any export + return new DependencyReference(this.module, [], false); + } + + get type() { + return "require.include"; + } +} + +RequireIncludeDependency.Template = class RequireIncludeDependencyTemplate { + apply(dep, source, runtime) { + const comment = runtime.outputOptions.pathinfo + ? Template.toComment( + `require.include ${runtime.requestShortener.shorten(dep.request)}` + ) + : ""; + source.replace(dep.range[0], dep.range[1] - 1, `undefined${comment}`); + } +}; + +module.exports = RequireIncludeDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireIncludeDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/RequireIncludeDependencyParserPlugin.js new file mode 100644 index 0000000..117e204 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireIncludeDependencyParserPlugin.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireIncludeDependency = require("./RequireIncludeDependency"); + +module.exports = class RequireIncludeDependencyParserPlugin { + apply(parser) { + parser.hooks.call + .for("require.include") + .tap("RequireIncludeDependencyParserPlugin", expr => { + if (expr.arguments.length !== 1) return; + const param = parser.evaluateExpression(expr.arguments[0]); + if (!param.isString()) return; + const dep = new RequireIncludeDependency(param.string, expr.range); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + }); + } +}; diff --git a/node_modules/webpack/lib/dependencies/RequireIncludePlugin.js b/node_modules/webpack/lib/dependencies/RequireIncludePlugin.js new file mode 100644 index 0000000..e7d535b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireIncludePlugin.js @@ -0,0 +1,61 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireIncludeDependency = require("./RequireIncludeDependency"); +const RequireIncludeDependencyParserPlugin = require("./RequireIncludeDependencyParserPlugin"); + +const ParserHelpers = require("../ParserHelpers"); + +class RequireIncludePlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "RequireIncludePlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + RequireIncludeDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + RequireIncludeDependency, + new RequireIncludeDependency.Template() + ); + + const handler = (parser, parserOptions) => { + if ( + parserOptions.requireInclude !== undefined && + !parserOptions.requireInclude + ) + return; + + new RequireIncludeDependencyParserPlugin().apply(parser); + parser.hooks.evaluateTypeof + .for("require.include") + .tap( + "RequireIncludePlugin", + ParserHelpers.evaluateToString("function") + ); + parser.hooks.typeof + .for("require.include") + .tap( + "RequireIncludePlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("RequireIncludePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("RequireIncludePlugin", handler); + } + ); + } +} +module.exports = RequireIncludePlugin; diff --git a/node_modules/webpack/lib/dependencies/RequireResolveContextDependency.js b/node_modules/webpack/lib/dependencies/RequireResolveContextDependency.js new file mode 100644 index 0000000..cc40451 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireResolveContextDependency.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ContextDependency = require("./ContextDependency"); +const ContextDependencyTemplateAsId = require("./ContextDependencyTemplateAsId"); + +class RequireResolveContextDependency extends ContextDependency { + constructor(options, range, valueRange) { + super(options); + this.range = range; + this.valueRange = valueRange; + } + + get type() { + return "amd require context"; + } +} + +RequireResolveContextDependency.Template = ContextDependencyTemplateAsId; + +module.exports = RequireResolveContextDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireResolveDependency.js b/node_modules/webpack/lib/dependencies/RequireResolveDependency.js new file mode 100644 index 0000000..3933baa --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireResolveDependency.js @@ -0,0 +1,22 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); +const ModuleDependencyAsId = require("./ModuleDependencyTemplateAsId"); + +class RequireResolveDependency extends ModuleDependency { + constructor(request, range) { + super(request); + this.range = range; + } + + get type() { + return "require.resolve"; + } +} + +RequireResolveDependency.Template = ModuleDependencyAsId; + +module.exports = RequireResolveDependency; diff --git a/node_modules/webpack/lib/dependencies/RequireResolveDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/RequireResolveDependencyParserPlugin.js new file mode 100644 index 0000000..0d356cf --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireResolveDependencyParserPlugin.js @@ -0,0 +1,86 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const RequireResolveDependency = require("./RequireResolveDependency"); +const RequireResolveContextDependency = require("./RequireResolveContextDependency"); +const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); + +class RequireResolveDependencyParserPlugin { + constructor(options) { + this.options = options; + } + + apply(parser) { + const options = this.options; + + const process = (expr, weak) => { + if (expr.arguments.length !== 1) return; + const param = parser.evaluateExpression(expr.arguments[0]); + if (param.isConditional()) { + for (const option of param.options) { + const result = processItem(expr, option, weak); + if (result === undefined) { + processContext(expr, option, weak); + } + } + const dep = new RequireResolveHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + } else { + const result = processItem(expr, param, weak); + if (result === undefined) { + processContext(expr, param, weak); + } + const dep = new RequireResolveHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + return true; + } + }; + const processItem = (expr, param, weak) => { + if (param.isString()) { + const dep = new RequireResolveDependency(param.string, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + dep.weak = weak; + parser.state.current.addDependency(dep); + return true; + } + }; + const processContext = (expr, param, weak) => { + const dep = ContextDependencyHelpers.create( + RequireResolveContextDependency, + param.range, + param, + expr, + options, + { + mode: weak ? "weak" : "sync" + }, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }; + + parser.hooks.call + .for("require.resolve") + .tap("RequireResolveDependencyParserPlugin", expr => { + return process(expr, false); + }); + parser.hooks.call + .for("require.resolveWeak") + .tap("RequireResolveDependencyParserPlugin", expr => { + return process(expr, true); + }); + } +} +module.exports = RequireResolveDependencyParserPlugin; diff --git a/node_modules/webpack/lib/dependencies/RequireResolveHeaderDependency.js b/node_modules/webpack/lib/dependencies/RequireResolveHeaderDependency.js new file mode 100644 index 0000000..05fe86d --- /dev/null +++ b/node_modules/webpack/lib/dependencies/RequireResolveHeaderDependency.js @@ -0,0 +1,26 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); + +class RequireResolveHeaderDependency extends NullDependency { + constructor(range) { + super(); + if (!Array.isArray(range)) throw new Error("range must be valid"); + this.range = range; + } +} + +RequireResolveHeaderDependency.Template = class RequireResolveHeaderDependencyTemplate { + apply(dep, source) { + source.replace(dep.range[0], dep.range[1] - 1, "/*require.resolve*/"); + } + + applyAsTemplateArgument(name, dep, source) { + source.replace(dep.range[0], dep.range[1] - 1, "/*require.resolve*/"); + } +}; + +module.exports = RequireResolveHeaderDependency; diff --git a/node_modules/webpack/lib/dependencies/SingleEntryDependency.js b/node_modules/webpack/lib/dependencies/SingleEntryDependency.js new file mode 100644 index 0000000..75a8c08 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/SingleEntryDependency.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const ModuleDependency = require("./ModuleDependency"); + +class SingleEntryDependency extends ModuleDependency { + /** + * @param {string} request request path for entry + */ + constructor(request) { + super(request); + } + + get type() { + return "single entry"; + } +} + +module.exports = SingleEntryDependency; diff --git a/node_modules/webpack/lib/dependencies/SystemPlugin.js b/node_modules/webpack/lib/dependencies/SystemPlugin.js new file mode 100644 index 0000000..0e3419b --- /dev/null +++ b/node_modules/webpack/lib/dependencies/SystemPlugin.js @@ -0,0 +1,122 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ParserHelpers = require("../ParserHelpers"); +const WebpackError = require("../WebpackError"); + +class SystemPlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "SystemPlugin", + (compilation, { normalModuleFactory }) => { + const handler = (parser, parserOptions) => { + if (parserOptions.system !== undefined && !parserOptions.system) + return; + + const shouldWarn = parserOptions.system === undefined; + + const setNotSupported = name => { + parser.hooks.evaluateTypeof + .for(name) + .tap("SystemPlugin", ParserHelpers.evaluateToString("undefined")); + parser.hooks.expression + .for(name) + .tap( + "SystemPlugin", + ParserHelpers.expressionIsUnsupported( + parser, + name + " is not supported by webpack." + ) + ); + }; + + parser.hooks.typeof + .for("System.import") + .tap( + "SystemPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("function") + ) + ); + parser.hooks.evaluateTypeof + .for("System.import") + .tap("SystemPlugin", ParserHelpers.evaluateToString("function")); + parser.hooks.typeof + .for("System") + .tap( + "SystemPlugin", + ParserHelpers.toConstantDependency( + parser, + JSON.stringify("object") + ) + ); + parser.hooks.evaluateTypeof + .for("System") + .tap("SystemPlugin", ParserHelpers.evaluateToString("object")); + + setNotSupported("System.set"); + setNotSupported("System.get"); + setNotSupported("System.register"); + + parser.hooks.expression.for("System").tap("SystemPlugin", () => { + const systemPolyfillRequire = ParserHelpers.requireFileAsExpression( + parser.state.module.context, + require.resolve("../../buildin/system") + ); + return ParserHelpers.addParsedVariableToModule( + parser, + "System", + systemPolyfillRequire + ); + }); + + parser.hooks.call.for("System.import").tap("SystemPlugin", expr => { + if (shouldWarn) { + parser.state.module.warnings.push( + new SystemImportDeprecationWarning( + parser.state.module, + expr.loc + ) + ); + } + + return parser.hooks.importCall.call(expr); + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("SystemPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("SystemPlugin", handler); + } + ); + } +} + +class SystemImportDeprecationWarning extends WebpackError { + constructor(module, loc) { + super( + "System.import() is deprecated and will be removed soon. Use import() instead.\n" + + "For more info visit https://webpack.js.org/guides/code-splitting/" + ); + + this.name = "SystemImportDeprecationWarning"; + + this.module = module; + this.loc = loc; + + Error.captureStackTrace(this, this.constructor); + } +} + +module.exports = SystemPlugin; diff --git a/node_modules/webpack/lib/dependencies/UnsupportedDependency.js b/node_modules/webpack/lib/dependencies/UnsupportedDependency.js new file mode 100644 index 0000000..614af78 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/UnsupportedDependency.js @@ -0,0 +1,27 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const NullDependency = require("./NullDependency"); +const webpackMissingModule = require("./WebpackMissingModule").module; + +class UnsupportedDependency extends NullDependency { + constructor(request, range) { + super(); + this.request = request; + this.range = range; + } +} + +UnsupportedDependency.Template = class UnsupportedDependencyTemplate { + apply(dep, source, runtime) { + source.replace( + dep.range[0], + dep.range[1], + webpackMissingModule(dep.request) + ); + } +}; + +module.exports = UnsupportedDependency; diff --git a/node_modules/webpack/lib/dependencies/WebAssemblyExportImportedDependency.js b/node_modules/webpack/lib/dependencies/WebAssemblyExportImportedDependency.js new file mode 100644 index 0000000..9fa55f2 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/WebAssemblyExportImportedDependency.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const ModuleDependency = require("./ModuleDependency"); + +class WebAssemblyExportImportedDependency extends ModuleDependency { + constructor(exportName, request, name, valueType) { + super(request); + /** @type {string} */ + this.exportName = exportName; + /** @type {string} */ + this.name = name; + /** @type {string} */ + this.valueType = valueType; + } + + getReference() { + if (!this.module) return null; + return new DependencyReference(this.module, [this.name], false); + } + + get type() { + return "wasm export import"; + } +} + +module.exports = WebAssemblyExportImportedDependency; diff --git a/node_modules/webpack/lib/dependencies/WebAssemblyImportDependency.js b/node_modules/webpack/lib/dependencies/WebAssemblyImportDependency.js new file mode 100644 index 0000000..4b36faa --- /dev/null +++ b/node_modules/webpack/lib/dependencies/WebAssemblyImportDependency.js @@ -0,0 +1,54 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const DependencyReference = require("./DependencyReference"); +const ModuleDependency = require("./ModuleDependency"); +const UnsupportedWebAssemblyFeatureError = require("../wasm/UnsupportedWebAssemblyFeatureError"); + +/** @typedef {import("@webassemblyjs/ast").ModuleImportDescription} ModuleImportDescription */ + +class WebAssemblyImportDependency extends ModuleDependency { + /** + * @param {string} request the request + * @param {string} name the imported name + * @param {ModuleImportDescription} description the WASM ast node + * @param {false | string} onlyDirectImport if only direct imports are allowed + */ + constructor(request, name, description, onlyDirectImport) { + super(request); + /** @type {string} */ + this.name = name; + /** @type {ModuleImportDescription} */ + this.description = description; + /** @type {false | string} */ + this.onlyDirectImport = onlyDirectImport; + } + + getReference() { + if (!this.module) return null; + return new DependencyReference(this.module, [this.name], false); + } + + getErrors() { + if ( + this.onlyDirectImport && + this.module && + !this.module.type.startsWith("webassembly") + ) { + return [ + new UnsupportedWebAssemblyFeatureError( + `Import "${this.name}" from "${this.request}" with ${this.onlyDirectImport} can only be used for direct wasm to wasm dependencies` + ) + ]; + } + } + + get type() { + return "wasm import"; + } +} + +module.exports = WebAssemblyImportDependency; diff --git a/node_modules/webpack/lib/dependencies/WebpackMissingModule.js b/node_modules/webpack/lib/dependencies/WebpackMissingModule.js new file mode 100644 index 0000000..a55c9ec --- /dev/null +++ b/node_modules/webpack/lib/dependencies/WebpackMissingModule.js @@ -0,0 +1,20 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const toErrorCode = err => + `var e = new Error(${JSON.stringify(err)}); e.code = 'MODULE_NOT_FOUND';`; + +exports.module = request => + `!(function webpackMissingModule() { ${exports.moduleCode(request)} }())`; + +exports.promise = request => { + const errorCode = toErrorCode(`Cannot find module '${request}'`); + return `Promise.reject(function webpackMissingModule() { ${errorCode} return e; }())`; +}; + +exports.moduleCode = request => { + const errorCode = toErrorCode(`Cannot find module '${request}'`); + return `${errorCode} throw e;`; +}; diff --git a/node_modules/webpack/lib/dependencies/getFunctionExpression.js b/node_modules/webpack/lib/dependencies/getFunctionExpression.js new file mode 100644 index 0000000..0e73840 --- /dev/null +++ b/node_modules/webpack/lib/dependencies/getFunctionExpression.js @@ -0,0 +1,52 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +module.exports = expr => { + // <FunctionExpression> + if ( + expr.type === "FunctionExpression" || + expr.type === "ArrowFunctionExpression" + ) { + return { + fn: expr, + expressions: [], + needThis: false + }; + } + + // <FunctionExpression>.bind(<Expression>) + if ( + expr.type === "CallExpression" && + expr.callee.type === "MemberExpression" && + expr.callee.object.type === "FunctionExpression" && + expr.callee.property.type === "Identifier" && + expr.callee.property.name === "bind" && + expr.arguments.length === 1 + ) { + return { + fn: expr.callee.object, + expressions: [expr.arguments[0]], + needThis: undefined + }; + } + // (function(_this) {return <FunctionExpression>})(this) (Coffeescript) + if ( + expr.type === "CallExpression" && + expr.callee.type === "FunctionExpression" && + expr.callee.body.type === "BlockStatement" && + expr.arguments.length === 1 && + expr.arguments[0].type === "ThisExpression" && + expr.callee.body.body && + expr.callee.body.body.length === 1 && + expr.callee.body.body[0].type === "ReturnStatement" && + expr.callee.body.body[0].argument && + expr.callee.body.body[0].argument.type === "FunctionExpression" + ) { + return { + fn: expr.callee.body.body[0].argument, + expressions: [], + needThis: true + }; + } +}; diff --git a/node_modules/webpack/lib/formatLocation.js b/node_modules/webpack/lib/formatLocation.js new file mode 100644 index 0000000..f608cd4 --- /dev/null +++ b/node_modules/webpack/lib/formatLocation.js @@ -0,0 +1,75 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */ +/** @typedef {import("./Dependency").SourcePosition} SourcePosition */ + +// TODO webpack 5: pos must be SourcePosition +/** + * @param {SourcePosition|DependencyLocation|string} pos position + * @returns {string} formatted position + */ +const formatPosition = pos => { + if (pos === null) return ""; + // TODO webpack 5: Simplify this + if (typeof pos === "string") return pos; + if (typeof pos === "number") return `${pos}`; + if (typeof pos === "object") { + if ("line" in pos && "column" in pos) { + return `${pos.line}:${pos.column}`; + } else if ("line" in pos) { + return `${pos.line}:?`; + } else if ("index" in pos) { + // TODO webpack 5 remove this case + return `+${pos.index}`; + } else { + return ""; + } + } + return ""; +}; + +// TODO webpack 5: loc must be DependencyLocation +/** + * @param {DependencyLocation|SourcePosition|string} loc location + * @returns {string} formatted location + */ +const formatLocation = loc => { + if (loc === null) return ""; + // TODO webpack 5: Simplify this + if (typeof loc === "string") return loc; + if (typeof loc === "number") return `${loc}`; + if (typeof loc === "object") { + if ("start" in loc && loc.start && "end" in loc && loc.end) { + if ( + typeof loc.start === "object" && + typeof loc.start.line === "number" && + typeof loc.end === "object" && + typeof loc.end.line === "number" && + typeof loc.end.column === "number" && + loc.start.line === loc.end.line + ) { + return `${formatPosition(loc.start)}-${loc.end.column}`; + } else { + return `${formatPosition(loc.start)}-${formatPosition(loc.end)}`; + } + } + if ("start" in loc && loc.start) { + return formatPosition(loc.start); + } + if ("name" in loc && "index" in loc) { + return `${loc.name}[${loc.index}]`; + } + if ("name" in loc) { + return loc.name; + } + return formatPosition(loc); + } + return ""; +}; + +module.exports = formatLocation; diff --git a/node_modules/webpack/lib/logging/Logger.js b/node_modules/webpack/lib/logging/Logger.js new file mode 100644 index 0000000..835683e --- /dev/null +++ b/node_modules/webpack/lib/logging/Logger.js @@ -0,0 +1,128 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + +"use strict"; + +const LogType = Object.freeze({ + error: /** @type {"error"} */ ("error"), // message, c style arguments + warn: /** @type {"warn"} */ ("warn"), // message, c style arguments + info: /** @type {"info"} */ ("info"), // message, c style arguments + log: /** @type {"log"} */ ("log"), // message, c style arguments + debug: /** @type {"debug"} */ ("debug"), // message, c style arguments + + trace: /** @type {"trace"} */ ("trace"), // no arguments + + group: /** @type {"group"} */ ("group"), // [label] + groupCollapsed: /** @type {"groupCollapsed"} */ ("groupCollapsed"), // [label] + groupEnd: /** @type {"groupEnd"} */ ("groupEnd"), // [label] + + profile: /** @type {"profile"} */ ("profile"), // [profileName] + profileEnd: /** @type {"profileEnd"} */ ("profileEnd"), // [profileName] + + time: /** @type {"time"} */ ("time"), // name, time as [seconds, nanoseconds] + + clear: /** @type {"clear"} */ ("clear"), // no arguments + status: /** @type {"status"} */ ("status") // message, arguments +}); + +exports.LogType = LogType; + +/** @typedef {typeof LogType[keyof typeof LogType]} LogTypeEnum */ + +const LOG_SYMBOL = Symbol("webpack logger raw log method"); +const TIMERS_SYMBOL = Symbol("webpack logger times"); + +class WebpackLogger { + /** + * @param {function(LogTypeEnum, any[]=): void} log log function + */ + constructor(log) { + this[LOG_SYMBOL] = log; + } + + error(...args) { + this[LOG_SYMBOL](LogType.error, args); + } + + warn(...args) { + this[LOG_SYMBOL](LogType.warn, args); + } + + info(...args) { + this[LOG_SYMBOL](LogType.info, args); + } + + log(...args) { + this[LOG_SYMBOL](LogType.log, args); + } + + debug(...args) { + this[LOG_SYMBOL](LogType.debug, args); + } + + assert(assertion, ...args) { + if (!assertion) { + this[LOG_SYMBOL](LogType.error, args); + } + } + + trace() { + this[LOG_SYMBOL](LogType.trace, ["Trace"]); + } + + clear() { + this[LOG_SYMBOL](LogType.clear); + } + + status(...args) { + this[LOG_SYMBOL](LogType.status, args); + } + + group(...args) { + this[LOG_SYMBOL](LogType.group, args); + } + + groupCollapsed(...args) { + this[LOG_SYMBOL](LogType.groupCollapsed, args); + } + + groupEnd(...args) { + this[LOG_SYMBOL](LogType.groupEnd, args); + } + + profile(label) { + this[LOG_SYMBOL](LogType.profile, [label]); + } + + profileEnd(label) { + this[LOG_SYMBOL](LogType.profileEnd, [label]); + } + + time(label) { + this[TIMERS_SYMBOL] = this[TIMERS_SYMBOL] || new Map(); + this[TIMERS_SYMBOL].set(label, process.hrtime()); + } + + timeLog(label) { + const prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label); + if (!prev) { + throw new Error(`No such label '${label}' for WebpackLogger.timeLog()`); + } + const time = process.hrtime(prev); + this[LOG_SYMBOL](LogType.time, [label, ...time]); + } + + timeEnd(label) { + const prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label); + if (!prev) { + throw new Error(`No such label '${label}' for WebpackLogger.timeEnd()`); + } + const time = process.hrtime(prev); + this[TIMERS_SYMBOL].delete(label); + this[LOG_SYMBOL](LogType.time, [label, ...time]); + } +} + +exports.Logger = WebpackLogger; diff --git a/node_modules/webpack/lib/logging/createConsoleLogger.js b/node_modules/webpack/lib/logging/createConsoleLogger.js new file mode 100644 index 0000000..504f660 --- /dev/null +++ b/node_modules/webpack/lib/logging/createConsoleLogger.js @@ -0,0 +1,210 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { LogType } = require("./Logger"); + +/** @typedef {import("./Logger").LogTypeEnum} LogTypeEnum */ +/** @typedef {import("../../declarations/WebpackOptions").FilterTypes} FilterTypes */ +/** @typedef {import("../../declarations/WebpackOptions").FilterItemTypes} FilterItemTypes */ + +/** @typedef {function(string): boolean} FilterFunction */ + +/** + * @typedef {Object} LoggerOptions + * @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel + * @property {FilterTypes|boolean} debug filter for debug logging + * @property {Console & { status?: Function, logTime?: Function }} console the console to log to + */ + +/** + * @param {FilterItemTypes} item an input item + * @returns {FilterFunction} filter funtion + */ +const filterToFunction = item => { + if (typeof item === "string") { + const regExp = new RegExp( + `[\\\\/]${item.replace( + // eslint-disable-next-line no-useless-escape + /[-[\]{}()*+?.\\^$|]/g, + "\\$&" + )}([\\\\/]|$|!|\\?)` + ); + return ident => regExp.test(ident); + } + if (item && typeof item === "object" && typeof item.test === "function") { + return ident => item.test(ident); + } + if (typeof item === "function") { + return item; + } + if (typeof item === "boolean") { + return () => item; + } +}; + +/** + * @enum {number} + */ +const LogLevel = { + none: 6, + false: 6, + error: 5, + warn: 4, + info: 3, + log: 2, + true: 2, + verbose: 1 +}; + +/** + * @param {LoggerOptions} options options object + * @returns {function(string, LogTypeEnum, any[]): void} logging function + */ +module.exports = ({ level = "info", debug = false, console }) => { + const debugFilters = + typeof debug === "boolean" + ? [() => debug] + : /** @type {FilterItemTypes[]} */ ([]) + .concat(debug) + .map(filterToFunction); + /** @type {number} */ + const loglevel = LogLevel[`${level}`] || 0; + + /** + * @param {string} name name of the logger + * @param {LogTypeEnum} type type of the log entry + * @param {any[]} args arguments of the log entry + * @returns {void} + */ + const logger = (name, type, args) => { + const labeledArgs = () => { + if (Array.isArray(args)) { + if (args.length > 0 && typeof args[0] === "string") { + return [`[${name}] ${args[0]}`, ...args.slice(1)]; + } else { + return [`[${name}]`, ...args]; + } + } else { + return []; + } + }; + const debug = debugFilters.some(f => f(name)); + switch (type) { + case LogType.debug: + if (!debug) return; + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.debug === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.debug(...labeledArgs()); + } else { + console.log(...labeledArgs()); + } + break; + case LogType.log: + if (!debug && loglevel > LogLevel.log) return; + console.log(...labeledArgs()); + break; + case LogType.info: + if (!debug && loglevel > LogLevel.info) return; + console.info(...labeledArgs()); + break; + case LogType.warn: + if (!debug && loglevel > LogLevel.warn) return; + console.warn(...labeledArgs()); + break; + case LogType.error: + if (!debug && loglevel > LogLevel.error) return; + console.error(...labeledArgs()); + break; + case LogType.trace: + if (!debug) return; + console.trace(); + break; + case LogType.groupCollapsed: + if (!debug && loglevel > LogLevel.log) return; + if (!debug && loglevel > LogLevel.verbose) { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.groupCollapsed === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.groupCollapsed(...labeledArgs()); + } else { + console.log(...labeledArgs()); + } + break; + } + // falls through + case LogType.group: + if (!debug && loglevel > LogLevel.log) return; + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.group === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.group(...labeledArgs()); + } else { + console.log(...labeledArgs()); + } + break; + case LogType.groupEnd: + if (!debug && loglevel > LogLevel.log) return; + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.groupEnd === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.groupEnd(); + } + break; + case LogType.time: { + if (!debug && loglevel > LogLevel.log) return; + const ms = args[1] * 1000 + args[2] / 1000000; + const msg = `[${name}] ${args[0]}: ${ms}ms`; + if (typeof console.logTime === "function") { + console.logTime(msg); + } else { + console.log(msg); + } + break; + } + case LogType.profile: + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.profile === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.profile(...labeledArgs()); + } + break; + case LogType.profileEnd: + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.profileEnd === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.profileEnd(...labeledArgs()); + } + break; + case LogType.clear: + if (!debug && loglevel > LogLevel.log) return; + // eslint-disable-next-line node/no-unsupported-features/node-builtins + if (typeof console.clear === "function") { + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.clear(); + } + break; + case LogType.status: + if (!debug && loglevel > LogLevel.info) return; + if (typeof console.status === "function") { + if (args.length === 0) { + console.status(); + } else { + console.status(...labeledArgs()); + } + } else { + if (args.length !== 0) { + console.info(...labeledArgs()); + } + } + break; + default: + throw new Error(`Unexpected LogType ${type}`); + } + }; + return logger; +}; diff --git a/node_modules/webpack/lib/logging/runtime.js b/node_modules/webpack/lib/logging/runtime.js new file mode 100644 index 0000000..18e2148 --- /dev/null +++ b/node_modules/webpack/lib/logging/runtime.js @@ -0,0 +1,36 @@ +const SyncBailHook = require("tapable/lib/SyncBailHook"); +const { Logger } = require("./Logger"); +const createConsoleLogger = require("./createConsoleLogger"); + +/** @type {createConsoleLogger.LoggerOptions} */ +let currentDefaultLoggerOptions = { + level: "info", + debug: false, + console +}; +let currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions); + +/** + * @param {string} name name of the logger + * @returns {Logger} a logger + */ +exports.getLogger = name => { + return new Logger((type, args) => { + if (exports.hooks.log.call(name, type, args) === undefined) { + currentDefaultLogger(name, type, args); + } + }); +}; + +/** + * @param {createConsoleLogger.LoggerOptions} options new options, merge with old options + * @returns {void} + */ +exports.configureDefaultLogger = options => { + Object.assign(currentDefaultLoggerOptions, options); + currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions); +}; + +exports.hooks = { + log: new SyncBailHook(["origin", "type", "args"]) +}; diff --git a/node_modules/webpack/lib/logging/truncateArgs.js b/node_modules/webpack/lib/logging/truncateArgs.js new file mode 100644 index 0000000..8522586 --- /dev/null +++ b/node_modules/webpack/lib/logging/truncateArgs.js @@ -0,0 +1,76 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + +"use strict"; + +/** + * @param {any[]} args items to be truncated + * @param {number} maxLength maximum length of args including spaces between + * @returns {string[]} truncated args + */ +const truncateArgs = (args, maxLength) => { + const lengths = args.map(a => `${a}`.length); + const availableLength = maxLength - lengths.length + 1; + + if (availableLength > 0 && args.length === 1) { + if (availableLength >= args[0].length) { + return args; + } else if (availableLength > 3) { + return ["..." + args[0].slice(-availableLength + 3)]; + } else { + return [args[0].slice(-availableLength)]; + } + } + + // Check if there is space for at least 4 chars per arg + if (availableLength < lengths.reduce((s, i) => s + Math.min(i, 6), 0)) { + // remove args + if (args.length > 1) + return truncateArgs(args.slice(0, args.length - 1), maxLength); + return []; + } + + let currentLength = lengths.reduce((a, b) => a + b, 0); + + // Check if all fits into maxLength + if (currentLength <= availableLength) return args; + + // Try to remove chars from the longest items until it fits + while (currentLength > availableLength) { + const maxLength = Math.max(...lengths); + const shorterItems = lengths.filter(l => l !== maxLength); + const nextToMaxLength = + shorterItems.length > 0 ? Math.max(...shorterItems) : 0; + const maxReduce = maxLength - nextToMaxLength; + let maxItems = lengths.length - shorterItems.length; + let overrun = currentLength - availableLength; + for (let i = 0; i < lengths.length; i++) { + if (lengths[i] === maxLength) { + const reduce = Math.min(Math.floor(overrun / maxItems), maxReduce); + lengths[i] -= reduce; + currentLength -= reduce; + overrun -= reduce; + maxItems--; + } + } + } + + // Return args reduced to length in lengths + return args.map((a, i) => { + const str = `${a}`; + const length = lengths[i]; + if (str.length === length) { + return str; + } else if (length > 5) { + return "..." + str.slice(-length + 3); + } else if (length > 0) { + return str.slice(-length); + } else { + return ""; + } + }); +}; + +module.exports = truncateArgs; diff --git a/node_modules/webpack/lib/node/NodeChunkTemplatePlugin.js b/node_modules/webpack/lib/node/NodeChunkTemplatePlugin.js new file mode 100644 index 0000000..292182a --- /dev/null +++ b/node_modules/webpack/lib/node/NodeChunkTemplatePlugin.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +class NodeChunkTemplatePlugin { + apply(chunkTemplate) { + chunkTemplate.hooks.render.tap( + "NodeChunkTemplatePlugin", + (modules, chunk) => { + const source = new ConcatSource(); + source.add( + `exports.ids = ${JSON.stringify(chunk.ids)};\nexports.modules = ` + ); + source.add(modules); + source.add(";"); + return source; + } + ); + chunkTemplate.hooks.hash.tap("NodeChunkTemplatePlugin", hash => { + hash.update("node"); + hash.update("3"); + }); + } +} + +module.exports = NodeChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/node/NodeEnvironmentPlugin.js b/node_modules/webpack/lib/node/NodeEnvironmentPlugin.js new file mode 100644 index 0000000..98c7985 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeEnvironmentPlugin.js @@ -0,0 +1,44 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const NodeWatchFileSystem = require("./NodeWatchFileSystem"); +const NodeOutputFileSystem = require("./NodeOutputFileSystem"); +const NodeJsInputFileSystem = require("enhanced-resolve/lib/NodeJsInputFileSystem"); +const CachedInputFileSystem = require("enhanced-resolve/lib/CachedInputFileSystem"); +const createConsoleLogger = require("../logging/createConsoleLogger"); +const nodeConsole = require("./nodeConsole"); + +class NodeEnvironmentPlugin { + constructor(options) { + this.options = options || {}; + } + + apply(compiler) { + compiler.infrastructureLogger = createConsoleLogger( + Object.assign( + { + level: "info", + debug: false, + console: nodeConsole + }, + this.options.infrastructureLogging + ) + ); + compiler.inputFileSystem = new CachedInputFileSystem( + new NodeJsInputFileSystem(), + 60000 + ); + const inputFileSystem = compiler.inputFileSystem; + compiler.outputFileSystem = new NodeOutputFileSystem(); + compiler.watchFileSystem = new NodeWatchFileSystem( + compiler.inputFileSystem + ); + compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", compiler => { + if (compiler.inputFileSystem === inputFileSystem) inputFileSystem.purge(); + }); + } +} +module.exports = NodeEnvironmentPlugin; diff --git a/node_modules/webpack/lib/node/NodeHotUpdateChunkTemplatePlugin.js b/node_modules/webpack/lib/node/NodeHotUpdateChunkTemplatePlugin.js new file mode 100644 index 0000000..bbd2e12 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeHotUpdateChunkTemplatePlugin.js @@ -0,0 +1,36 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +class NodeHotUpdateChunkTemplatePlugin { + apply(hotUpdateChunkTemplate) { + hotUpdateChunkTemplate.hooks.render.tap( + "NodeHotUpdateChunkTemplatePlugin", + (modulesSource, modules, removedModules, hash, id) => { + const source = new ConcatSource(); + source.add( + "exports.id = " + JSON.stringify(id) + ";\nexports.modules = " + ); + source.add(modulesSource); + source.add(";"); + return source; + } + ); + hotUpdateChunkTemplate.hooks.hash.tap( + "NodeHotUpdateChunkTemplatePlugin", + hash => { + hash.update("NodeHotUpdateChunkTemplatePlugin"); + hash.update("3"); + hash.update( + hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + "" + ); + hash.update(hotUpdateChunkTemplate.outputOptions.library + ""); + } + ); + } +} +module.exports = NodeHotUpdateChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/node/NodeMainTemplate.runtime.js b/node_modules/webpack/lib/node/NodeMainTemplate.runtime.js new file mode 100644 index 0000000..0880124 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeMainTemplate.runtime.js @@ -0,0 +1,32 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// eslint-disable-next-line no-unused-vars +var $hotChunkFilename$ = undefined; +var hotAddUpdateChunk = undefined; +var installedChunks = undefined; +var $hotMainFilename$ = undefined; + +module.exports = function() { + // eslint-disable-next-line no-unused-vars + function hotDownloadUpdateChunk(chunkId) { + var chunk = require("./" + $hotChunkFilename$); + hotAddUpdateChunk(chunk.id, chunk.modules); + } + + // eslint-disable-next-line no-unused-vars + function hotDownloadManifest() { + try { + var update = require("./" + $hotMainFilename$); + } catch (e) { + return Promise.resolve(); + } + return Promise.resolve(update); + } + + //eslint-disable-next-line no-unused-vars + function hotDisposeChunk(chunkId) { + delete installedChunks[chunkId]; + } +}; diff --git a/node_modules/webpack/lib/node/NodeMainTemplateAsync.runtime.js b/node_modules/webpack/lib/node/NodeMainTemplateAsync.runtime.js new file mode 100644 index 0000000..a021f5a --- /dev/null +++ b/node_modules/webpack/lib/node/NodeMainTemplateAsync.runtime.js @@ -0,0 +1,50 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// eslint-disable-next-line no-unused-vars +var $hotChunkFilename$ = undefined; +var $require$ = undefined; +var hotAddUpdateChunk = undefined; +var $hotMainFilename$ = undefined; +var installedChunks = undefined; + +module.exports = function() { + // eslint-disable-next-line no-unused-vars + function hotDownloadUpdateChunk(chunkId) { + var filename = require("path").join(__dirname, $hotChunkFilename$); + require("fs").readFile(filename, "utf-8", function(err, content) { + if (err) { + if ($require$.onError) return $require$.oe(err); + throw err; + } + var chunk = {}; + require("vm").runInThisContext( + "(function(exports) {" + content + "\n})", + { filename: filename } + )(chunk); + hotAddUpdateChunk(chunk.id, chunk.modules); + }); + } + + // eslint-disable-next-line no-unused-vars + function hotDownloadManifest() { + var filename = require("path").join(__dirname, $hotMainFilename$); + return new Promise(function(resolve, reject) { + require("fs").readFile(filename, "utf-8", function(err, content) { + if (err) return resolve(); + try { + var update = JSON.parse(content); + } catch (e) { + return reject(e); + } + resolve(update); + }); + }); + } + + // eslint-disable-next-line no-unused-vars + function hotDisposeChunk(chunkId) { + delete installedChunks[chunkId]; + } +}; diff --git a/node_modules/webpack/lib/node/NodeMainTemplatePlugin.js b/node_modules/webpack/lib/node/NodeMainTemplatePlugin.js new file mode 100644 index 0000000..a270296 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeMainTemplatePlugin.js @@ -0,0 +1,321 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("../Template"); + +module.exports = class NodeMainTemplatePlugin { + constructor(asyncChunkLoading) { + this.asyncChunkLoading = asyncChunkLoading; + } + + apply(mainTemplate) { + const needChunkOnDemandLoadingCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.getNumberOfChildren() > 0) return true; + } + return false; + }; + const asyncChunkLoading = this.asyncChunkLoading; + mainTemplate.hooks.localVars.tap( + "NodeMainTemplatePlugin", + (source, chunk) => { + if (needChunkOnDemandLoadingCode(chunk)) { + return Template.asString([ + source, + "", + "// object to store loaded chunks", + '// "0" means "already loaded"', + "var installedChunks = {", + Template.indent( + chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(",\n") + ), + "};" + ]); + } + return source; + } + ); + mainTemplate.hooks.requireExtensions.tap( + "NodeMainTemplatePlugin", + (source, chunk) => { + if (needChunkOnDemandLoadingCode(chunk)) { + return Template.asString([ + source, + "", + "// uncaught error handler for webpack runtime", + `${mainTemplate.requireFn}.oe = function(err) {`, + Template.indent([ + "process.nextTick(function() {", + Template.indent( + "throw err; // catch this error by using import().catch()" + ), + "});" + ]), + "};" + ]); + } + return source; + } + ); + mainTemplate.hooks.requireEnsure.tap( + "NodeMainTemplatePlugin", + (source, chunk, hash) => { + const chunkFilename = mainTemplate.outputOptions.chunkFilename; + const chunkMaps = chunk.getChunkMaps(); + const insertMoreModules = [ + "var moreModules = chunk.modules, chunkIds = chunk.ids;", + "for(var moduleId in moreModules) {", + Template.indent( + mainTemplate.renderAddModule( + hash, + chunk, + "moduleId", + "moreModules[moduleId]" + ) + ), + "}" + ]; + if (asyncChunkLoading) { + return Template.asString([ + source, + "", + "// ReadFile + VM.run chunk loading for javascript", + "", + "var installedChunkData = installedChunks[chunkId];", + 'if(installedChunkData !== 0) { // 0 means "already installed".', + Template.indent([ + '// array of [resolve, reject, promise] means "currently loading"', + "if(installedChunkData) {", + Template.indent(["promises.push(installedChunkData[2]);"]), + "} else {", + Template.indent([ + "// load the chunk and return promise to it", + "var promise = new Promise(function(resolve, reject) {", + Template.indent([ + "installedChunkData = installedChunks[chunkId] = [resolve, reject];", + "var filename = require('path').join(__dirname, " + + mainTemplate.getAssetPath( + JSON.stringify(`/${chunkFilename}`), + { + hash: `" + ${mainTemplate.renderCurrentHashCode( + hash + )} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode( + hash, + length + )} + "`, + chunk: { + id: '" + chunkId + "', + hash: `" + ${JSON.stringify( + chunkMaps.hash + )}[chunkId] + "`, + hashWithLength: length => { + const shortChunkHashMap = {}; + for (const chunkId of Object.keys(chunkMaps.hash)) { + if (typeof chunkMaps.hash[chunkId] === "string") { + shortChunkHashMap[chunkId] = chunkMaps.hash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap + )}[chunkId] + "`; + }, + contentHash: { + javascript: `" + ${JSON.stringify( + chunkMaps.contentHash.javascript + )}[chunkId] + "` + }, + contentHashWithLength: { + javascript: length => { + const shortContentHashMap = {}; + const contentHash = + chunkMaps.contentHash.javascript; + for (const chunkId of Object.keys(contentHash)) { + if (typeof contentHash[chunkId] === "string") { + shortContentHashMap[chunkId] = contentHash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortContentHashMap + )}[chunkId] + "`; + } + }, + name: `" + (${JSON.stringify( + chunkMaps.name + )}[chunkId]||chunkId) + "` + }, + contentHashType: "javascript" + } + ) + + ");", + "require('fs').readFile(filename, 'utf-8', function(err, content) {", + Template.indent( + [ + "if(err) return reject(err);", + "var chunk = {};", + "require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" + + "(chunk, require, require('path').dirname(filename), filename);" + ] + .concat(insertMoreModules) + .concat([ + "var callbacks = [];", + "for(var i = 0; i < chunkIds.length; i++) {", + Template.indent([ + "if(installedChunks[chunkIds[i]])", + Template.indent([ + "callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);" + ]), + "installedChunks[chunkIds[i]] = 0;" + ]), + "}", + "for(i = 0; i < callbacks.length; i++)", + Template.indent("callbacks[i]();") + ]) + ), + "});" + ]), + "});", + "promises.push(installedChunkData[2] = promise);" + ]), + "}" + ]), + "}" + ]); + } else { + const request = mainTemplate.getAssetPath( + JSON.stringify(`./${chunkFilename}`), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + chunk: { + id: '" + chunkId + "', + hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`, + hashWithLength: length => { + const shortChunkHashMap = {}; + for (const chunkId of Object.keys(chunkMaps.hash)) { + if (typeof chunkMaps.hash[chunkId] === "string") { + shortChunkHashMap[chunkId] = chunkMaps.hash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap + )}[chunkId] + "`; + }, + contentHash: { + javascript: `" + ${JSON.stringify( + chunkMaps.contentHash.javascript + )}[chunkId] + "` + }, + contentHashWithLength: { + javascript: length => { + const shortContentHashMap = {}; + const contentHash = chunkMaps.contentHash.javascript; + for (const chunkId of Object.keys(contentHash)) { + if (typeof contentHash[chunkId] === "string") { + shortContentHashMap[chunkId] = contentHash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortContentHashMap + )}[chunkId] + "`; + } + }, + name: `" + (${JSON.stringify( + chunkMaps.name + )}[chunkId]||chunkId) + "` + }, + contentHashType: "javascript" + } + ); + return Template.asString([ + source, + "", + "// require() chunk loading for javascript", + "", + '// "0" is the signal for "already loaded"', + "if(installedChunks[chunkId] !== 0) {", + Template.indent( + [`var chunk = require(${request});`] + .concat(insertMoreModules) + .concat([ + "for(var i = 0; i < chunkIds.length; i++)", + Template.indent("installedChunks[chunkIds[i]] = 0;") + ]) + ), + "}" + ]); + } + } + ); + mainTemplate.hooks.hotBootstrap.tap( + "NodeMainTemplatePlugin", + (source, chunk, hash) => { + const hotUpdateChunkFilename = + mainTemplate.outputOptions.hotUpdateChunkFilename; + const hotUpdateMainFilename = + mainTemplate.outputOptions.hotUpdateMainFilename; + const chunkMaps = chunk.getChunkMaps(); + const currentHotUpdateChunkFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateChunkFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + chunk: { + id: '" + chunkId + "', + hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`, + hashWithLength: length => { + const shortChunkHashMap = {}; + for (const chunkId of Object.keys(chunkMaps.hash)) { + if (typeof chunkMaps.hash[chunkId] === "string") { + shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr( + 0, + length + ); + } + } + return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`; + }, + name: `" + (${JSON.stringify( + chunkMaps.name + )}[chunkId]||chunkId) + "` + } + } + ); + const currentHotUpdateMainFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateMainFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "` + } + ); + return Template.getFunctionContent( + asyncChunkLoading + ? require("./NodeMainTemplateAsync.runtime") + : require("./NodeMainTemplate.runtime") + ) + .replace(/\$require\$/g, mainTemplate.requireFn) + .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) + .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename); + } + ); + mainTemplate.hooks.hash.tap("NodeMainTemplatePlugin", hash => { + hash.update("node"); + hash.update("4"); + }); + } +}; diff --git a/node_modules/webpack/lib/node/NodeOutputFileSystem.js b/node_modules/webpack/lib/node/NodeOutputFileSystem.js new file mode 100644 index 0000000..2789b57 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeOutputFileSystem.js @@ -0,0 +1,22 @@ +/* + 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 mkdirp = require("mkdirp"); + +class NodeOutputFileSystem { + constructor() { + this.mkdirp = mkdirp; + this.mkdir = fs.mkdir.bind(fs); + this.rmdir = fs.rmdir.bind(fs); + this.unlink = fs.unlink.bind(fs); + this.writeFile = fs.writeFile.bind(fs); + this.join = path.join.bind(path); + } +} + +module.exports = NodeOutputFileSystem; diff --git a/node_modules/webpack/lib/node/NodeSourcePlugin.js b/node_modules/webpack/lib/node/NodeSourcePlugin.js new file mode 100644 index 0000000..081e1a6 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeSourcePlugin.js @@ -0,0 +1,141 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const AliasPlugin = require("enhanced-resolve/lib/AliasPlugin"); +const ParserHelpers = require("../ParserHelpers"); +const nodeLibsBrowser = require("node-libs-browser"); + +module.exports = class NodeSourcePlugin { + constructor(options) { + this.options = options; + } + apply(compiler) { + const options = this.options; + if (options === false) { + // allow single kill switch to turn off this plugin + return; + } + + const getPathToModule = (module, type) => { + if (type === true || (type === undefined && nodeLibsBrowser[module])) { + if (!nodeLibsBrowser[module]) { + throw new Error( + `No browser version for node.js core module ${module} available` + ); + } + return nodeLibsBrowser[module]; + } else if (type === "mock") { + return require.resolve(`node-libs-browser/mock/${module}`); + } else if (type === "empty") { + return require.resolve("node-libs-browser/mock/empty"); + } else { + return module; + } + }; + + const addExpression = (parser, name, module, type, suffix) => { + suffix = suffix || ""; + parser.hooks.expression.for(name).tap("NodeSourcePlugin", () => { + if ( + parser.state.module && + parser.state.module.resource === getPathToModule(module, type) + ) + return; + const mockModule = ParserHelpers.requireFileAsExpression( + parser.state.module.context, + getPathToModule(module, type) + ); + return ParserHelpers.addParsedVariableToModule( + parser, + name, + mockModule + suffix + ); + }); + }; + + compiler.hooks.compilation.tap( + "NodeSourcePlugin", + (compilation, { normalModuleFactory }) => { + const handler = (parser, parserOptions) => { + if (parserOptions.node === false) return; + + let localOptions = options; + if (parserOptions.node) { + localOptions = Object.assign({}, localOptions, parserOptions.node); + } + if (localOptions.global) { + parser.hooks.expression + .for("global") + .tap("NodeSourcePlugin", () => { + const retrieveGlobalModule = ParserHelpers.requireFileAsExpression( + parser.state.module.context, + require.resolve("../../buildin/global") + ); + return ParserHelpers.addParsedVariableToModule( + parser, + "global", + retrieveGlobalModule + ); + }); + } + if (localOptions.process) { + const processType = localOptions.process; + addExpression(parser, "process", "process", processType); + } + if (localOptions.console) { + const consoleType = localOptions.console; + addExpression(parser, "console", "console", consoleType); + } + const bufferType = localOptions.Buffer; + if (bufferType) { + addExpression(parser, "Buffer", "buffer", bufferType, ".Buffer"); + } + if (localOptions.setImmediate) { + const setImmediateType = localOptions.setImmediate; + addExpression( + parser, + "setImmediate", + "timers", + setImmediateType, + ".setImmediate" + ); + addExpression( + parser, + "clearImmediate", + "timers", + setImmediateType, + ".clearImmediate" + ); + } + }; + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("NodeSourcePlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("NodeSourcePlugin", handler); + } + ); + compiler.hooks.afterResolvers.tap("NodeSourcePlugin", compiler => { + for (const lib of Object.keys(nodeLibsBrowser)) { + if (options[lib] !== false) { + compiler.resolverFactory.hooks.resolver + .for("normal") + .tap("NodeSourcePlugin", resolver => { + new AliasPlugin( + "described-resolve", + { + name: lib, + onlyModule: true, + alias: getPathToModule(lib, options[lib]) + }, + "resolve" + ).apply(resolver); + }); + } + } + }); + } +}; diff --git a/node_modules/webpack/lib/node/NodeTargetPlugin.js b/node_modules/webpack/lib/node/NodeTargetPlugin.js new file mode 100644 index 0000000..1ac5d8a --- /dev/null +++ b/node_modules/webpack/lib/node/NodeTargetPlugin.js @@ -0,0 +1,19 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const ExternalsPlugin = require("../ExternalsPlugin"); + +const builtins = + // eslint-disable-next-line node/no-unsupported-features/node-builtins,node/no-deprecated-api + require("module").builtinModules || Object.keys(process.binding("natives")); + +class NodeTargetPlugin { + apply(compiler) { + new ExternalsPlugin("commonjs", builtins).apply(compiler); + } +} + +module.exports = NodeTargetPlugin; diff --git a/node_modules/webpack/lib/node/NodeTemplatePlugin.js b/node_modules/webpack/lib/node/NodeTemplatePlugin.js new file mode 100644 index 0000000..cdb1076 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeTemplatePlugin.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const NodeMainTemplatePlugin = require("./NodeMainTemplatePlugin"); +const NodeChunkTemplatePlugin = require("./NodeChunkTemplatePlugin"); +const NodeHotUpdateChunkTemplatePlugin = require("./NodeHotUpdateChunkTemplatePlugin"); + +class NodeTemplatePlugin { + constructor(options) { + options = options || {}; + this.asyncChunkLoading = options.asyncChunkLoading; + } + + apply(compiler) { + compiler.hooks.thisCompilation.tap("NodeTemplatePlugin", compilation => { + new NodeMainTemplatePlugin(this.asyncChunkLoading).apply( + compilation.mainTemplate + ); + new NodeChunkTemplatePlugin().apply(compilation.chunkTemplate); + new NodeHotUpdateChunkTemplatePlugin().apply( + compilation.hotUpdateChunkTemplate + ); + }); + } +} + +module.exports = NodeTemplatePlugin; diff --git a/node_modules/webpack/lib/node/NodeWatchFileSystem.js b/node_modules/webpack/lib/node/NodeWatchFileSystem.js new file mode 100644 index 0000000..235e0f0 --- /dev/null +++ b/node_modules/webpack/lib/node/NodeWatchFileSystem.js @@ -0,0 +1,109 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Watchpack = require("watchpack"); +const objectToMap = require("../util/objectToMap"); + +class NodeWatchFileSystem { + constructor(inputFileSystem) { + this.inputFileSystem = inputFileSystem; + this.watcherOptions = { + aggregateTimeout: 0 + }; + this.watcher = new Watchpack(this.watcherOptions); + } + + watch(files, dirs, missing, startTime, options, callback, callbackUndelayed) { + if (!Array.isArray(files)) { + throw new Error("Invalid arguments: 'files'"); + } + if (!Array.isArray(dirs)) { + throw new Error("Invalid arguments: 'dirs'"); + } + if (!Array.isArray(missing)) { + throw new Error("Invalid arguments: 'missing'"); + } + if (typeof callback !== "function") { + throw new Error("Invalid arguments: 'callback'"); + } + if (typeof startTime !== "number" && startTime) { + throw new Error("Invalid arguments: 'startTime'"); + } + if (typeof options !== "object") { + throw new Error("Invalid arguments: 'options'"); + } + if (typeof callbackUndelayed !== "function" && callbackUndelayed) { + throw new Error("Invalid arguments: 'callbackUndelayed'"); + } + const oldWatcher = this.watcher; + this.watcher = new Watchpack(options); + + if (callbackUndelayed) { + this.watcher.once("change", callbackUndelayed); + } + const cachedFiles = files; + const cachedDirs = dirs; + this.watcher.once("aggregated", (changes, removals) => { + changes = changes.concat(removals); + if (this.inputFileSystem && this.inputFileSystem.purge) { + this.inputFileSystem.purge(changes); + } + const times = objectToMap(this.watcher.getTimes()); + files = new Set(files); + dirs = new Set(dirs); + missing = new Set(missing); + removals = new Set(removals.filter(file => files.has(file))); + callback( + null, + changes.filter(file => files.has(file)).sort(), + changes.filter(file => dirs.has(file)).sort(), + changes.filter(file => missing.has(file)).sort(), + times, + times, + removals + ); + }); + + this.watcher.watch( + cachedFiles.concat(missing), + cachedDirs.concat(missing), + startTime + ); + + if (oldWatcher) { + oldWatcher.close(); + } + return { + close: () => { + if (this.watcher) { + this.watcher.close(); + this.watcher = null; + } + }, + pause: () => { + if (this.watcher) { + this.watcher.pause(); + } + }, + getFileTimestamps: () => { + if (this.watcher) { + return objectToMap(this.watcher.getTimes()); + } else { + return new Map(); + } + }, + getContextTimestamps: () => { + if (this.watcher) { + return objectToMap(this.watcher.getTimes()); + } else { + return new Map(); + } + } + }; + } +} + +module.exports = NodeWatchFileSystem; diff --git a/node_modules/webpack/lib/node/ReadFileCompileWasmTemplatePlugin.js b/node_modules/webpack/lib/node/ReadFileCompileWasmTemplatePlugin.js new file mode 100644 index 0000000..a7566b8 --- /dev/null +++ b/node_modules/webpack/lib/node/ReadFileCompileWasmTemplatePlugin.js @@ -0,0 +1,61 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("../Template"); +const WasmMainTemplatePlugin = require("../wasm/WasmMainTemplatePlugin"); + +class ReadFileCompileWasmTemplatePlugin { + constructor(options) { + this.options = options || {}; + } + + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "ReadFileCompileWasmTemplatePlugin", + compilation => { + const generateLoadBinaryCode = path => + Template.asString([ + "new Promise(function (resolve, reject) {", + Template.indent([ + "var { readFile } = require('fs');", + "var { join } = require('path');", + "", + "try {", + Template.indent([ + `readFile(join(__dirname, ${path}), function(err, buffer){`, + Template.indent([ + "if (err) return reject(err);", + "", + "// Fake fetch response", + "resolve({", + Template.indent([ + "arrayBuffer() { return Promise.resolve(buffer); }" + ]), + "});" + ]), + "});" + ]), + "} catch (err) { reject(err); }" + ]), + "})" + ]); + + const plugin = new WasmMainTemplatePlugin( + Object.assign( + { + generateLoadBinaryCode, + supportsStreaming: false + }, + this.options + ) + ); + plugin.apply(compilation.mainTemplate); + } + ); + } +} + +module.exports = ReadFileCompileWasmTemplatePlugin; diff --git a/node_modules/webpack/lib/node/nodeConsole.js b/node_modules/webpack/lib/node/nodeConsole.js new file mode 100644 index 0000000..32a8099 --- /dev/null +++ b/node_modules/webpack/lib/node/nodeConsole.js @@ -0,0 +1,135 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const truncateArgs = require("../logging/truncateArgs"); +const util = require("util"); + +const tty = process.stderr.isTTY && process.env.TERM !== "dumb"; + +let currentStatusMessage = undefined; +let hasStatusMessage = false; +let currentIndent = ""; +let currentCollapsed = 0; + +const indent = (str, prefix, colorPrefix, colorSuffix) => { + if (str === "") return str; + prefix = currentIndent + prefix; + if (tty) { + return ( + prefix + + colorPrefix + + str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) + + colorSuffix + ); + } else { + return prefix + str.replace(/\n/g, "\n" + prefix); + } +}; + +const clearStatusMessage = () => { + if (hasStatusMessage) { + process.stderr.write("\x1b[2K\r"); + hasStatusMessage = false; + } +}; + +const writeStatusMessage = () => { + if (!currentStatusMessage) return; + const l = process.stderr.columns; + const args = l + ? truncateArgs(currentStatusMessage, l - 1) + : currentStatusMessage; + const str = args.join(" "); + const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`; + process.stderr.write(`\x1b[2K\r${coloredStr}`); + hasStatusMessage = true; +}; + +const writeColored = (prefix, colorPrefix, colorSuffix) => { + return (...args) => { + if (currentCollapsed > 0) return; + clearStatusMessage(); + // @ts-ignore + const str = indent(util.format(...args), prefix, colorPrefix, colorSuffix); + process.stderr.write(str + "\n"); + writeStatusMessage(); + }; +}; + +const writeGroupMessage = writeColored( + "<-> ", + "\u001b[1m\u001b[36m", + "\u001b[39m\u001b[22m" +); + +const writeGroupCollapsedMessage = writeColored( + "<+> ", + "\u001b[1m\u001b[36m", + "\u001b[39m\u001b[22m" +); + +module.exports = { + log: writeColored(" ", "\u001b[1m", "\u001b[22m"), + debug: writeColored(" ", "", ""), + trace: writeColored(" ", "", ""), + info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"), + warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"), + error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"), + logTime: writeColored("<t> ", "\u001b[1m\u001b[35m", "\u001b[39m\u001b[22m"), + group: (...args) => { + writeGroupMessage(...args); + if (currentCollapsed > 0) { + currentCollapsed++; + } else { + currentIndent += " "; + } + }, + groupCollapsed: (...args) => { + writeGroupCollapsedMessage(...args); + currentCollapsed++; + }, + groupEnd: () => { + if (currentCollapsed > 0) currentCollapsed--; + else if (currentIndent.length >= 2) + currentIndent = currentIndent.slice(0, currentIndent.length - 2); + }, + // eslint-disable-next-line node/no-unsupported-features/node-builtins + profile: console.profile && (name => console.profile(name)), + // eslint-disable-next-line node/no-unsupported-features/node-builtins + profileEnd: console.profileEnd && (name => console.profileEnd(name)), + clear: + tty && + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.clear && + (() => { + clearStatusMessage(); + // eslint-disable-next-line node/no-unsupported-features/node-builtins + console.clear(); + writeStatusMessage(); + }), + status: tty + ? (name, ...args) => { + args = args.filter(Boolean); + if (name === undefined && args.length === 0) { + clearStatusMessage(); + currentStatusMessage = undefined; + } else if ( + typeof name === "string" && + name.startsWith("[webpack.Progress] ") + ) { + currentStatusMessage = [name.slice(19), ...args]; + writeStatusMessage(); + } else if (name === "[webpack.Progress]") { + currentStatusMessage = [...args]; + writeStatusMessage(); + } else { + currentStatusMessage = [name, ...args]; + writeStatusMessage(); + } + } + : writeColored("<s> ", "", "") +}; diff --git a/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js new file mode 100644 index 0000000..e3a4c37 --- /dev/null +++ b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js @@ -0,0 +1,87 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class AggressiveMergingPlugin { + constructor(options) { + if ( + (options !== undefined && typeof options !== "object") || + Array.isArray(options) + ) { + throw new Error( + "Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/" + ); + } + this.options = options || {}; + } + + apply(compiler) { + const options = this.options; + const minSizeReduce = options.minSizeReduce || 1.5; + + compiler.hooks.thisCompilation.tap( + "AggressiveMergingPlugin", + compilation => { + compilation.hooks.optimizeChunksAdvanced.tap( + "AggressiveMergingPlugin", + chunks => { + let combinations = []; + chunks.forEach((a, idx) => { + if (a.canBeInitial()) return; + for (let i = 0; i < idx; i++) { + const b = chunks[i]; + if (b.canBeInitial()) continue; + combinations.push({ + a, + b, + improvement: undefined + }); + } + }); + + for (const pair of combinations) { + const a = pair.b.size({ + chunkOverhead: 0 + }); + const b = pair.a.size({ + chunkOverhead: 0 + }); + const ab = pair.b.integratedSize(pair.a, { + chunkOverhead: 0 + }); + let newSize; + if (ab === false) { + pair.improvement = false; + return; + } else { + newSize = ab; + } + + pair.improvement = (a + b) / newSize; + } + combinations = combinations.filter(pair => { + return pair.improvement !== false; + }); + combinations.sort((a, b) => { + return b.improvement - a.improvement; + }); + + const pair = combinations[0]; + + if (!pair) return; + if (pair.improvement < minSizeReduce) return; + + if (pair.b.integrate(pair.a, "aggressive-merge")) { + chunks.splice(chunks.indexOf(pair.a), 1); + return true; + } + } + ); + } + ); + } +} + +module.exports = AggressiveMergingPlugin; diff --git a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js new file mode 100644 index 0000000..3843878 --- /dev/null +++ b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js @@ -0,0 +1,294 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const identifierUtils = require("../util/identifier"); +const { intersect } = require("../util/SetHelpers"); +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"); + +/** @typedef {import("../../declarations/plugins/optimize/AggressiveSplittingPlugin").AggressiveSplittingPluginOptions} AggressiveSplittingPluginOptions */ + +const moveModuleBetween = (oldChunk, newChunk) => { + return module => { + oldChunk.moveModule(module, newChunk); + }; +}; + +const isNotAEntryModule = entryModule => { + return module => { + return entryModule !== module; + }; +}; + +class AggressiveSplittingPlugin { + /** + * @param {AggressiveSplittingPluginOptions=} options options object + */ + constructor(options) { + if (!options) options = {}; + + validateOptions(schema, options, "Aggressive Splitting Plugin"); + + this.options = options; + if (typeof this.options.minSize !== "number") { + this.options.minSize = 30 * 1024; + } + if (typeof this.options.maxSize !== "number") { + this.options.maxSize = 50 * 1024; + } + if (typeof this.options.chunkOverhead !== "number") { + this.options.chunkOverhead = 0; + } + if (typeof this.options.entryChunkMultiplicator !== "number") { + this.options.entryChunkMultiplicator = 1; + } + } + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "AggressiveSplittingPlugin", + compilation => { + let needAdditionalSeal = false; + let newSplits; + let fromAggressiveSplittingSet; + let chunkSplitDataMap; + compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => { + newSplits = []; + fromAggressiveSplittingSet = new Set(); + chunkSplitDataMap = new Map(); + }); + compilation.hooks.optimizeChunksAdvanced.tap( + "AggressiveSplittingPlugin", + chunks => { + // Precompute stuff + const nameToModuleMap = new Map(); + const moduleToNameMap = new Map(); + for (const m of compilation.modules) { + const name = identifierUtils.makePathsRelative( + compiler.context, + m.identifier(), + compilation.cache + ); + nameToModuleMap.set(name, m); + moduleToNameMap.set(m, name); + } + + // Check used chunk ids + const usedIds = new Set(); + for (const chunk of chunks) { + usedIds.add(chunk.id); + } + + const recordedSplits = + (compilation.records && compilation.records.aggressiveSplits) || + []; + const usedSplits = newSplits + ? recordedSplits.concat(newSplits) + : recordedSplits; + + const minSize = this.options.minSize; + const maxSize = this.options.maxSize; + + const applySplit = splitData => { + // Cannot split if id is already taken + if (splitData.id !== undefined && usedIds.has(splitData.id)) { + return false; + } + + // Get module objects from names + const selectedModules = splitData.modules.map(name => + nameToModuleMap.get(name) + ); + + // Does the modules exist at all? + if (!selectedModules.every(Boolean)) return false; + + // Check if size matches (faster than waiting for hash) + const size = selectedModules.reduce( + (sum, m) => sum + m.size(), + 0 + ); + if (size !== splitData.size) return false; + + // get chunks with all modules + const selectedChunks = intersect( + selectedModules.map(m => new Set(m.chunksIterable)) + ); + + // No relevant chunks found + if (selectedChunks.size === 0) return false; + + // The found chunk is already the split or similar + if ( + selectedChunks.size === 1 && + Array.from(selectedChunks)[0].getNumberOfModules() === + selectedModules.length + ) { + const chunk = Array.from(selectedChunks)[0]; + if (fromAggressiveSplittingSet.has(chunk)) return false; + fromAggressiveSplittingSet.add(chunk); + chunkSplitDataMap.set(chunk, splitData); + return true; + } + + // split the chunk into two parts + const newChunk = compilation.addChunk(); + newChunk.chunkReason = "aggressive splitted"; + for (const chunk of selectedChunks) { + selectedModules.forEach(moveModuleBetween(chunk, newChunk)); + chunk.split(newChunk); + chunk.name = null; + } + fromAggressiveSplittingSet.add(newChunk); + chunkSplitDataMap.set(newChunk, splitData); + + if (splitData.id !== null && splitData.id !== undefined) { + newChunk.id = splitData.id; + } + return true; + }; + + // try to restore to recorded splitting + let changed = false; + for (let j = 0; j < usedSplits.length; j++) { + const splitData = usedSplits[j]; + if (applySplit(splitData)) changed = true; + } + + // for any chunk which isn't splitted yet, split it and create a new entry + // start with the biggest chunk + const sortedChunks = chunks.slice().sort((a, b) => { + const diff1 = b.modulesSize() - a.modulesSize(); + if (diff1) return diff1; + const diff2 = a.getNumberOfModules() - b.getNumberOfModules(); + if (diff2) return diff2; + const modulesA = Array.from(a.modulesIterable); + const modulesB = Array.from(b.modulesIterable); + modulesA.sort(); + modulesB.sort(); + const aI = modulesA[Symbol.iterator](); + const bI = modulesB[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = aI.next(); + const bItem = bI.next(); + if (aItem.done) return 0; + const aModuleIdentifier = aItem.value.identifier(); + const bModuleIdentifier = bItem.value.identifier(); + if (aModuleIdentifier > bModuleIdentifier) return -1; + if (aModuleIdentifier < bModuleIdentifier) return 1; + } + }); + for (const chunk of sortedChunks) { + if (fromAggressiveSplittingSet.has(chunk)) continue; + const size = chunk.modulesSize(); + if (size > maxSize && chunk.getNumberOfModules() > 1) { + const modules = chunk + .getModules() + .filter(isNotAEntryModule(chunk.entryModule)) + .sort((a, b) => { + a = a.identifier(); + b = b.identifier(); + if (a > b) return 1; + if (a < b) return -1; + return 0; + }); + const selectedModules = []; + let selectedModulesSize = 0; + for (let k = 0; k < modules.length; k++) { + const module = modules[k]; + const newSize = selectedModulesSize + module.size(); + if (newSize > maxSize && selectedModulesSize >= minSize) { + break; + } + selectedModulesSize = newSize; + selectedModules.push(module); + } + if (selectedModules.length === 0) continue; + const splitData = { + modules: selectedModules + .map(m => moduleToNameMap.get(m)) + .sort(), + size: selectedModulesSize + }; + + if (applySplit(splitData)) { + newSplits = (newSplits || []).concat(splitData); + changed = true; + } + } + } + if (changed) return true; + } + ); + compilation.hooks.recordHash.tap( + "AggressiveSplittingPlugin", + records => { + // 4. save made splittings to records + const allSplits = new Set(); + const invalidSplits = new Set(); + + // Check if some splittings are invalid + // We remove invalid splittings and try again + for (const chunk of compilation.chunks) { + const splitData = chunkSplitDataMap.get(chunk); + if (splitData !== undefined) { + if (splitData.hash && chunk.hash !== splitData.hash) { + // Split was successful, but hash doesn't equal + // We can throw away the split since it's useless now + invalidSplits.add(splitData); + } + } + } + + if (invalidSplits.size > 0) { + records.aggressiveSplits = records.aggressiveSplits.filter( + splitData => !invalidSplits.has(splitData) + ); + needAdditionalSeal = true; + } else { + // set hash and id values on all (new) splittings + for (const chunk of compilation.chunks) { + const splitData = chunkSplitDataMap.get(chunk); + if (splitData !== undefined) { + splitData.hash = chunk.hash; + splitData.id = chunk.id; + allSplits.add(splitData); + // set flag for stats + chunk.recorded = true; + } + } + + // Also add all unused historial splits (after the used ones) + // They can still be used in some future compilation + const recordedSplits = + compilation.records && compilation.records.aggressiveSplits; + if (recordedSplits) { + for (const splitData of recordedSplits) { + if (!invalidSplits.has(splitData)) allSplits.add(splitData); + } + } + + // record all splits + records.aggressiveSplits = Array.from(allSplits); + + needAdditionalSeal = false; + } + } + ); + compilation.hooks.needAdditionalSeal.tap( + "AggressiveSplittingPlugin", + () => { + if (needAdditionalSeal) { + needAdditionalSeal = false; + return true; + } + } + ); + } + ); + } +} +module.exports = AggressiveSplittingPlugin; diff --git a/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js new file mode 100644 index 0000000..9e3abd3 --- /dev/null +++ b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js @@ -0,0 +1,66 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const sortByIndex = (a, b) => { + return a.index - b.index; +}; + +const sortByIndex2 = (a, b) => { + return a.index2 - b.index2; +}; + +class ChunkModuleIdRangePlugin { + constructor(options) { + this.options = options; + } + + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", compilation => { + compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", modules => { + const chunk = compilation.chunks.find( + chunk => chunk.name === options.name + ); + if (!chunk) { + throw new Error( + `ChunkModuleIdRangePlugin: Chunk with name '${options.name}"' was not found` + ); + } + + let chunkModules; + if (options.order) { + chunkModules = Array.from(chunk.modulesIterable); + switch (options.order) { + case "index": + chunkModules.sort(sortByIndex); + break; + case "index2": + chunkModules.sort(sortByIndex2); + break; + default: + throw new Error( + "ChunkModuleIdRangePlugin: unexpected value of order" + ); + } + } else { + chunkModules = modules.filter(m => { + return m.chunksIterable.has(chunk); + }); + } + + let currentId = options.start || 0; + for (let i = 0; i < chunkModules.length; i++) { + const m = chunkModules[i]; + if (m.id === null) { + m.id = currentId++; + } + if (options.end && currentId > options.end) break; + } + }); + }); + } +} +module.exports = ChunkModuleIdRangePlugin; diff --git a/node_modules/webpack/lib/optimize/ConcatenatedModule.js b/node_modules/webpack/lib/optimize/ConcatenatedModule.js new file mode 100644 index 0000000..df4d216 --- /dev/null +++ b/node_modules/webpack/lib/optimize/ConcatenatedModule.js @@ -0,0 +1,1477 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Module = require("../Module"); +const Template = require("../Template"); +const Parser = require("../Parser"); +const eslintScope = require("eslint-scope"); +const { ConcatSource, ReplaceSource } = require("webpack-sources"); +const DependencyReference = require("../dependencies/DependencyReference"); +const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); +const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency"); +const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); +const HarmonyExportSpecifierDependency = require("../dependencies/HarmonyExportSpecifierDependency"); +const HarmonyExportExpressionDependency = require("../dependencies/HarmonyExportExpressionDependency"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); +const createHash = require("../util/createHash"); + +/** @typedef {import("../Dependency")} Dependency */ +/** @typedef {import("../Compilation")} Compilation */ +/** @typedef {import("../util/createHash").Hash} Hash */ +/** @typedef {import("../RequestShortener")} RequestShortener */ + +const joinIterableWithComma = iterable => { + // This is more performant than Array.from().join(", ") + // as it doesn't create an array + let str = ""; + let first = true; + for (const item of iterable) { + if (first) { + first = false; + } else { + str += ", "; + } + str += item; + } + return str; +}; + +/** + * @typedef {Object} ConcatenationEntry + * @property {"concatenated" | "external"} type + * @property {Module} module + */ + +const ensureNsObjSource = ( + info, + moduleToInfoMap, + requestShortener, + strictHarmonyModule +) => { + if (!info.hasNamespaceObject) { + info.hasNamespaceObject = true; + const name = info.exportMap.get(true); + const nsObj = [`var ${name} = {};`, `__webpack_require__.r(${name});`]; + for (const exportName of info.module.buildMeta.providedExports) { + const finalName = getFinalName( + info, + exportName, + moduleToInfoMap, + requestShortener, + false, + strictHarmonyModule + ); + nsObj.push( + `__webpack_require__.d(${name}, ${JSON.stringify( + exportName + )}, function() { return ${finalName}; });` + ); + } + info.namespaceObjectSource = nsObj.join("\n") + "\n"; + } +}; + +const getExternalImport = ( + importedModule, + info, + exportName, + asCall, + strictHarmonyModule +) => { + const used = importedModule.isUsed(exportName); + if (!used) return "/* unused reexport */undefined"; + const comment = + used !== exportName ? ` ${Template.toNormalComment(exportName)}` : ""; + switch (importedModule.buildMeta.exportsType) { + case "named": + if (exportName === "default") { + return info.name; + } else if (exportName === true) { + info.interopNamespaceObjectUsed = true; + return info.interopNamespaceObjectName; + } else { + break; + } + case "namespace": + if (exportName === true) { + return info.name; + } else { + break; + } + default: + if (strictHarmonyModule) { + if (exportName === "default") { + return info.name; + } else if (exportName === true) { + info.interopNamespaceObjectUsed = true; + return info.interopNamespaceObjectName; + } else { + return "/* non-default import from non-esm module */undefined"; + } + } else { + if (exportName === "default") { + info.interopDefaultAccessUsed = true; + return asCall + ? `${info.interopDefaultAccessName}()` + : `${info.interopDefaultAccessName}.a`; + } else if (exportName === true) { + return info.name; + } else { + break; + } + } + } + const reference = `${info.name}[${JSON.stringify(used)}${comment}]`; + if (asCall) return `Object(${reference})`; + return reference; +}; + +const getFinalName = ( + info, + exportName, + moduleToInfoMap, + requestShortener, + asCall, + strictHarmonyModule, + alreadyVisited = new Set() +) => { + switch (info.type) { + case "concatenated": { + const directExport = info.exportMap.get(exportName); + if (directExport) { + if (exportName === true) { + ensureNsObjSource( + info, + moduleToInfoMap, + requestShortener, + strictHarmonyModule + ); + } else if (!info.module.isUsed(exportName)) { + return "/* unused export */ undefined"; + } + if (info.globalExports.has(directExport)) { + return directExport; + } + const name = info.internalNames.get(directExport); + if (!name) { + throw new Error( + `The export "${directExport}" in "${info.module.readableIdentifier( + requestShortener + )}" has no internal name` + ); + } + return name; + } + const reexport = info.reexportMap.get(exportName); + if (reexport) { + if (alreadyVisited.has(reexport)) { + throw new Error( + `Circular reexports ${Array.from( + alreadyVisited, + e => + `"${e.module.readableIdentifier(requestShortener)}".${ + e.exportName + }` + ).join( + " --> " + )} -(circular)-> "${reexport.module.readableIdentifier( + requestShortener + )}".${reexport.exportName}` + ); + } + alreadyVisited.add(reexport); + const refInfo = moduleToInfoMap.get(reexport.module); + if (refInfo) { + // module is in the concatenation + return getFinalName( + refInfo, + reexport.exportName, + moduleToInfoMap, + requestShortener, + asCall, + strictHarmonyModule, + alreadyVisited + ); + } + } + const problem = + `Cannot get final name for export "${exportName}" in "${info.module.readableIdentifier( + requestShortener + )}"` + + ` (known exports: ${Array.from(info.exportMap.keys()) + .filter(name => name !== true) + .join(" ")}, ` + + `known reexports: ${Array.from(info.reexportMap.keys()).join(" ")})`; + return `${Template.toNormalComment(problem)} undefined`; + } + case "external": { + const importedModule = info.module; + return getExternalImport( + importedModule, + info, + exportName, + asCall, + strictHarmonyModule + ); + } + } +}; + +const addScopeSymbols1 = (s, nameSet, scopeSet) => { + let scope = s; + while (scope) { + if (scopeSet.has(scope)) break; + scopeSet.add(scope); + for (const variable of scope.variables) { + nameSet.add(variable.name); + } + scope = scope.upper; + } +}; + +const addScopeSymbols2 = (s, nameSet, scopeSet1, scopeSet2) => { + let scope = s; + while (scope) { + if (scopeSet1.has(scope)) break; + if (scopeSet2.has(scope)) break; + scopeSet1.add(scope); + for (const variable of scope.variables) { + nameSet.add(variable.name); + } + scope = scope.upper; + } +}; + +const getAllReferences = variable => { + let set = variable.references; + // Look for inner scope variables too (like in class Foo { t() { Foo } }) + const identifiers = new Set(variable.identifiers); + for (const scope of variable.scope.childScopes) { + for (const innerVar of scope.variables) { + if (innerVar.identifiers.some(id => identifiers.has(id))) { + set = set.concat(innerVar.references); + break; + } + } + } + return set; +}; + +const getPathInAst = (ast, node) => { + if (ast === node) { + return []; + } + + const nr = node.range; + + const enterNode = n => { + if (!n) return undefined; + const r = n.range; + if (r) { + if (r[0] <= nr[0] && r[1] >= nr[1]) { + const path = getPathInAst(n, node); + if (path) { + path.push(n); + return path; + } + } + } + return undefined; + }; + + var i; + if (Array.isArray(ast)) { + for (i = 0; i < ast.length; i++) { + const enterResult = enterNode(ast[i]); + if (enterResult !== undefined) return enterResult; + } + } else if (ast && typeof ast === "object") { + const keys = Object.keys(ast); + for (i = 0; i < keys.length; i++) { + const value = ast[keys[i]]; + if (Array.isArray(value)) { + const pathResult = getPathInAst(value, node); + if (pathResult !== undefined) return pathResult; + } else if (value && typeof value === "object") { + const enterResult = enterNode(value); + if (enterResult !== undefined) return enterResult; + } + } + } +}; + +const getHarmonyExportImportedSpecifierDependencyExports = dep => { + const importModule = dep._module; + if (!importModule) return []; + if (dep._id) { + // export { named } from "module" + return [ + { + name: dep.name, + id: dep._id, + module: importModule + } + ]; + } + if (dep.name) { + // export * as abc from "module" + return [ + { + name: dep.name, + id: true, + module: importModule + } + ]; + } + // export * from "module" + return importModule.buildMeta.providedExports + .filter(exp => exp !== "default" && !dep.activeExports.has(exp)) + .map(exp => { + return { + name: exp, + id: exp, + module: importModule + }; + }); +}; + +class ConcatenatedModule extends Module { + constructor(rootModule, modules, concatenationList) { + super("javascript/esm", null); + super.setChunks(rootModule._chunks); + + // Info from Factory + this.rootModule = rootModule; + this.factoryMeta = rootModule.factoryMeta; + + // Info from Compilation + this.index = rootModule.index; + this.index2 = rootModule.index2; + this.depth = rootModule.depth; + + // Info from Optimization + this.used = rootModule.used; + this.usedExports = rootModule.usedExports; + + // Info from Build + this.buildInfo = { + strict: true, + cacheable: modules.every(m => m.buildInfo.cacheable), + moduleArgument: rootModule.buildInfo.moduleArgument, + exportsArgument: rootModule.buildInfo.exportsArgument, + fileDependencies: new Set(), + contextDependencies: new Set(), + assets: undefined + }; + this.built = modules.some(m => m.built); + this.buildMeta = rootModule.buildMeta; + + // Caching + this._numberOfConcatenatedModules = modules.length; + + // Graph + const modulesSet = new Set(modules); + this.reasons = rootModule.reasons.filter( + reason => + !(reason.dependency instanceof HarmonyImportDependency) || + !modulesSet.has(reason.module) + ); + + this.dependencies = []; + this.blocks = []; + + this.warnings = []; + this.errors = []; + this._orderedConcatenationList = + concatenationList || + ConcatenatedModule.createConcatenationList(rootModule, modulesSet, null); + for (const info of this._orderedConcatenationList) { + if (info.type === "concatenated") { + const m = info.module; + + // populate dependencies + for (const d of m.dependencies.filter( + dep => + !(dep instanceof HarmonyImportDependency) || + !modulesSet.has(dep._module) + )) { + this.dependencies.push(d); + } + // populate blocks + for (const d of m.blocks) { + this.blocks.push(d); + } + // populate file dependencies + if (m.buildInfo.fileDependencies) { + for (const file of m.buildInfo.fileDependencies) { + this.buildInfo.fileDependencies.add(file); + } + } + // populate context dependencies + if (m.buildInfo.contextDependencies) { + for (const context of m.buildInfo.contextDependencies) { + this.buildInfo.contextDependencies.add(context); + } + } + // populate warnings + for (const warning of m.warnings) { + this.warnings.push(warning); + } + // populate errors + for (const error of m.errors) { + this.errors.push(error); + } + + if (m.buildInfo.assets) { + if (this.buildInfo.assets === undefined) { + this.buildInfo.assets = Object.create(null); + } + Object.assign(this.buildInfo.assets, m.buildInfo.assets); + } + if (m.buildInfo.assetsInfo) { + if (this.buildInfo.assetsInfo === undefined) { + this.buildInfo.assetsInfo = new Map(); + } + for (const [key, value] of m.buildInfo.assetsInfo) { + this.buildInfo.assetsInfo.set(key, value); + } + } + } + } + this._identifier = this._createIdentifier(); + } + + get modules() { + return this._orderedConcatenationList + .filter(info => info.type === "concatenated") + .map(info => info.module); + } + + identifier() { + return this._identifier; + } + + readableIdentifier(requestShortener) { + return ( + this.rootModule.readableIdentifier(requestShortener) + + ` + ${this._numberOfConcatenatedModules - 1} modules` + ); + } + + libIdent(options) { + return this.rootModule.libIdent(options); + } + + nameForCondition() { + return this.rootModule.nameForCondition(); + } + + build(options, compilation, resolver, fs, callback) { + throw new Error("Cannot build this module. It should be already built."); + } + + size() { + // Guess size from embedded modules + return this._orderedConcatenationList.reduce((sum, info) => { + switch (info.type) { + case "concatenated": + return sum + info.module.size(); + case "external": + return sum + 5; + } + return sum; + }, 0); + } + + /** + * @param {Module} rootModule the root of the concatenation + * @param {Set<Module>} modulesSet a set of modules which should be concatenated + * @param {Compilation} compilation the compilation context + * @returns {ConcatenationEntry[]} concatenation list + */ + static createConcatenationList(rootModule, modulesSet, compilation) { + const list = []; + const set = new Set(); + + /** + * @param {Module} module a module + * @returns {(function(): Module)[]} imported modules in order + */ + const getConcatenatedImports = module => { + /** @type {WeakMap<DependencyReference, Dependency>} */ + const map = new WeakMap(); + const references = module.dependencies + .filter(dep => dep instanceof HarmonyImportDependency) + .map(dep => { + const ref = compilation.getDependencyReference(module, dep); + if (ref) map.set(ref, dep); + return ref; + }) + .filter(ref => ref); + DependencyReference.sort(references); + // TODO webpack 5: remove this hack, see also DependencyReference + return references.map(ref => { + const dep = map.get(ref); + return () => compilation.getDependencyReference(module, dep).module; + }); + }; + + const enterModule = getModule => { + const module = getModule(); + if (!module) return; + if (set.has(module)) return; + set.add(module); + if (modulesSet.has(module)) { + const imports = getConcatenatedImports(module); + imports.forEach(enterModule); + list.push({ + type: "concatenated", + module + }); + } else { + list.push({ + type: "external", + get module() { + // We need to use a getter here, because the module in the dependency + // could be replaced by some other process (i. e. also replaced with a + // concatenated module) + return getModule(); + } + }); + } + }; + + enterModule(() => rootModule); + + return list; + } + + _createIdentifier() { + let orderedConcatenationListIdentifiers = ""; + for (let i = 0; i < this._orderedConcatenationList.length; i++) { + if (this._orderedConcatenationList[i].type === "concatenated") { + orderedConcatenationListIdentifiers += this._orderedConcatenationList[ + i + ].module.identifier(); + orderedConcatenationListIdentifiers += " "; + } + } + const hash = createHash("md4"); + hash.update(orderedConcatenationListIdentifiers); + return this.rootModule.identifier() + " " + hash.digest("hex"); + } + + source(dependencyTemplates, runtimeTemplate) { + const requestShortener = runtimeTemplate.requestShortener; + // Metainfo for each module + const modulesWithInfo = this._orderedConcatenationList.map((info, idx) => { + switch (info.type) { + case "concatenated": { + const exportMap = new Map(); + const reexportMap = new Map(); + for (const dep of info.module.dependencies) { + if (dep instanceof HarmonyExportSpecifierDependency) { + if (!exportMap.has(dep.name)) { + exportMap.set(dep.name, dep.id); + } + } else if (dep instanceof HarmonyExportExpressionDependency) { + if (!exportMap.has("default")) { + exportMap.set("default", "__WEBPACK_MODULE_DEFAULT_EXPORT__"); + } + } else if ( + dep instanceof HarmonyExportImportedSpecifierDependency + ) { + const exportName = dep.name; + const importName = dep._id; + const importedModule = dep._module; + if (exportName && importName) { + if (!reexportMap.has(exportName)) { + reexportMap.set(exportName, { + module: importedModule, + exportName: importName, + dependency: dep + }); + } + } else if (exportName) { + if (!reexportMap.has(exportName)) { + reexportMap.set(exportName, { + module: importedModule, + exportName: true, + dependency: dep + }); + } + } else if (importedModule) { + for (const name of importedModule.buildMeta.providedExports) { + if (dep.activeExports.has(name) || name === "default") { + continue; + } + if (!reexportMap.has(name)) { + reexportMap.set(name, { + module: importedModule, + exportName: name, + dependency: dep + }); + } + } + } + } + } + return { + type: "concatenated", + module: info.module, + index: idx, + ast: undefined, + internalSource: undefined, + source: undefined, + globalScope: undefined, + moduleScope: undefined, + internalNames: new Map(), + globalExports: new Set(), + exportMap: exportMap, + reexportMap: reexportMap, + hasNamespaceObject: false, + namespaceObjectSource: null + }; + } + case "external": + return { + type: "external", + module: info.module, + index: idx, + name: undefined, + interopNamespaceObjectUsed: false, + interopNamespaceObjectName: undefined, + interopDefaultAccessUsed: false, + interopDefaultAccessName: undefined + }; + default: + throw new Error(`Unsupported concatenation entry type ${info.type}`); + } + }); + + // Create mapping from module to info + const moduleToInfoMap = new Map(); + for (const m of modulesWithInfo) { + moduleToInfoMap.set(m.module, m); + } + + // Configure template decorators for dependencies + const innerDependencyTemplates = new Map(dependencyTemplates); + + innerDependencyTemplates.set( + HarmonyImportSpecifierDependency, + new HarmonyImportSpecifierDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyImportSpecifierDependency), + moduleToInfoMap + ) + ); + innerDependencyTemplates.set( + HarmonyImportSideEffectDependency, + new HarmonyImportSideEffectDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyImportSideEffectDependency), + moduleToInfoMap + ) + ); + innerDependencyTemplates.set( + HarmonyExportSpecifierDependency, + new NullTemplate() + ); + innerDependencyTemplates.set( + HarmonyExportExpressionDependency, + new HarmonyExportExpressionDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyExportExpressionDependency), + this.rootModule + ) + ); + innerDependencyTemplates.set( + HarmonyExportImportedSpecifierDependency, + new NullTemplate() + ); + innerDependencyTemplates.set( + HarmonyCompatibilityDependency, + new NullTemplate() + ); + + // Must use full identifier in our cache here to ensure that the source + // is updated should our dependencies list change. + // TODO webpack 5 refactor + innerDependencyTemplates.set( + "hash", + innerDependencyTemplates.get("hash") + this.identifier() + ); + + // Generate source code and analyse scopes + // Prepare a ReplaceSource for the final source + for (const info of modulesWithInfo) { + if (info.type === "concatenated") { + const m = info.module; + const source = m.source(innerDependencyTemplates, runtimeTemplate); + const code = source.source(); + let ast; + try { + ast = Parser.parse(code, { + sourceType: "module" + }); + } catch (err) { + if ( + err.loc && + typeof err.loc === "object" && + typeof err.loc.line === "number" + ) { + const lineNumber = err.loc.line; + const lines = code.split("\n"); + err.message += + "\n| " + + lines + .slice(Math.max(0, lineNumber - 3), lineNumber + 2) + .join("\n| "); + } + throw err; + } + const scopeManager = eslintScope.analyze(ast, { + ecmaVersion: 6, + sourceType: "module", + optimistic: true, + ignoreEval: true, + impliedStrict: true + }); + const globalScope = scopeManager.acquire(ast); + const moduleScope = globalScope.childScopes[0]; + const resultSource = new ReplaceSource(source); + info.ast = ast; + info.internalSource = source; + info.source = resultSource; + info.globalScope = globalScope; + info.moduleScope = moduleScope; + } + } + + // List of all used names to avoid conflicts + const allUsedNames = new Set([ + "__WEBPACK_MODULE_DEFAULT_EXPORT__", // avoid using this internal name + + "abstract", + "arguments", + "async", + "await", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "double", + "else", + "enum", + "eval", + "export", + "extends", + "false", + "final", + "finally", + "float", + "for", + "function", + "goto", + "if", + "implements", + "import", + "in", + "instanceof", + "int", + "interface", + "let", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "true", + "try", + "typeof", + "var", + "void", + "volatile", + "while", + "with", + "yield", + + "module", + "__dirname", + "__filename", + "exports", + + "Array", + "Date", + "eval", + "function", + "hasOwnProperty", + "Infinity", + "isFinite", + "isNaN", + "isPrototypeOf", + "length", + "Math", + "NaN", + "name", + "Number", + "Object", + "prototype", + "String", + "toString", + "undefined", + "valueOf", + + "alert", + "all", + "anchor", + "anchors", + "area", + "assign", + "blur", + "button", + "checkbox", + "clearInterval", + "clearTimeout", + "clientInformation", + "close", + "closed", + "confirm", + "constructor", + "crypto", + "decodeURI", + "decodeURIComponent", + "defaultStatus", + "document", + "element", + "elements", + "embed", + "embeds", + "encodeURI", + "encodeURIComponent", + "escape", + "event", + "fileUpload", + "focus", + "form", + "forms", + "frame", + "innerHeight", + "innerWidth", + "layer", + "layers", + "link", + "location", + "mimeTypes", + "navigate", + "navigator", + "frames", + "frameRate", + "hidden", + "history", + "image", + "images", + "offscreenBuffering", + "open", + "opener", + "option", + "outerHeight", + "outerWidth", + "packages", + "pageXOffset", + "pageYOffset", + "parent", + "parseFloat", + "parseInt", + "password", + "pkcs11", + "plugin", + "prompt", + "propertyIsEnum", + "radio", + "reset", + "screenX", + "screenY", + "scroll", + "secure", + "select", + "self", + "setInterval", + "setTimeout", + "status", + "submit", + "taint", + "text", + "textarea", + "top", + "unescape", + "untaint", + "window", + + "onblur", + "onclick", + "onerror", + "onfocus", + "onkeydown", + "onkeypress", + "onkeyup", + "onmouseover", + "onload", + "onmouseup", + "onmousedown", + "onsubmit" + ]); + + // Set of already checked scopes + const alreadyCheckedScopes = new Set(); + + // get all global names + for (const info of modulesWithInfo) { + const superClassExpressions = []; + + // ignore symbols from moduleScope + if (info.moduleScope) { + alreadyCheckedScopes.add(info.moduleScope); + + // The super class expression in class scopes behaves weird + // We store ranges of all super class expressions to make + // renaming to work correctly + for (const childScope of info.moduleScope.childScopes) { + if (childScope.type !== "class") continue; + if (!childScope.block.superClass) continue; + superClassExpressions.push({ + range: childScope.block.superClass.range, + variables: childScope.variables + }); + } + } + + // add global symbols + if (info.globalScope) { + for (const reference of info.globalScope.through) { + const name = reference.identifier.name; + if ( + /^__WEBPACK_MODULE_REFERENCE__\d+_([\da-f]+|ns)(_call)?(_strict)?__$/.test( + name + ) + ) { + for (const expr of superClassExpressions) { + if ( + expr.range[0] <= reference.identifier.range[0] && + expr.range[1] >= reference.identifier.range[1] + ) { + for (const variable of expr.variables) { + allUsedNames.add(variable.name); + } + } + } + addScopeSymbols1( + reference.from, + allUsedNames, + alreadyCheckedScopes + ); + } else { + allUsedNames.add(name); + } + } + } + + // add exported globals + if (info.type === "concatenated") { + const variables = new Set(); + for (const variable of info.moduleScope.variables) { + variables.add(variable.name); + } + for (const [, variable] of info.exportMap) { + if (!variables.has(variable)) { + info.globalExports.add(variable); + } + } + } + } + + // generate names for symbols + for (const info of modulesWithInfo) { + switch (info.type) { + case "concatenated": { + const namespaceObjectName = this.findNewName( + "namespaceObject", + allUsedNames, + null, + info.module.readableIdentifier(requestShortener) + ); + allUsedNames.add(namespaceObjectName); + info.internalNames.set(namespaceObjectName, namespaceObjectName); + info.exportMap.set(true, namespaceObjectName); + for (const variable of info.moduleScope.variables) { + const name = variable.name; + if (allUsedNames.has(name)) { + const references = getAllReferences(variable); + const symbolsInReferences = new Set(); + const alreadyCheckedInnerScopes = new Set(); + for (const ref of references) { + addScopeSymbols2( + ref.from, + symbolsInReferences, + alreadyCheckedInnerScopes, + alreadyCheckedScopes + ); + } + const newName = this.findNewName( + name, + allUsedNames, + symbolsInReferences, + info.module.readableIdentifier(requestShortener) + ); + allUsedNames.add(newName); + info.internalNames.set(name, newName); + const source = info.source; + const allIdentifiers = new Set( + references.map(r => r.identifier).concat(variable.identifiers) + ); + for (const identifier of allIdentifiers) { + const r = identifier.range; + const path = getPathInAst(info.ast, identifier); + if ( + path && + path.length > 1 && + path[1].type === "Property" && + path[1].shorthand + ) { + source.insert(r[1], `: ${newName}`); + } else { + source.replace(r[0], r[1] - 1, newName); + } + } + } else { + allUsedNames.add(name); + info.internalNames.set(name, name); + } + } + break; + } + case "external": { + const externalName = this.findNewName( + "", + allUsedNames, + null, + info.module.readableIdentifier(requestShortener) + ); + allUsedNames.add(externalName); + info.name = externalName; + if ( + info.module.buildMeta.exportsType === "named" || + !info.module.buildMeta.exportsType + ) { + const externalNameInterop = this.findNewName( + "namespaceObject", + allUsedNames, + null, + info.module.readableIdentifier(requestShortener) + ); + allUsedNames.add(externalNameInterop); + info.interopNamespaceObjectName = externalNameInterop; + } + if (!info.module.buildMeta.exportsType) { + const externalNameInterop = this.findNewName( + "default", + allUsedNames, + null, + info.module.readableIdentifier(requestShortener) + ); + allUsedNames.add(externalNameInterop); + info.interopDefaultAccessName = externalNameInterop; + } + break; + } + } + } + + // Find and replace referenced to modules + for (const info of modulesWithInfo) { + if (info.type === "concatenated") { + for (const reference of info.globalScope.through) { + const name = reference.identifier.name; + const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?(_strict)?__$/.exec( + name + ); + if (match) { + const referencedModule = modulesWithInfo[+match[1]]; + let exportName; + if (match[2] === "ns") { + exportName = true; + } else { + const exportData = match[2]; + exportName = Buffer.from(exportData, "hex").toString("utf-8"); + } + const asCall = !!match[3]; + const strictHarmonyModule = !!match[4]; + const finalName = getFinalName( + referencedModule, + exportName, + moduleToInfoMap, + requestShortener, + asCall, + strictHarmonyModule + ); + const r = reference.identifier.range; + const source = info.source; + source.replace(r[0], r[1] - 1, finalName); + } + } + } + } + + // Map with all root exposed used exports + /** @type {Map<string, function(RequestShortener): string>} */ + const exportsMap = new Map(); + + // Set with all root exposed unused exports + /** @type {Set<string>} */ + const unusedExports = new Set(); + + for (const dep of this.rootModule.dependencies) { + if (dep instanceof HarmonyExportSpecifierDependency) { + const used = this.rootModule.isUsed(dep.name); + if (used) { + const info = moduleToInfoMap.get(this.rootModule); + if (!exportsMap.has(used)) { + exportsMap.set( + used, + () => `/* binding */ ${info.internalNames.get(dep.id)}` + ); + } + } else { + unusedExports.add(dep.name || "namespace"); + } + } else if (dep instanceof HarmonyExportImportedSpecifierDependency) { + const exportDefs = getHarmonyExportImportedSpecifierDependencyExports( + dep + ); + for (const def of exportDefs) { + const info = moduleToInfoMap.get(def.module); + const used = dep.originModule.isUsed(def.name); + if (used) { + if (!exportsMap.has(used)) { + exportsMap.set(used, requestShortener => { + const finalName = getFinalName( + info, + def.id, + moduleToInfoMap, + requestShortener, + false, + this.rootModule.buildMeta.strictHarmonyModule + ); + return `/* reexport */ ${finalName}`; + }); + } + } else { + unusedExports.add(def.name); + } + } + } + } + + const result = new ConcatSource(); + + // add harmony compatibility flag (must be first because of possible circular dependencies) + const usedExports = this.rootModule.usedExports; + if (usedExports === true || usedExports === null) { + result.add(`// ESM COMPAT FLAG\n`); + result.add( + runtimeTemplate.defineEsModuleFlagStatement({ + exportsArgument: this.exportsArgument + }) + ); + } + + // define exports + if (exportsMap.size > 0) { + result.add(`\n// EXPORTS\n`); + for (const [key, value] of exportsMap) { + result.add( + `__webpack_require__.d(${this.exportsArgument}, ${JSON.stringify( + key + )}, function() { return ${value(requestShortener)}; });\n` + ); + } + } + + // list unused exports + if (unusedExports.size > 0) { + result.add( + `\n// UNUSED EXPORTS: ${joinIterableWithComma(unusedExports)}\n` + ); + } + + // define required namespace objects (must be before evaluation modules) + for (const info of modulesWithInfo) { + if (info.namespaceObjectSource) { + result.add( + `\n// NAMESPACE OBJECT: ${info.module.readableIdentifier( + requestShortener + )}\n` + ); + result.add(info.namespaceObjectSource); + } + } + + // evaluate modules in order + for (const info of modulesWithInfo) { + switch (info.type) { + case "concatenated": + result.add( + `\n// CONCATENATED MODULE: ${info.module.readableIdentifier( + requestShortener + )}\n` + ); + result.add(info.source); + break; + case "external": + result.add( + `\n// EXTERNAL MODULE: ${info.module.readableIdentifier( + requestShortener + )}\n` + ); + result.add( + `var ${info.name} = __webpack_require__(${JSON.stringify( + info.module.id + )});\n` + ); + if (info.interopNamespaceObjectUsed) { + if (info.module.buildMeta.exportsType === "named") { + result.add( + `var ${info.interopNamespaceObjectName} = /*#__PURE__*/__webpack_require__.t(${info.name}, 2);\n` + ); + } else if (!info.module.buildMeta.exportsType) { + result.add( + `var ${info.interopNamespaceObjectName} = /*#__PURE__*/__webpack_require__.t(${info.name});\n` + ); + } + } + if (info.interopDefaultAccessUsed) { + result.add( + `var ${info.interopDefaultAccessName} = /*#__PURE__*/__webpack_require__.n(${info.name});\n` + ); + } + break; + default: + throw new Error(`Unsupported concatenation entry type ${info.type}`); + } + } + + return result; + } + + findNewName(oldName, usedNamed1, usedNamed2, extraInfo) { + let name = oldName; + + if (name === "__WEBPACK_MODULE_DEFAULT_EXPORT__") name = ""; + + // Remove uncool stuff + extraInfo = extraInfo.replace( + /\.+\/|(\/index)?\.([a-zA-Z0-9]{1,4})($|\s|\?)|\s*\+\s*\d+\s*modules/g, + "" + ); + + const splittedInfo = extraInfo.split("/"); + while (splittedInfo.length) { + name = splittedInfo.pop() + (name ? "_" + name : ""); + const nameIdent = Template.toIdentifier(name); + if ( + !usedNamed1.has(nameIdent) && + (!usedNamed2 || !usedNamed2.has(nameIdent)) + ) + return nameIdent; + } + + let i = 0; + let nameWithNumber = Template.toIdentifier(`${name}_${i}`); + while ( + usedNamed1.has(nameWithNumber) || + (usedNamed2 && usedNamed2.has(nameWithNumber)) + ) { + i++; + nameWithNumber = Template.toIdentifier(`${name}_${i}`); + } + return nameWithNumber; + } + + /** + * @param {Hash} hash the hash used to track dependencies + * @returns {void} + */ + updateHash(hash) { + for (const info of this._orderedConcatenationList) { + switch (info.type) { + case "concatenated": + info.module.updateHash(hash); + break; + case "external": + hash.update(`${info.module.id}`); + break; + } + } + super.updateHash(hash); + } +} + +class HarmonyImportSpecifierDependencyConcatenatedTemplate { + constructor(originalTemplate, modulesMap) { + this.originalTemplate = originalTemplate; + this.modulesMap = modulesMap; + } + + getHarmonyInitOrder(dep) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + return this.originalTemplate.getHarmonyInitOrder(dep); + } + return NaN; + } + + harmonyInit(dep, source, runtimeTemplate, dependencyTemplates) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + this.originalTemplate.harmonyInit( + dep, + source, + runtimeTemplate, + dependencyTemplates + ); + return; + } + } + + apply(dep, source, runtime, dependencyTemplates) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + this.originalTemplate.apply(dep, source, runtime, dependencyTemplates); + return; + } + let content; + const callFlag = dep.call ? "_call" : ""; + const strictFlag = dep.originModule.buildMeta.strictHarmonyModule + ? "_strict" + : ""; + if (dep._id === null) { + content = `__WEBPACK_MODULE_REFERENCE__${info.index}_ns${strictFlag}__`; + } else if (dep.namespaceObjectAsContext) { + content = `__WEBPACK_MODULE_REFERENCE__${ + info.index + }_ns${strictFlag}__[${JSON.stringify(dep._id)}]`; + } else { + const exportData = Buffer.from(dep._id, "utf-8").toString("hex"); + content = `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}${callFlag}${strictFlag}__`; + } + if (dep.shorthand) { + content = dep.name + ": " + content; + } + source.replace(dep.range[0], dep.range[1] - 1, content); + } +} + +class HarmonyImportSideEffectDependencyConcatenatedTemplate { + constructor(originalTemplate, modulesMap) { + this.originalTemplate = originalTemplate; + this.modulesMap = modulesMap; + } + + getHarmonyInitOrder(dep) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + return this.originalTemplate.getHarmonyInitOrder(dep); + } + return NaN; + } + + harmonyInit(dep, source, runtime, dependencyTemplates) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + this.originalTemplate.harmonyInit( + dep, + source, + runtime, + dependencyTemplates + ); + return; + } + } + + apply(dep, source, runtime, dependencyTemplates) { + const module = dep._module; + const info = this.modulesMap.get(module); + if (!info) { + this.originalTemplate.apply(dep, source, runtime, dependencyTemplates); + return; + } + } +} + +class HarmonyExportExpressionDependencyConcatenatedTemplate { + constructor(originalTemplate, rootModule) { + this.originalTemplate = originalTemplate; + this.rootModule = rootModule; + } + + apply(dep, source, runtime, dependencyTemplates) { + let content = + "/* harmony default export */ var __WEBPACK_MODULE_DEFAULT_EXPORT__ = "; + if (dep.originModule === this.rootModule) { + const used = dep.originModule.isUsed("default"); + const exportsName = dep.originModule.exportsArgument; + if (used) content += `${exportsName}[${JSON.stringify(used)}] = `; + } + + if (dep.range) { + source.replace( + dep.rangeStatement[0], + dep.range[0] - 1, + content + "(" + dep.prefix + ); + source.replace(dep.range[1], dep.rangeStatement[1] - 1, ");"); + return; + } + + source.replace( + dep.rangeStatement[0], + dep.rangeStatement[1] - 1, + content + dep.prefix + ); + } +} + +class NullTemplate { + apply() {} +} + +module.exports = ConcatenatedModule; diff --git a/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js new file mode 100644 index 0000000..5d05ec8 --- /dev/null +++ b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js @@ -0,0 +1,70 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const GraphHelpers = require("../GraphHelpers"); + +class EnsureChunkConditionsPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "EnsureChunkConditionsPlugin", + compilation => { + const handler = chunks => { + let changed = false; + for (const module of compilation.modules) { + if (!module.chunkCondition) continue; + const sourceChunks = new Set(); + const chunkGroups = new Set(); + for (const chunk of module.chunksIterable) { + if (!module.chunkCondition(chunk)) { + sourceChunks.add(chunk); + for (const group of chunk.groupsIterable) { + chunkGroups.add(group); + } + } + } + if (sourceChunks.size === 0) continue; + const targetChunks = new Set(); + chunkGroupLoop: for (const chunkGroup of chunkGroups) { + // Can module be placed in a chunk of this group? + for (const chunk of chunkGroup.chunks) { + if (module.chunkCondition(chunk)) { + targetChunks.add(chunk); + continue chunkGroupLoop; + } + } + // We reached the entrypoint: fail + if (chunkGroup.isInitial()) { + throw new Error( + "Cannot fullfil chunk condition of " + module.identifier() + ); + } + // Try placing in all parents + for (const group of chunkGroup.parentsIterable) { + chunkGroups.add(group); + } + } + for (const sourceChunk of sourceChunks) { + GraphHelpers.disconnectChunkAndModule(sourceChunk, module); + } + for (const targetChunk of targetChunks) { + GraphHelpers.connectChunkAndModule(targetChunk, module); + } + } + if (changed) return true; + }; + compilation.hooks.optimizeChunksBasic.tap( + "EnsureChunkConditionsPlugin", + handler + ); + compilation.hooks.optimizeExtractedChunksBasic.tap( + "EnsureChunkConditionsPlugin", + handler + ); + } + ); + } +} +module.exports = EnsureChunkConditionsPlugin; diff --git a/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js new file mode 100644 index 0000000..1890f05 --- /dev/null +++ b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js @@ -0,0 +1,99 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class FlagIncludedChunksPlugin { + apply(compiler) { + compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => { + compilation.hooks.optimizeChunkIds.tap( + "FlagIncludedChunksPlugin", + chunks => { + // prepare two bit integers for each module + // 2^31 is the max number represented as SMI in v8 + // we want the bits distributed this way: + // the bit 2^31 is pretty rar and only one module should get it + // so it has a probability of 1 / modulesCount + // the first bit (2^0) is the easiest and every module could get it + // if it doesn't get a better bit + // from bit 2^n to 2^(n+1) there is a probability of p + // so 1 / modulesCount == p^31 + // <=> p = sqrt31(1 / modulesCount) + // so we use a modulo of 1 / sqrt31(1 / modulesCount) + const moduleBits = new WeakMap(); + const modulesCount = compilation.modules.length; + + // precalculate the modulo values for each bit + const modulo = 1 / Math.pow(1 / modulesCount, 1 / 31); + const modulos = Array.from( + { length: 31 }, + (x, i) => Math.pow(modulo, i) | 0 + ); + + // iterate all modules to generate bit values + let i = 0; + for (const module of compilation.modules) { + let bit = 30; + while (i % modulos[bit] !== 0) { + bit--; + } + moduleBits.set(module, 1 << bit); + i++; + } + + // interate all chunks to generate bitmaps + const chunkModulesHash = new WeakMap(); + for (const chunk of chunks) { + let hash = 0; + for (const module of chunk.modulesIterable) { + hash |= moduleBits.get(module); + } + chunkModulesHash.set(chunk, hash); + } + + for (const chunkA of chunks) { + const chunkAHash = chunkModulesHash.get(chunkA); + const chunkAModulesCount = chunkA.getNumberOfModules(); + if (chunkAModulesCount === 0) continue; + let bestModule = undefined; + for (const module of chunkA.modulesIterable) { + if ( + bestModule === undefined || + bestModule.getNumberOfChunks() > module.getNumberOfChunks() + ) + bestModule = module; + } + loopB: for (const chunkB of bestModule.chunksIterable) { + // as we iterate the same iterables twice + // skip if we find ourselves + if (chunkA === chunkB) continue; + + const chunkBModulesCount = chunkB.getNumberOfModules(); + + // ids for empty chunks are not included + if (chunkBModulesCount === 0) continue; + + // instead of swapping A and B just bail + // as we loop twice the current A will be B and B then A + if (chunkAModulesCount > chunkBModulesCount) continue; + + // is chunkA in chunkB? + + // we do a cheap check for the hash value + const chunkBHash = chunkModulesHash.get(chunkB); + if ((chunkBHash & chunkAHash) !== chunkAHash) continue; + + // compare all modules + for (const m of chunkA.modulesIterable) { + if (!chunkB.containsModule(m)) continue loopB; + } + chunkB.ids.push(chunkA.id); + } + } + } + ); + }); + } +} +module.exports = FlagIncludedChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js new file mode 100644 index 0000000..87f2849 --- /dev/null +++ b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js @@ -0,0 +1,231 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json"); +const LazyBucketSortedSet = require("../util/LazyBucketSortedSet"); + +/** @typedef {import("../../declarations/plugins/optimize/LimitChunkCountPlugin").LimitChunkCountPluginOptions} LimitChunkCountPluginOptions */ +/** @typedef {import("../Chunk")} Chunk */ +/** @typedef {import("../Compiler")} Compiler */ + +/** + * @typedef {Object} ChunkCombination + * @property {boolean} deleted this is set to true when combination was removed + * @property {number} sizeDiff + * @property {number} integratedSize + * @property {Chunk} a + * @property {Chunk} b + * @property {number} aIdx + * @property {number} bIdx + * @property {number} aSize + * @property {number} bSize + */ + +const addToSetMap = (map, key, value) => { + const set = map.get(key); + if (set === undefined) { + map.set(key, new Set([value])); + } else { + set.add(value); + } +}; + +class LimitChunkCountPlugin { + /** + * @param {LimitChunkCountPluginOptions=} options options object + */ + constructor(options) { + if (!options) options = {}; + + validateOptions(schema, options, "Limit Chunk Count Plugin"); + this.options = options; + } + + /** + * @param {Compiler} compiler the webpack compiler + * @returns {void} + */ + apply(compiler) { + const options = this.options; + compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => { + compilation.hooks.optimizeChunksAdvanced.tap( + "LimitChunkCountPlugin", + chunks => { + const maxChunks = options.maxChunks; + if (!maxChunks) return; + if (maxChunks < 1) return; + if (chunks.length <= maxChunks) return; + + let remainingChunksToMerge = chunks.length - maxChunks; + + // order chunks in a deterministic way + const orderedChunks = chunks.slice().sort((a, b) => a.compareTo(b)); + + // create a lazy sorted data structure to keep all combinations + // this is large. Size = chunks * (chunks - 1) / 2 + // It uses a multi layer bucket sort plus normal sort in the last layer + // It's also lazy so only accessed buckets are sorted + const combinations = new LazyBucketSortedSet( + // Layer 1: ordered by largest size benefit + c => c.sizeDiff, + (a, b) => b - a, + // Layer 2: ordered by smallest combined size + c => c.integratedSize, + (a, b) => a - b, + // Layer 3: ordered by position difference in orderedChunk (-> to be deterministic) + c => c.bIdx - c.aIdx, + (a, b) => a - b, + // Layer 4: ordered by position in orderedChunk (-> to be deterministic) + (a, b) => a.bIdx - b.bIdx + ); + + // we keep a mappng from chunk to all combinations + // but this mapping is not kept up-to-date with deletions + // so `deleted` flag need to be considered when iterating this + /** @type {Map<Chunk, Set<ChunkCombination>>} */ + const combinationsByChunk = new Map(); + + orderedChunks.forEach((b, bIdx) => { + // create combination pairs with size and integrated size + for (let aIdx = 0; aIdx < bIdx; aIdx++) { + const a = orderedChunks[aIdx]; + const integratedSize = a.integratedSize(b, options); + + // filter pairs that do not have an integratedSize + // meaning they can NOT be integrated! + if (integratedSize === false) continue; + + const aSize = a.size(options); + const bSize = b.size(options); + const c = { + deleted: false, + sizeDiff: aSize + bSize - integratedSize, + integratedSize, + a, + b, + aIdx, + bIdx, + aSize, + bSize + }; + combinations.add(c); + addToSetMap(combinationsByChunk, a, c); + addToSetMap(combinationsByChunk, b, c); + } + return combinations; + }); + + // list of modified chunks during this run + // combinations affected by this change are skipped to allow + // futher optimizations + /** @type {Set<Chunk>} */ + const modifiedChunks = new Set(); + + let changed = false; + // eslint-disable-next-line no-constant-condition + loop: while (true) { + const combination = combinations.popFirst(); + if (combination === undefined) break; + + combination.deleted = true; + const { a, b, integratedSize } = combination; + + // skip over pair when + // one of the already merged chunks is a parent of one of the chunks + if (modifiedChunks.size > 0) { + const queue = new Set(a.groupsIterable); + for (const group of b.groupsIterable) { + queue.add(group); + } + for (const group of queue) { + for (const mChunk of modifiedChunks) { + if (mChunk !== a && mChunk !== b && mChunk.isInGroup(group)) { + // This is a potential pair which needs recalculation + // We can't do that now, but it merge before following pairs + // so we leave space for it, and consider chunks as modified + // just for the worse case + remainingChunksToMerge--; + if (remainingChunksToMerge <= 0) break loop; + modifiedChunks.add(a); + modifiedChunks.add(b); + continue loop; + } + } + for (const parent of group.parentsIterable) { + queue.add(parent); + } + } + } + + // merge the chunks + if (a.integrate(b, "limit")) { + chunks.splice(chunks.indexOf(b), 1); + + // flag chunk a as modified as further optimization are possible for all children here + modifiedChunks.add(a); + + changed = true; + remainingChunksToMerge--; + if (remainingChunksToMerge <= 0) break; + + // Update all affected combinations + // delete all combination with the removed chunk + // we will use combinations with the kept chunk instead + for (const combination of combinationsByChunk.get(b)) { + if (combination.deleted) continue; + combination.deleted = true; + combinations.delete(combination); + } + + // Update combinations with the kept chunk with new sizes + for (const combination of combinationsByChunk.get(a)) { + if (combination.deleted) continue; + if (combination.a === a) { + // Update size + const newIntegratedSize = a.integratedSize( + combination.b, + options + ); + if (newIntegratedSize === false) { + combination.deleted = true; + combinations.delete(combination); + continue; + } + const finishUpdate = combinations.startUpdate(combination); + combination.integratedSize = newIntegratedSize; + combination.aSize = integratedSize; + combination.sizeDiff = + combination.bSize + integratedSize - newIntegratedSize; + finishUpdate(); + } else if (combination.b === a) { + // Update size + const newIntegratedSize = combination.a.integratedSize( + a, + options + ); + if (newIntegratedSize === false) { + combination.deleted = true; + combinations.delete(combination); + continue; + } + const finishUpdate = combinations.startUpdate(combination); + combination.integratedSize = newIntegratedSize; + combination.bSize = integratedSize; + combination.sizeDiff = + integratedSize + combination.aSize - newIntegratedSize; + finishUpdate(); + } + } + } + } + if (changed) return true; + } + ); + }); + } +} +module.exports = LimitChunkCountPlugin; diff --git a/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js new file mode 100644 index 0000000..1c3e23a --- /dev/null +++ b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js @@ -0,0 +1,78 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class MergeDuplicateChunksPlugin { + apply(compiler) { + compiler.hooks.compilation.tap( + "MergeDuplicateChunksPlugin", + compilation => { + compilation.hooks.optimizeChunksBasic.tap( + "MergeDuplicateChunksPlugin", + chunks => { + // remember already tested chunks for performance + const notDuplicates = new Set(); + + // for each chunk + for (const chunk of chunks) { + // track a Set of all chunk that could be duplicates + let possibleDuplicates; + for (const module of chunk.modulesIterable) { + if (possibleDuplicates === undefined) { + // when possibleDuplicates is not yet set, + // create a new Set from chunks of the current module + // including only chunks with the same number of modules + for (const dup of module.chunksIterable) { + if ( + dup !== chunk && + chunk.getNumberOfModules() === dup.getNumberOfModules() && + !notDuplicates.has(dup) + ) { + // delay allocating the new Set until here, reduce memory pressure + if (possibleDuplicates === undefined) { + possibleDuplicates = new Set(); + } + possibleDuplicates.add(dup); + } + } + // when no chunk is possible we can break here + if (possibleDuplicates === undefined) break; + } else { + // validate existing possible duplicates + for (const dup of possibleDuplicates) { + // remove possible duplicate when module is not contained + if (!dup.containsModule(module)) { + possibleDuplicates.delete(dup); + } + } + // when all chunks has been removed we can break here + if (possibleDuplicates.size === 0) break; + } + } + + // when we found duplicates + if ( + possibleDuplicates !== undefined && + possibleDuplicates.size > 0 + ) { + for (const otherChunk of possibleDuplicates) { + if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue; + // merge them + if (chunk.integrate(otherChunk, "duplicate")) { + chunks.splice(chunks.indexOf(otherChunk), 1); + } + } + } + + // don't check already processed chunks twice + notDuplicates.add(chunk); + } + } + ); + } + ); + } +} +module.exports = MergeDuplicateChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js new file mode 100644 index 0000000..144af27 --- /dev/null +++ b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js @@ -0,0 +1,82 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/MinChunkSizePlugin.json"); + +/** @typedef {import("../../declarations/plugins/optimize/MinChunkSizePlugin").MinChunkSizePluginOptions} MinChunkSizePluginOptions */ + +class MinChunkSizePlugin { + /** + * @param {MinChunkSizePluginOptions} options options object + */ + constructor(options) { + validateOptions(schema, options, "Min Chunk Size Plugin"); + this.options = options; + } + + apply(compiler) { + const options = this.options; + const minChunkSize = options.minChunkSize; + compiler.hooks.compilation.tap("MinChunkSizePlugin", compilation => { + compilation.hooks.optimizeChunksAdvanced.tap( + "MinChunkSizePlugin", + chunks => { + const equalOptions = { + chunkOverhead: 1, + entryChunkMultiplicator: 1 + }; + + const sortedSizeFilteredExtendedPairCombinations = chunks + .reduce((combinations, a, idx) => { + // create combination pairs + for (let i = 0; i < idx; i++) { + const b = chunks[i]; + combinations.push([b, a]); + } + return combinations; + }, []) + .filter(pair => { + // check if one of the chunks sizes is smaller than the minChunkSize + const p0SmallerThanMinChunkSize = + pair[0].size(equalOptions) < minChunkSize; + const p1SmallerThanMinChunkSize = + pair[1].size(equalOptions) < minChunkSize; + return p0SmallerThanMinChunkSize || p1SmallerThanMinChunkSize; + }) + .map(pair => { + // extend combination pairs with size and integrated size + const a = pair[0].size(options); + const b = pair[1].size(options); + const ab = pair[0].integratedSize(pair[1], options); + return [a + b - ab, ab, pair[0], pair[1]]; + }) + .filter(pair => { + // filter pairs that do not have an integratedSize + // meaning they can NOT be integrated! + return pair[1] !== false; + }) + .sort((a, b) => { + // sadly javascript does an inplace sort here + // sort by size + const diff = b[0] - a[0]; + if (diff !== 0) return diff; + return a[1] - b[1]; + }); + + if (sortedSizeFilteredExtendedPairCombinations.length === 0) return; + + const pair = sortedSizeFilteredExtendedPairCombinations[0]; + + pair[2].integrate(pair[3], "min-size"); + chunks.splice(chunks.indexOf(pair[3]), 1); + return true; + } + ); + }); + } +} +module.exports = MinChunkSizePlugin; diff --git a/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js b/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js new file mode 100644 index 0000000..255e918 --- /dev/null +++ b/node_modules/webpack/lib/optimize/MinMaxSizeWarning.js @@ -0,0 +1,29 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); +const SizeFormatHelpers = require("../SizeFormatHelpers"); + +class MinMaxSizeWarning extends WebpackError { + constructor(keys, minSize, maxSize) { + let keysMessage = "Fallback cache group"; + if (keys) { + keysMessage = + keys.length > 1 + ? `Cache groups ${keys.sort().join(", ")}` + : `Cache group ${keys[0]}`; + } + super( + `SplitChunksPlugin\n` + + `${keysMessage}\n` + + `Configured minSize (${SizeFormatHelpers.formatSize(minSize)}) is ` + + `bigger than maxSize (${SizeFormatHelpers.formatSize(maxSize)}).\n` + + "This seem to be a invalid optimiziation.splitChunks configuration." + ); + } +} + +module.exports = MinMaxSizeWarning; diff --git a/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js new file mode 100644 index 0000000..0c5bfd3 --- /dev/null +++ b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js @@ -0,0 +1,485 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); +const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency"); +const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency"); +const ConcatenatedModule = require("./ConcatenatedModule"); +const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); +const StackedSetMap = require("../util/StackedSetMap"); + +const formatBailoutReason = msg => { + return "ModuleConcatenation bailout: " + msg; +}; + +class ModuleConcatenationPlugin { + constructor(options) { + if (typeof options !== "object") options = {}; + this.options = options; + } + + apply(compiler) { + compiler.hooks.compilation.tap( + "ModuleConcatenationPlugin", + (compilation, { normalModuleFactory }) => { + const handler = (parser, parserOptions) => { + parser.hooks.call.for("eval").tap("ModuleConcatenationPlugin", () => { + // Because of variable renaming we can't use modules with eval. + parser.state.module.buildMeta.moduleConcatenationBailout = "eval()"; + }); + }; + + normalModuleFactory.hooks.parser + .for("javascript/auto") + .tap("ModuleConcatenationPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/dynamic") + .tap("ModuleConcatenationPlugin", handler); + normalModuleFactory.hooks.parser + .for("javascript/esm") + .tap("ModuleConcatenationPlugin", handler); + + const bailoutReasonMap = new Map(); + + const setBailoutReason = (module, reason) => { + bailoutReasonMap.set(module, reason); + module.optimizationBailout.push( + typeof reason === "function" + ? rs => formatBailoutReason(reason(rs)) + : formatBailoutReason(reason) + ); + }; + + const getBailoutReason = (module, requestShortener) => { + const reason = bailoutReasonMap.get(module); + if (typeof reason === "function") return reason(requestShortener); + return reason; + }; + + compilation.hooks.optimizeChunkModules.tap( + "ModuleConcatenationPlugin", + (allChunks, modules) => { + const relevantModules = []; + const possibleInners = new Set(); + for (const module of modules) { + // Only harmony modules are valid for optimization + if ( + !module.buildMeta || + module.buildMeta.exportsType !== "namespace" || + !module.dependencies.some( + d => d instanceof HarmonyCompatibilityDependency + ) + ) { + setBailoutReason(module, "Module is not an ECMAScript module"); + continue; + } + + // 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.buildMeta && + module.buildMeta.moduleConcatenationBailout + ) { + setBailoutReason( + module, + `Module uses ${module.buildMeta.moduleConcatenationBailout}` + ); + continue; + } + + // Exports must be known (and not dynamic) + if (!Array.isArray(module.buildMeta.providedExports)) { + setBailoutReason(module, "Module exports are unknown"); + continue; + } + + // Using dependency variables is not possible as this wraps the code in a function + if (module.variables.length > 0) { + setBailoutReason( + module, + `Module uses injected variables (${module.variables + .map(v => v.name) + .join(", ")})` + ); + continue; + } + + // Hot Module Replacement need it's own module to work correctly + if ( + module.dependencies.some( + dep => + dep instanceof ModuleHotAcceptDependency || + dep instanceof ModuleHotDeclineDependency + ) + ) { + setBailoutReason(module, "Module uses Hot Module Replacement"); + continue; + } + + relevantModules.push(module); + + // Module must not be the entry points + if (module.isEntryModule()) { + setBailoutReason(module, "Module is an entry point"); + continue; + } + + // Module must be in any chunk (we don't want to do useless work) + if (module.getNumberOfChunks() === 0) { + setBailoutReason(module, "Module is not in any chunk"); + continue; + } + + // Module must only be used by Harmony Imports + const nonHarmonyReasons = module.reasons.filter( + reason => + !reason.dependency || + !(reason.dependency instanceof HarmonyImportDependency) + ); + if (nonHarmonyReasons.length > 0) { + const importingModules = new Set( + nonHarmonyReasons.map(r => r.module).filter(Boolean) + ); + const importingExplanations = new Set( + nonHarmonyReasons.map(r => r.explanation).filter(Boolean) + ); + const importingModuleTypes = new Map( + Array.from(importingModules).map( + m => /** @type {[string, Set]} */ ([ + m, + new Set( + nonHarmonyReasons + .filter(r => r.module === m) + .map(r => r.dependency.type) + .sort() + ) + ]) + ) + ); + setBailoutReason(module, requestShortener => { + const names = Array.from(importingModules) + .map( + m => + `${m.readableIdentifier( + requestShortener + )} (referenced with ${Array.from( + importingModuleTypes.get(m) + ).join(", ")})` + ) + .sort(); + const explanations = Array.from(importingExplanations).sort(); + if (names.length > 0 && explanations.length === 0) { + return `Module is referenced from these modules with unsupported syntax: ${names.join( + ", " + )}`; + } else if (names.length === 0 && explanations.length > 0) { + return `Module is referenced by: ${explanations.join( + ", " + )}`; + } else if (names.length > 0 && explanations.length > 0) { + return `Module is referenced from these modules with unsupported syntax: ${names.join( + ", " + )} and by: ${explanations.join(", ")}`; + } else { + return "Module is referenced in a unsupported way"; + } + }); + continue; + } + + possibleInners.add(module); + } + // sort by depth + // modules with lower depth are more likely suited as roots + // this improves performance, because modules already selected as inner are skipped + relevantModules.sort((a, b) => { + return a.depth - b.depth; + }); + const concatConfigurations = []; + const usedAsInner = new Set(); + for (const currentRoot of relevantModules) { + // when used by another configuration as inner: + // the other configuration is better and we can skip this one + if (usedAsInner.has(currentRoot)) continue; + + // create a configuration with the root + const currentConfiguration = new ConcatConfiguration(currentRoot); + + // cache failures to add modules + const failureCache = new Map(); + + // try to add all imports + for (const imp of this._getImports(compilation, currentRoot)) { + const problem = this._tryToAdd( + compilation, + currentConfiguration, + imp, + possibleInners, + failureCache + ); + if (problem) { + failureCache.set(imp, problem); + currentConfiguration.addWarning(imp, problem); + } + } + if (!currentConfiguration.isEmpty()) { + concatConfigurations.push(currentConfiguration); + for (const module of currentConfiguration.getModules()) { + if (module !== currentConfiguration.rootModule) { + usedAsInner.add(module); + } + } + } + } + // HACK: Sort configurations by length and start with the longest one + // to get the biggers groups possible. Used modules are marked with usedModules + // TODO: Allow to reuse existing configuration while trying to add dependencies. + // This would improve performance. O(n^2) -> O(n) + concatConfigurations.sort((a, b) => { + return b.modules.size - a.modules.size; + }); + const usedModules = new Set(); + for (const concatConfiguration of concatConfigurations) { + if (usedModules.has(concatConfiguration.rootModule)) continue; + const modules = concatConfiguration.getModules(); + const rootModule = concatConfiguration.rootModule; + const newModule = new ConcatenatedModule( + rootModule, + Array.from(modules), + ConcatenatedModule.createConcatenationList( + rootModule, + modules, + compilation + ) + ); + for (const warning of concatConfiguration.getWarningsSorted()) { + newModule.optimizationBailout.push(requestShortener => { + const reason = getBailoutReason(warning[0], requestShortener); + const reasonWithPrefix = reason ? ` (<- ${reason})` : ""; + if (warning[0] === warning[1]) { + return formatBailoutReason( + `Cannot concat with ${warning[0].readableIdentifier( + requestShortener + )}${reasonWithPrefix}` + ); + } else { + return formatBailoutReason( + `Cannot concat with ${warning[0].readableIdentifier( + requestShortener + )} because of ${warning[1].readableIdentifier( + requestShortener + )}${reasonWithPrefix}` + ); + } + }); + } + const chunks = concatConfiguration.rootModule.getChunks(); + for (const m of modules) { + usedModules.add(m); + for (const chunk of chunks) { + chunk.removeModule(m); + } + } + for (const chunk of chunks) { + chunk.addModule(newModule); + newModule.addChunk(chunk); + } + for (const chunk of allChunks) { + if (chunk.entryModule === concatConfiguration.rootModule) { + chunk.entryModule = newModule; + } + } + compilation.modules.push(newModule); + for (const reason of newModule.reasons) { + if (reason.dependency.module === concatConfiguration.rootModule) + reason.dependency.module = newModule; + if ( + reason.dependency.redirectedModule === + concatConfiguration.rootModule + ) + reason.dependency.redirectedModule = newModule; + } + // TODO: remove when LTS node version contains fixed v8 version + // @see https://github.com/webpack/webpack/pull/6613 + // Turbofan does not correctly inline for-of loops with polymorphic input arrays. + // Work around issue by using a standard for loop and assigning dep.module.reasons + for (let i = 0; i < newModule.dependencies.length; i++) { + let dep = newModule.dependencies[i]; + if (dep.module) { + let reasons = dep.module.reasons; + for (let j = 0; j < reasons.length; j++) { + let reason = reasons[j]; + if (reason.dependency === dep) { + reason.module = newModule; + } + } + } + } + } + compilation.modules = compilation.modules.filter( + m => !usedModules.has(m) + ); + } + ); + } + ); + } + + _getImports(compilation, module) { + return new Set( + module.dependencies + + // Get reference info only for harmony Dependencies + .map(dep => { + if (!(dep instanceof HarmonyImportDependency)) return null; + if (!compilation) return dep.getReference(); + return compilation.getDependencyReference(module, dep); + }) + + // Reference is valid and has a module + // Dependencies are simple enough to concat them + .filter( + ref => + ref && + ref.module && + (Array.isArray(ref.importedNames) || + Array.isArray(ref.module.buildMeta.providedExports)) + ) + + // Take the imported module + .map(ref => ref.module) + ); + } + + _tryToAdd(compilation, config, module, possibleModules, failureCache) { + const cacheEntry = failureCache.get(module); + if (cacheEntry) { + return cacheEntry; + } + + // Already added? + if (config.has(module)) { + return null; + } + + // Not possible to add? + if (!possibleModules.has(module)) { + failureCache.set(module, module); // cache failures for performance + return module; + } + + // module must be in the same chunks + if (!config.rootModule.hasEqualsChunks(module)) { + failureCache.set(module, module); // cache failures for performance + return module; + } + + // Clone config to make experimental changes + const testConfig = config.clone(); + + // Add the module + testConfig.add(module); + + // Every module which depends on the added module must be in the configuration too. + for (const reason of module.reasons) { + // Modules that are not used can be ignored + if ( + reason.module.factoryMeta.sideEffectFree && + reason.module.used === false + ) + continue; + + const problem = this._tryToAdd( + compilation, + testConfig, + reason.module, + possibleModules, + failureCache + ); + if (problem) { + failureCache.set(module, problem); // cache failures for performance + return problem; + } + } + + // Commit experimental changes + config.set(testConfig); + + // Eagerly try to add imports too if possible + for (const imp of this._getImports(compilation, module)) { + const problem = this._tryToAdd( + compilation, + config, + imp, + possibleModules, + failureCache + ); + if (problem) { + config.addWarning(imp, problem); + } + } + return null; + } +} + +class ConcatConfiguration { + constructor(rootModule, cloneFrom) { + this.rootModule = rootModule; + if (cloneFrom) { + this.modules = cloneFrom.modules.createChild(5); + this.warnings = cloneFrom.warnings.createChild(5); + } else { + this.modules = new StackedSetMap(); + this.modules.add(rootModule); + this.warnings = new StackedSetMap(); + } + } + + add(module) { + this.modules.add(module); + } + + has(module) { + return this.modules.has(module); + } + + isEmpty() { + return this.modules.size === 1; + } + + addWarning(module, problem) { + this.warnings.set(module, problem); + } + + getWarningsSorted() { + return new Map( + this.warnings.asPairArray().sort((a, b) => { + const ai = a[0].identifier(); + const bi = b[0].identifier(); + if (ai < bi) return -1; + if (ai > bi) return 1; + return 0; + }) + ); + } + + getModules() { + return this.modules.asSet(); + } + + clone() { + return new ConcatConfiguration(this.rootModule, this); + } + + set(config) { + this.rootModule = config.rootModule; + this.modules = config.modules; + this.warnings = config.warnings; + } +} + +module.exports = ModuleConcatenationPlugin; diff --git a/node_modules/webpack/lib/optimize/NaturalChunkOrderPlugin.js b/node_modules/webpack/lib/optimize/NaturalChunkOrderPlugin.js new file mode 100644 index 0000000..00f8010 --- /dev/null +++ b/node_modules/webpack/lib/optimize/NaturalChunkOrderPlugin.js @@ -0,0 +1,41 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +/** @typedef {import("../Compiler")} Compiler */ + +class NaturalChunkOrderPlugin { + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap("NaturalChunkOrderPlugin", compilation => { + compilation.hooks.optimizeChunkOrder.tap( + "NaturalChunkOrderPlugin", + chunks => { + chunks.sort((chunkA, chunkB) => { + const a = chunkA.modulesIterable[Symbol.iterator](); + const b = chunkB.modulesIterable[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = a.next(); + const bItem = b.next(); + if (aItem.done && bItem.done) return 0; + if (aItem.done) return -1; + if (bItem.done) return 1; + const aModuleId = aItem.value.id; + const bModuleId = bItem.value.id; + if (aModuleId < bModuleId) return -1; + if (aModuleId > bModuleId) return 1; + } + }); + } + ); + }); + } +} + +module.exports = NaturalChunkOrderPlugin; diff --git a/node_modules/webpack/lib/optimize/OccurrenceChunkOrderPlugin.js b/node_modules/webpack/lib/optimize/OccurrenceChunkOrderPlugin.js new file mode 100644 index 0000000..4f7ec9a --- /dev/null +++ b/node_modules/webpack/lib/optimize/OccurrenceChunkOrderPlugin.js @@ -0,0 +1,66 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/OccurrenceOrderChunkIdsPlugin.json"); + +/** @typedef {import("../../declarations/plugins/optimize/OccurrenceOrderChunkIdsPlugin").OccurrenceOrderChunkIdsPluginOptions} OccurrenceOrderChunkIdsPluginOptions */ + +class OccurrenceOrderChunkIdsPlugin { + /** + * @param {OccurrenceOrderChunkIdsPluginOptions=} options options object + */ + constructor(options = {}) { + validateOptions(schema, options, "Occurrence Order Chunk Ids Plugin"); + this.options = options; + } + + apply(compiler) { + const prioritiseInitial = this.options.prioritiseInitial; + compiler.hooks.compilation.tap( + "OccurrenceOrderChunkIdsPlugin", + compilation => { + compilation.hooks.optimizeChunkOrder.tap( + "OccurrenceOrderChunkIdsPlugin", + chunks => { + const occursInInitialChunksMap = new Map(); + const originalOrder = new Map(); + + let i = 0; + for (const c of chunks) { + let occurs = 0; + for (const chunkGroup of c.groupsIterable) { + for (const parent of chunkGroup.parentsIterable) { + if (parent.isInitial()) occurs++; + } + } + occursInInitialChunksMap.set(c, occurs); + originalOrder.set(c, i++); + } + + chunks.sort((a, b) => { + if (prioritiseInitial) { + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); + if (aEntryOccurs > bEntryOccurs) return -1; + if (aEntryOccurs < bEntryOccurs) return 1; + } + const aOccurs = a.getNumberOfGroups(); + const bOccurs = b.getNumberOfGroups(); + if (aOccurs > bOccurs) return -1; + if (aOccurs < bOccurs) return 1; + const orgA = originalOrder.get(a); + const orgB = originalOrder.get(b); + return orgA - orgB; + }); + } + ); + } + ); + } +} + +module.exports = OccurrenceOrderChunkIdsPlugin; diff --git a/node_modules/webpack/lib/optimize/OccurrenceModuleOrderPlugin.js b/node_modules/webpack/lib/optimize/OccurrenceModuleOrderPlugin.js new file mode 100644 index 0000000..cb9a3e8 --- /dev/null +++ b/node_modules/webpack/lib/optimize/OccurrenceModuleOrderPlugin.js @@ -0,0 +1,112 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json"); + +/** @typedef {import("../../declarations/plugins/optimize/OccurrenceOrderModuleIdsPlugin").OccurrenceOrderModuleIdsPluginOptions} OccurrenceOrderModuleIdsPluginOptions */ + +class OccurrenceOrderModuleIdsPlugin { + /** + * @param {OccurrenceOrderModuleIdsPluginOptions=} options options object + */ + constructor(options = {}) { + validateOptions(schema, options, "Occurrence Order Module Ids Plugin"); + this.options = options; + } + + apply(compiler) { + const prioritiseInitial = this.options.prioritiseInitial; + compiler.hooks.compilation.tap( + "OccurrenceOrderModuleIdsPlugin", + compilation => { + compilation.hooks.optimizeModuleOrder.tap( + "OccurrenceOrderModuleIdsPlugin", + modules => { + const occursInInitialChunksMap = new Map(); + const occursInAllChunksMap = new Map(); + + const initialChunkChunkMap = new Map(); + const entryCountMap = new Map(); + for (const m of modules) { + let initial = 0; + let entry = 0; + for (const c of m.chunksIterable) { + if (c.canBeInitial()) initial++; + if (c.entryModule === m) entry++; + } + initialChunkChunkMap.set(m, initial); + entryCountMap.set(m, entry); + } + + const countOccursInEntry = (sum, r) => { + if (!r.module) { + return sum; + } + const count = initialChunkChunkMap.get(r.module); + if (!count) { + return sum; + } + return sum + count; + }; + const countOccurs = (sum, r) => { + if (!r.module) { + return sum; + } + let factor = 1; + if (typeof r.dependency.getNumberOfIdOccurrences === "function") { + factor = r.dependency.getNumberOfIdOccurrences(); + } + if (factor === 0) { + return sum; + } + return sum + factor * r.module.getNumberOfChunks(); + }; + + if (prioritiseInitial) { + for (const m of modules) { + const result = + m.reasons.reduce(countOccursInEntry, 0) + + initialChunkChunkMap.get(m) + + entryCountMap.get(m); + occursInInitialChunksMap.set(m, result); + } + } + + const originalOrder = new Map(); + let i = 0; + for (const m of modules) { + const result = + m.reasons.reduce(countOccurs, 0) + + m.getNumberOfChunks() + + entryCountMap.get(m); + occursInAllChunksMap.set(m, result); + originalOrder.set(m, i++); + } + + modules.sort((a, b) => { + if (prioritiseInitial) { + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); + if (aEntryOccurs > bEntryOccurs) return -1; + if (aEntryOccurs < bEntryOccurs) return 1; + } + const aOccurs = occursInAllChunksMap.get(a); + const bOccurs = occursInAllChunksMap.get(b); + if (aOccurs > bOccurs) return -1; + if (aOccurs < bOccurs) return 1; + const orgA = originalOrder.get(a); + const orgB = originalOrder.get(b); + return orgA - orgB; + }); + } + ); + } + ); + } +} + +module.exports = OccurrenceOrderModuleIdsPlugin; diff --git a/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js new file mode 100644 index 0000000..c73ec8e --- /dev/null +++ b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js @@ -0,0 +1,135 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +// TODO webpack 5 remove this plugin +// It has been splitted into separate plugins for modules and chunks +class OccurrenceOrderPlugin { + constructor(preferEntry) { + if (preferEntry !== undefined && typeof preferEntry !== "boolean") { + throw new Error( + "Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/" + ); + } + this.preferEntry = preferEntry; + } + apply(compiler) { + const preferEntry = this.preferEntry; + compiler.hooks.compilation.tap("OccurrenceOrderPlugin", compilation => { + compilation.hooks.optimizeModuleOrder.tap( + "OccurrenceOrderPlugin", + modules => { + const occursInInitialChunksMap = new Map(); + const occursInAllChunksMap = new Map(); + + const initialChunkChunkMap = new Map(); + const entryCountMap = new Map(); + for (const m of modules) { + let initial = 0; + let entry = 0; + for (const c of m.chunksIterable) { + if (c.canBeInitial()) initial++; + if (c.entryModule === m) entry++; + } + initialChunkChunkMap.set(m, initial); + entryCountMap.set(m, entry); + } + + const countOccursInEntry = (sum, r) => { + if (!r.module) { + return sum; + } + return sum + initialChunkChunkMap.get(r.module); + }; + const countOccurs = (sum, r) => { + if (!r.module) { + return sum; + } + let factor = 1; + if (typeof r.dependency.getNumberOfIdOccurrences === "function") { + factor = r.dependency.getNumberOfIdOccurrences(); + } + if (factor === 0) { + return sum; + } + return sum + factor * r.module.getNumberOfChunks(); + }; + + if (preferEntry) { + for (const m of modules) { + const result = + m.reasons.reduce(countOccursInEntry, 0) + + initialChunkChunkMap.get(m) + + entryCountMap.get(m); + occursInInitialChunksMap.set(m, result); + } + } + + const originalOrder = new Map(); + let i = 0; + for (const m of modules) { + const result = + m.reasons.reduce(countOccurs, 0) + + m.getNumberOfChunks() + + entryCountMap.get(m); + occursInAllChunksMap.set(m, result); + originalOrder.set(m, i++); + } + + modules.sort((a, b) => { + if (preferEntry) { + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); + if (aEntryOccurs > bEntryOccurs) return -1; + if (aEntryOccurs < bEntryOccurs) return 1; + } + const aOccurs = occursInAllChunksMap.get(a); + const bOccurs = occursInAllChunksMap.get(b); + if (aOccurs > bOccurs) return -1; + if (aOccurs < bOccurs) return 1; + const orgA = originalOrder.get(a); + const orgB = originalOrder.get(b); + return orgA - orgB; + }); + } + ); + compilation.hooks.optimizeChunkOrder.tap( + "OccurrenceOrderPlugin", + chunks => { + const occursInInitialChunksMap = new Map(); + const originalOrder = new Map(); + + let i = 0; + for (const c of chunks) { + let occurs = 0; + for (const chunkGroup of c.groupsIterable) { + for (const parent of chunkGroup.parentsIterable) { + if (parent.isInitial()) occurs++; + } + } + occursInInitialChunksMap.set(c, occurs); + originalOrder.set(c, i++); + } + + chunks.sort((a, b) => { + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); + if (aEntryOccurs > bEntryOccurs) return -1; + if (aEntryOccurs < bEntryOccurs) return 1; + const aOccurs = a.getNumberOfGroups(); + const bOccurs = b.getNumberOfGroups(); + if (aOccurs > bOccurs) return -1; + if (aOccurs < bOccurs) return 1; + const orgA = originalOrder.get(a); + const orgB = originalOrder.get(b); + return orgA - orgB; + }); + } + ); + }); + } +} + +module.exports = OccurrenceOrderPlugin; diff --git a/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js new file mode 100644 index 0000000..42ba24a --- /dev/null +++ b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js @@ -0,0 +1,42 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class RemoveEmptyChunksPlugin { + apply(compiler) { + compiler.hooks.compilation.tap("RemoveEmptyChunksPlugin", compilation => { + const handler = chunks => { + for (let i = chunks.length - 1; i >= 0; i--) { + const chunk = chunks[i]; + if ( + chunk.isEmpty() && + !chunk.hasRuntime() && + !chunk.hasEntryModule() + ) { + chunk.remove("empty"); + chunks.splice(i, 1); + } + } + }; + compilation.hooks.optimizeChunksBasic.tap( + "RemoveEmptyChunksPlugin", + handler + ); + compilation.hooks.optimizeChunksAdvanced.tap( + "RemoveEmptyChunksPlugin", + handler + ); + compilation.hooks.optimizeExtractedChunksBasic.tap( + "RemoveEmptyChunksPlugin", + handler + ); + compilation.hooks.optimizeExtractedChunksAdvanced.tap( + "RemoveEmptyChunksPlugin", + handler + ); + }); + } +} +module.exports = RemoveEmptyChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js new file mode 100644 index 0000000..7fff592 --- /dev/null +++ b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js @@ -0,0 +1,127 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Queue = require("../util/Queue"); +const { intersect } = require("../util/SetHelpers"); + +const getParentChunksWithModule = (currentChunk, module) => { + const chunks = []; + const stack = new Set(currentChunk.parentsIterable); + + for (const chunk of stack) { + if (chunk.containsModule(module)) { + chunks.push(chunk); + } else { + for (const parent of chunk.parentsIterable) { + stack.add(parent); + } + } + } + + return chunks; +}; + +class RemoveParentModulesPlugin { + apply(compiler) { + compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => { + const handler = (chunks, chunkGroups) => { + const queue = new Queue(); + const availableModulesMap = new WeakMap(); + + for (const chunkGroup of compilation.entrypoints.values()) { + // initialize available modules for chunks without parents + availableModulesMap.set(chunkGroup, new Set()); + for (const child of chunkGroup.childrenIterable) { + queue.enqueue(child); + } + } + + while (queue.length > 0) { + const chunkGroup = queue.dequeue(); + let availableModules = availableModulesMap.get(chunkGroup); + let changed = false; + for (const parent of chunkGroup.parentsIterable) { + const availableModulesInParent = availableModulesMap.get(parent); + if (availableModulesInParent !== undefined) { + // If we know the available modules in parent: process these + if (availableModules === undefined) { + // if we have not own info yet: create new entry + availableModules = new Set(availableModulesInParent); + for (const chunk of parent.chunks) { + for (const m of chunk.modulesIterable) { + availableModules.add(m); + } + } + availableModulesMap.set(chunkGroup, availableModules); + changed = true; + } else { + for (const m of availableModules) { + if ( + !parent.containsModule(m) && + !availableModulesInParent.has(m) + ) { + availableModules.delete(m); + changed = true; + } + } + } + } + } + if (changed) { + // if something changed: enqueue our children + for (const child of chunkGroup.childrenIterable) { + queue.enqueue(child); + } + } + } + + // now we have available modules for every chunk + for (const chunk of chunks) { + const availableModulesSets = Array.from( + chunk.groupsIterable, + chunkGroup => availableModulesMap.get(chunkGroup) + ); + if (availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group + const availableModules = + availableModulesSets.length === 1 + ? availableModulesSets[0] + : intersect(availableModulesSets); + const numberOfModules = chunk.getNumberOfModules(); + const toRemove = new Set(); + if (numberOfModules < availableModules.size) { + for (const m of chunk.modulesIterable) { + if (availableModules.has(m)) { + toRemove.add(m); + } + } + } else { + for (const m of availableModules) { + if (chunk.containsModule(m)) { + toRemove.add(m); + } + } + } + for (const module of toRemove) { + module.rewriteChunkInReasons( + chunk, + getParentChunksWithModule(chunk, module) + ); + chunk.removeModule(module); + } + } + }; + compilation.hooks.optimizeChunksBasic.tap( + "RemoveParentModulesPlugin", + handler + ); + compilation.hooks.optimizeExtractedChunksBasic.tap( + "RemoveParentModulesPlugin", + handler + ); + }); + } +} +module.exports = RemoveParentModulesPlugin; diff --git a/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js b/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js new file mode 100644 index 0000000..1325dfc --- /dev/null +++ b/node_modules/webpack/lib/optimize/RuntimeChunkPlugin.js @@ -0,0 +1,41 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +module.exports = class RuntimeChunkPlugin { + constructor(options) { + this.options = Object.assign( + { + name: entrypoint => `runtime~${entrypoint.name}` + }, + options + ); + } + + apply(compiler) { + compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => { + compilation.hooks.optimizeChunksAdvanced.tap("RuntimeChunkPlugin", () => { + for (const entrypoint of compilation.entrypoints.values()) { + const chunk = entrypoint.getRuntimeChunk(); + let name = this.options.name; + if (typeof name === "function") { + name = name(entrypoint); + } + if ( + chunk.getNumberOfModules() > 0 || + !chunk.preventIntegration || + chunk.name !== name + ) { + const newChunk = compilation.addChunk(name); + newChunk.preventIntegration = true; + entrypoint.unshiftChunk(newChunk); + newChunk.addGroup(entrypoint); + entrypoint.setRuntimeChunk(newChunk); + } + } + }); + }); + } +}; diff --git a/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js new file mode 100644 index 0000000..5db780c --- /dev/null +++ b/node_modules/webpack/lib/optimize/SideEffectsFlagPlugin.js @@ -0,0 +1,352 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const mm = require("micromatch"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency"); +const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); + +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../Dependency")} Dependency */ + +/** + * @typedef {Object} ExportInModule + * @property {Module} module the module + * @property {string} exportName the name of the export + * @property {boolean} checked if the export is conditional + */ + +/** + * @typedef {Object} ReexportInfo + * @property {Map<string, ExportInModule[]>} static + * @property {Map<Module, Set<string>>} dynamic + */ + +/** + * @param {ReexportInfo} info info object + * @param {string} exportName name of export + * @returns {ExportInModule | undefined} static export + */ +const getMappingFromInfo = (info, exportName) => { + const staticMappings = info.static.get(exportName); + if (staticMappings !== undefined) { + if (staticMappings.length === 1) return staticMappings[0]; + return undefined; + } + const dynamicMappings = Array.from(info.dynamic).filter( + ([_, ignored]) => !ignored.has(exportName) + ); + if (dynamicMappings.length === 1) { + return { + module: dynamicMappings[0][0], + exportName, + checked: true + }; + } + return undefined; +}; + +/** + * @param {ReexportInfo} info info object + * @param {string} exportName name of export of source module + * @param {Module} module the target module + * @param {string} innerExportName name of export of target module + * @param {boolean} checked true, if existence of target module is checked + */ +const addStaticReexport = ( + info, + exportName, + module, + innerExportName, + checked +) => { + let mappings = info.static.get(exportName); + if (mappings !== undefined) { + for (const mapping of mappings) { + if (mapping.module === module && mapping.exportName === innerExportName) { + mapping.checked = mapping.checked && checked; + return; + } + } + } else { + mappings = []; + info.static.set(exportName, mappings); + } + mappings.push({ + module, + exportName: innerExportName, + checked + }); +}; + +/** + * @param {ReexportInfo} info info object + * @param {Module} module the reexport module + * @param {Set<string>} ignored ignore list + * @returns {void} + */ +const addDynamicReexport = (info, module, ignored) => { + const existingList = info.dynamic.get(module); + if (existingList !== undefined) { + for (const key of existingList) { + if (!ignored.has(key)) existingList.delete(key); + } + } else { + info.dynamic.set(module, new Set(ignored)); + } +}; + +class SideEffectsFlagPlugin { + apply(compiler) { + compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => { + nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { + const resolveData = data.resourceResolveData; + if ( + resolveData && + resolveData.descriptionFileData && + resolveData.relativePath + ) { + const sideEffects = resolveData.descriptionFileData.sideEffects; + const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects( + resolveData.relativePath, + sideEffects + ); + if (!hasSideEffects) { + module.factoryMeta.sideEffectFree = true; + } + } + + return module; + }); + nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => { + if (data.settings.sideEffects === false) { + module.factoryMeta.sideEffectFree = true; + } else if (data.settings.sideEffects === true) { + module.factoryMeta.sideEffectFree = false; + } + }); + }); + compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => { + compilation.hooks.optimizeDependencies.tap( + "SideEffectsFlagPlugin", + modules => { + /** @type {Map<Module, ReexportInfo>} */ + const reexportMaps = new Map(); + + // Capture reexports of sideEffectFree modules + for (const module of modules) { + /** @type {Dependency[]} */ + const removeDependencies = []; + for (const dep of module.dependencies) { + if (dep instanceof HarmonyImportSideEffectDependency) { + if (dep.module && dep.module.factoryMeta.sideEffectFree) { + removeDependencies.push(dep); + } + } else if ( + dep instanceof HarmonyExportImportedSpecifierDependency + ) { + if (module.factoryMeta.sideEffectFree) { + const mode = dep.getMode(true); + if ( + mode.type === "safe-reexport" || + mode.type === "checked-reexport" || + mode.type === "dynamic-reexport" || + mode.type === "reexport-non-harmony-default" || + mode.type === "reexport-non-harmony-default-strict" || + mode.type === "reexport-named-default" + ) { + let info = reexportMaps.get(module); + if (!info) { + reexportMaps.set( + module, + (info = { + static: new Map(), + dynamic: new Map() + }) + ); + } + const targetModule = dep._module; + switch (mode.type) { + case "safe-reexport": + for (const [key, id] of mode.map) { + if (id) { + addStaticReexport( + info, + key, + targetModule, + id, + false + ); + } + } + break; + case "checked-reexport": + for (const [key, id] of mode.map) { + if (id) { + addStaticReexport( + info, + key, + targetModule, + id, + true + ); + } + } + break; + case "dynamic-reexport": + addDynamicReexport(info, targetModule, mode.ignored); + break; + case "reexport-non-harmony-default": + case "reexport-non-harmony-default-strict": + case "reexport-named-default": + addStaticReexport( + info, + mode.name, + targetModule, + "default", + false + ); + break; + } + } + } + } + } + } + + // Flatten reexports + for (const info of reexportMaps.values()) { + const dynamicReexports = info.dynamic; + info.dynamic = new Map(); + for (const reexport of dynamicReexports) { + let [targetModule, ignored] = reexport; + for (;;) { + const innerInfo = reexportMaps.get(targetModule); + if (!innerInfo) break; + + for (const [key, reexports] of innerInfo.static) { + if (ignored.has(key)) continue; + for (const { module, exportName, checked } of reexports) { + addStaticReexport(info, key, module, exportName, checked); + } + } + + // Follow dynamic reexport if there is only one + if (innerInfo.dynamic.size !== 1) { + // When there are more then one, we don't know which one + break; + } + + ignored = new Set(ignored); + for (const [innerModule, innerIgnored] of innerInfo.dynamic) { + for (const key of innerIgnored) { + if (ignored.has(key)) continue; + // This reexports ends here + addStaticReexport(info, key, targetModule, key, true); + ignored.add(key); + } + targetModule = innerModule; + } + } + + // Update reexport as all other cases has been handled + addDynamicReexport(info, targetModule, ignored); + } + } + + for (const info of reexportMaps.values()) { + const staticReexports = info.static; + info.static = new Map(); + for (const [key, reexports] of staticReexports) { + for (let mapping of reexports) { + for (;;) { + const innerInfo = reexportMaps.get(mapping.module); + if (!innerInfo) break; + + const newMapping = getMappingFromInfo( + innerInfo, + mapping.exportName + ); + if (!newMapping) break; + mapping = newMapping; + } + addStaticReexport( + info, + key, + mapping.module, + mapping.exportName, + mapping.checked + ); + } + } + } + + // Update imports along the reexports from sideEffectFree modules + for (const pair of reexportMaps) { + const module = pair[0]; + const info = pair[1]; + let newReasons = undefined; + for (let i = 0; i < module.reasons.length; i++) { + const reason = module.reasons[i]; + const dep = reason.dependency; + if ( + (dep instanceof HarmonyExportImportedSpecifierDependency || + (dep instanceof HarmonyImportSpecifierDependency && + !dep.namespaceObjectAsContext)) && + dep._id + ) { + const mapping = getMappingFromInfo(info, dep._id); + if (mapping) { + dep.redirectedModule = mapping.module; + dep.redirectedId = mapping.exportName; + mapping.module.addReason( + reason.module, + dep, + reason.explanation + ? reason.explanation + + " (skipped side-effect-free modules)" + : "(skipped side-effect-free modules)" + ); + // removing the currect reason, by not adding it to the newReasons array + // lazily create the newReasons array + if (newReasons === undefined) { + newReasons = i === 0 ? [] : module.reasons.slice(0, i); + } + continue; + } + } + if (newReasons !== undefined) newReasons.push(reason); + } + if (newReasons !== undefined) { + module.reasons = newReasons; + } + } + } + ); + }); + } + + static moduleHasSideEffects(moduleName, flagValue) { + switch (typeof flagValue) { + case "undefined": + return true; + case "boolean": + return flagValue; + case "string": + if (process.platform === "win32") { + flagValue = flagValue.replace(/\\/g, "/"); + } + return mm.isMatch(moduleName, flagValue, { + matchBase: true + }); + case "object": + return flagValue.some(glob => + SideEffectsFlagPlugin.moduleHasSideEffects(moduleName, glob) + ); + } + } +} +module.exports = SideEffectsFlagPlugin; diff --git a/node_modules/webpack/lib/optimize/SplitChunksPlugin.js b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js new file mode 100644 index 0000000..439e407 --- /dev/null +++ b/node_modules/webpack/lib/optimize/SplitChunksPlugin.js @@ -0,0 +1,968 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const crypto = require("crypto"); +const SortableSet = require("../util/SortableSet"); +const GraphHelpers = require("../GraphHelpers"); +const { isSubset } = require("../util/SetHelpers"); +const deterministicGrouping = require("../util/deterministicGrouping"); +const MinMaxSizeWarning = require("./MinMaxSizeWarning"); +const contextify = require("../util/identifier").contextify; + +/** @typedef {import("../Compiler")} Compiler */ +/** @typedef {import("../Chunk")} Chunk */ +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../util/deterministicGrouping").Options<Module>} DeterministicGroupingOptionsForModule */ +/** @typedef {import("../util/deterministicGrouping").GroupedItems<Module>} DeterministicGroupingGroupedItemsForModule */ + +const deterministicGroupingForModules = /** @type {function(DeterministicGroupingOptionsForModule): DeterministicGroupingGroupedItemsForModule[]} */ (deterministicGrouping); + +const hashFilename = name => { + return crypto + .createHash("md4") + .update(name) + .digest("hex") + .slice(0, 8); +}; + +const sortByIdentifier = (a, b) => { + if (a.identifier() > b.identifier()) return 1; + if (a.identifier() < b.identifier()) return -1; + return 0; +}; + +const getRequests = chunk => { + let requests = 0; + for (const chunkGroup of chunk.groupsIterable) { + requests = Math.max(requests, chunkGroup.chunks.length); + } + return requests; +}; + +const getModulesSize = modules => { + let sum = 0; + for (const m of modules) { + sum += m.size(); + } + return sum; +}; + +/** + * @template T + * @param {Set<T>} a set + * @param {Set<T>} b other set + * @returns {boolean} true if at least one item of a is in b + */ +const isOverlap = (a, b) => { + for (const item of a) { + if (b.has(item)) return true; + } + return false; +}; + +const compareEntries = (a, b) => { + // 1. by priority + const diffPriority = a.cacheGroup.priority - b.cacheGroup.priority; + if (diffPriority) return diffPriority; + // 2. by number of chunks + const diffCount = a.chunks.size - b.chunks.size; + if (diffCount) return diffCount; + // 3. by size reduction + const aSizeReduce = a.size * (a.chunks.size - 1); + const bSizeReduce = b.size * (b.chunks.size - 1); + const diffSizeReduce = aSizeReduce - bSizeReduce; + if (diffSizeReduce) return diffSizeReduce; + // 4. by cache group index + const indexDiff = a.cacheGroupIndex - b.cacheGroupIndex; + if (indexDiff) return indexDiff; + // 5. by number of modules (to be able to compare by identifier) + const modulesA = a.modules; + const modulesB = b.modules; + const diff = modulesA.size - modulesB.size; + if (diff) return diff; + // 6. by module identifiers + modulesA.sort(); + modulesB.sort(); + const aI = modulesA[Symbol.iterator](); + const bI = modulesB[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = aI.next(); + const bItem = bI.next(); + if (aItem.done) return 0; + const aModuleIdentifier = aItem.value.identifier(); + const bModuleIdentifier = bItem.value.identifier(); + if (aModuleIdentifier > bModuleIdentifier) return -1; + if (aModuleIdentifier < bModuleIdentifier) return 1; + } +}; + +const compareNumbers = (a, b) => a - b; + +const INITIAL_CHUNK_FILTER = chunk => chunk.canBeInitial(); +const ASYNC_CHUNK_FILTER = chunk => !chunk.canBeInitial(); +const ALL_CHUNK_FILTER = chunk => true; + +module.exports = class SplitChunksPlugin { + constructor(options) { + this.options = SplitChunksPlugin.normalizeOptions(options); + } + + static normalizeOptions(options = {}) { + return { + chunksFilter: SplitChunksPlugin.normalizeChunksFilter( + options.chunks || "all" + ), + minSize: options.minSize || 0, + enforceSizeThreshold: options.enforceSizeThreshold || 0, + maxSize: options.maxSize || 0, + minChunks: options.minChunks || 1, + maxAsyncRequests: options.maxAsyncRequests || 1, + maxInitialRequests: options.maxInitialRequests || 1, + hidePathInfo: options.hidePathInfo || false, + filename: options.filename || undefined, + getCacheGroups: SplitChunksPlugin.normalizeCacheGroups({ + cacheGroups: options.cacheGroups, + name: options.name, + automaticNameDelimiter: options.automaticNameDelimiter, + automaticNameMaxLength: options.automaticNameMaxLength + }), + automaticNameDelimiter: options.automaticNameDelimiter, + automaticNameMaxLength: options.automaticNameMaxLength || 109, + fallbackCacheGroup: SplitChunksPlugin.normalizeFallbackCacheGroup( + options.fallbackCacheGroup || {}, + options + ) + }; + } + + static normalizeName({ + name, + automaticNameDelimiter, + automaticNamePrefix, + automaticNameMaxLength + }) { + if (name === true) { + /** @type {WeakMap<Chunk[], Record<string, string>>} */ + const cache = new WeakMap(); + const fn = (module, chunks, cacheGroup) => { + let cacheEntry = cache.get(chunks); + if (cacheEntry === undefined) { + cacheEntry = {}; + cache.set(chunks, cacheEntry); + } else if (cacheGroup in cacheEntry) { + return cacheEntry[cacheGroup]; + } + const names = chunks.map(c => c.name); + if (!names.every(Boolean)) { + cacheEntry[cacheGroup] = undefined; + return; + } + names.sort(); + const prefix = + typeof automaticNamePrefix === "string" + ? automaticNamePrefix + : cacheGroup; + const namePrefix = prefix ? prefix + automaticNameDelimiter : ""; + let name = namePrefix + names.join(automaticNameDelimiter); + // Filenames and paths can't be too long otherwise an + // ENAMETOOLONG error is raised. If the generated name if too + // long, it is truncated and a hash is appended. The limit has + // been set to 109 to prevent `[name].[chunkhash].[ext]` from + // generating a 256+ character string. + if (name.length > automaticNameMaxLength) { + const hashedFilename = hashFilename(name); + const sliceLength = + automaticNameMaxLength - + (automaticNameDelimiter.length + hashedFilename.length); + name = + name.slice(0, sliceLength) + + automaticNameDelimiter + + hashedFilename; + } + cacheEntry[cacheGroup] = name; + return name; + }; + return fn; + } + if (typeof name === "string") { + const fn = () => { + return name; + }; + return fn; + } + if (typeof name === "function") return name; + } + + static normalizeChunksFilter(chunks) { + if (chunks === "initial") { + return INITIAL_CHUNK_FILTER; + } + if (chunks === "async") { + return ASYNC_CHUNK_FILTER; + } + if (chunks === "all") { + return ALL_CHUNK_FILTER; + } + if (typeof chunks === "function") return chunks; + } + + static normalizeFallbackCacheGroup( + { + minSize = undefined, + maxSize = undefined, + automaticNameDelimiter = undefined + }, + { + minSize: defaultMinSize = undefined, + maxSize: defaultMaxSize = undefined, + automaticNameDelimiter: defaultAutomaticNameDelimiter = undefined + } + ) { + return { + minSize: typeof minSize === "number" ? minSize : defaultMinSize || 0, + maxSize: typeof maxSize === "number" ? maxSize : defaultMaxSize || 0, + automaticNameDelimiter: + automaticNameDelimiter || defaultAutomaticNameDelimiter || "~" + }; + } + + static normalizeCacheGroups({ + cacheGroups, + name, + automaticNameDelimiter, + automaticNameMaxLength + }) { + if (typeof cacheGroups === "function") { + // TODO webpack 5 remove this + if (cacheGroups.length !== 1) { + return module => cacheGroups(module, module.getChunks()); + } + return cacheGroups; + } + if (cacheGroups && typeof cacheGroups === "object") { + const fn = module => { + let results; + for (const key of Object.keys(cacheGroups)) { + let option = cacheGroups[key]; + if (option === false) continue; + if (option instanceof RegExp || typeof option === "string") { + option = { + test: option + }; + } + if (typeof option === "function") { + let result = option(module); + if (result) { + if (results === undefined) results = []; + for (const r of Array.isArray(result) ? result : [result]) { + const result = Object.assign({ key }, r); + if (result.name) result.getName = () => result.name; + if (result.chunks) { + result.chunksFilter = SplitChunksPlugin.normalizeChunksFilter( + result.chunks + ); + } + results.push(result); + } + } + } else if (SplitChunksPlugin.checkTest(option.test, module)) { + if (results === undefined) results = []; + results.push({ + key: key, + priority: option.priority, + getName: + SplitChunksPlugin.normalizeName({ + name: option.name || name, + automaticNameDelimiter: + typeof option.automaticNameDelimiter === "string" + ? option.automaticNameDelimiter + : automaticNameDelimiter, + automaticNamePrefix: option.automaticNamePrefix, + automaticNameMaxLength: + option.automaticNameMaxLength || automaticNameMaxLength + }) || (() => {}), + chunksFilter: SplitChunksPlugin.normalizeChunksFilter( + option.chunks + ), + enforce: option.enforce, + minSize: option.minSize, + enforceSizeThreshold: option.enforceSizeThreshold, + maxSize: option.maxSize, + minChunks: option.minChunks, + maxAsyncRequests: option.maxAsyncRequests, + maxInitialRequests: option.maxInitialRequests, + filename: option.filename, + reuseExistingChunk: option.reuseExistingChunk + }); + } + } + return results; + }; + return fn; + } + const fn = () => {}; + return fn; + } + + static checkTest(test, module) { + if (test === undefined) return true; + if (typeof test === "function") { + if (test.length !== 1) { + return test(module, module.getChunks()); + } + return test(module); + } + if (typeof test === "boolean") return test; + if (typeof test === "string") { + if ( + module.nameForCondition && + module.nameForCondition().startsWith(test) + ) { + return true; + } + for (const chunk of module.chunksIterable) { + if (chunk.name && chunk.name.startsWith(test)) { + return true; + } + } + return false; + } + if (test instanceof RegExp) { + if (module.nameForCondition && test.test(module.nameForCondition())) { + return true; + } + for (const chunk of module.chunksIterable) { + if (chunk.name && test.test(chunk.name)) { + return true; + } + } + return false; + } + return false; + } + + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.thisCompilation.tap("SplitChunksPlugin", compilation => { + let alreadyOptimized = false; + compilation.hooks.unseal.tap("SplitChunksPlugin", () => { + alreadyOptimized = false; + }); + compilation.hooks.optimizeChunksAdvanced.tap( + "SplitChunksPlugin", + chunks => { + if (alreadyOptimized) return; + alreadyOptimized = true; + // Give each selected chunk an index (to create strings from chunks) + const indexMap = new Map(); + let index = 1; + for (const chunk of chunks) { + indexMap.set(chunk, index++); + } + const getKey = chunks => { + return Array.from(chunks, c => indexMap.get(c)) + .sort(compareNumbers) + .join(); + }; + /** @type {Map<string, Set<Chunk>>} */ + const chunkSetsInGraph = new Map(); + for (const module of compilation.modules) { + const chunksKey = getKey(module.chunksIterable); + if (!chunkSetsInGraph.has(chunksKey)) { + chunkSetsInGraph.set(chunksKey, new Set(module.chunksIterable)); + } + } + + // group these set of chunks by count + // to allow to check less sets via isSubset + // (only smaller sets can be subset) + /** @type {Map<number, Array<Set<Chunk>>>} */ + const chunkSetsByCount = new Map(); + for (const chunksSet of chunkSetsInGraph.values()) { + const count = chunksSet.size; + let array = chunkSetsByCount.get(count); + if (array === undefined) { + array = []; + chunkSetsByCount.set(count, array); + } + array.push(chunksSet); + } + + // Create a list of possible combinations + const combinationsCache = new Map(); // Map<string, Set<Chunk>[]> + + const getCombinations = key => { + const chunksSet = chunkSetsInGraph.get(key); + var array = [chunksSet]; + if (chunksSet.size > 1) { + for (const [count, setArray] of chunkSetsByCount) { + // "equal" is not needed because they would have been merge in the first step + if (count < chunksSet.size) { + for (const set of setArray) { + if (isSubset(chunksSet, set)) { + array.push(set); + } + } + } + } + } + return array; + }; + + /** + * @typedef {Object} SelectedChunksResult + * @property {Chunk[]} chunks the list of chunks + * @property {string} key a key of the list + */ + + /** + * @typedef {function(Chunk): boolean} ChunkFilterFunction + */ + + /** @type {WeakMap<Set<Chunk>, WeakMap<ChunkFilterFunction, SelectedChunksResult>>} */ + const selectedChunksCacheByChunksSet = new WeakMap(); + + /** + * get list and key by applying the filter function to the list + * It is cached for performance reasons + * @param {Set<Chunk>} chunks list of chunks + * @param {ChunkFilterFunction} chunkFilter filter function for chunks + * @returns {SelectedChunksResult} list and key + */ + const getSelectedChunks = (chunks, chunkFilter) => { + let entry = selectedChunksCacheByChunksSet.get(chunks); + if (entry === undefined) { + entry = new WeakMap(); + selectedChunksCacheByChunksSet.set(chunks, entry); + } + /** @type {SelectedChunksResult} */ + let entry2 = entry.get(chunkFilter); + if (entry2 === undefined) { + /** @type {Chunk[]} */ + const selectedChunks = []; + for (const chunk of chunks) { + if (chunkFilter(chunk)) selectedChunks.push(chunk); + } + entry2 = { + chunks: selectedChunks, + key: getKey(selectedChunks) + }; + entry.set(chunkFilter, entry2); + } + return entry2; + }; + + /** + * @typedef {Object} ChunksInfoItem + * @property {SortableSet} modules + * @property {TODO} cacheGroup + * @property {number} cacheGroupIndex + * @property {string} name + * @property {number} size + * @property {Set<Chunk>} chunks + * @property {Set<Chunk>} reuseableChunks + * @property {Set<string>} chunksKeys + */ + + // Map a list of chunks to a list of modules + // For the key the chunk "index" is used, the value is a SortableSet of modules + /** @type {Map<string, ChunksInfoItem>} */ + const chunksInfoMap = new Map(); + + /** + * @param {TODO} cacheGroup the current cache group + * @param {number} cacheGroupIndex the index of the cache group of ordering + * @param {Chunk[]} selectedChunks chunks selected for this module + * @param {string} selectedChunksKey a key of selectedChunks + * @param {Module} module the current module + * @returns {void} + */ + const addModuleToChunksInfoMap = ( + cacheGroup, + cacheGroupIndex, + selectedChunks, + selectedChunksKey, + module + ) => { + // Break if minimum number of chunks is not reached + if (selectedChunks.length < cacheGroup.minChunks) return; + // Determine name for split chunk + const name = cacheGroup.getName( + module, + selectedChunks, + cacheGroup.key + ); + // Create key for maps + // When it has a name we use the name as key + // Elsewise we create the key from chunks and cache group key + // This automatically merges equal names + const key = + cacheGroup.key + + (name ? ` name:${name}` : ` chunks:${selectedChunksKey}`); + // Add module to maps + let info = chunksInfoMap.get(key); + if (info === undefined) { + chunksInfoMap.set( + key, + (info = { + modules: new SortableSet(undefined, sortByIdentifier), + cacheGroup, + cacheGroupIndex, + name, + size: 0, + chunks: new Set(), + reuseableChunks: new Set(), + chunksKeys: new Set() + }) + ); + } + info.modules.add(module); + info.size += module.size(); + if (!info.chunksKeys.has(selectedChunksKey)) { + info.chunksKeys.add(selectedChunksKey); + for (const chunk of selectedChunks) { + info.chunks.add(chunk); + } + } + }; + + // Walk through all modules + for (const module of compilation.modules) { + // Get cache group + let cacheGroups = this.options.getCacheGroups(module); + if (!Array.isArray(cacheGroups) || cacheGroups.length === 0) { + continue; + } + + // Prepare some values + const chunksKey = getKey(module.chunksIterable); + let combs = combinationsCache.get(chunksKey); + if (combs === undefined) { + combs = getCombinations(chunksKey); + combinationsCache.set(chunksKey, combs); + } + + let cacheGroupIndex = 0; + for (const cacheGroupSource of cacheGroups) { + const minSize = + cacheGroupSource.minSize !== undefined + ? cacheGroupSource.minSize + : cacheGroupSource.enforce + ? 0 + : this.options.minSize; + const enforceSizeThreshold = + cacheGroupSource.enforceSizeThreshold !== undefined + ? cacheGroupSource.enforceSizeThreshold + : cacheGroupSource.enforce + ? 0 + : this.options.enforceSizeThreshold; + const cacheGroup = { + key: cacheGroupSource.key, + priority: cacheGroupSource.priority || 0, + chunksFilter: + cacheGroupSource.chunksFilter || this.options.chunksFilter, + minSize, + minSizeForMaxSize: + cacheGroupSource.minSize !== undefined + ? cacheGroupSource.minSize + : this.options.minSize, + enforceSizeThreshold, + maxSize: + cacheGroupSource.maxSize !== undefined + ? cacheGroupSource.maxSize + : cacheGroupSource.enforce + ? 0 + : this.options.maxSize, + minChunks: + cacheGroupSource.minChunks !== undefined + ? cacheGroupSource.minChunks + : cacheGroupSource.enforce + ? 1 + : this.options.minChunks, + maxAsyncRequests: + cacheGroupSource.maxAsyncRequests !== undefined + ? cacheGroupSource.maxAsyncRequests + : cacheGroupSource.enforce + ? Infinity + : this.options.maxAsyncRequests, + maxInitialRequests: + cacheGroupSource.maxInitialRequests !== undefined + ? cacheGroupSource.maxInitialRequests + : cacheGroupSource.enforce + ? Infinity + : this.options.maxInitialRequests, + getName: + cacheGroupSource.getName !== undefined + ? cacheGroupSource.getName + : this.options.getName, + filename: + cacheGroupSource.filename !== undefined + ? cacheGroupSource.filename + : this.options.filename, + automaticNameDelimiter: + cacheGroupSource.automaticNameDelimiter !== undefined + ? cacheGroupSource.automaticNameDelimiter + : this.options.automaticNameDelimiter, + reuseExistingChunk: cacheGroupSource.reuseExistingChunk, + _validateSize: minSize > 0, + _conditionalEnforce: enforceSizeThreshold > 0 + }; + // For all combination of chunk selection + for (const chunkCombination of combs) { + // Break if minimum number of chunks is not reached + if (chunkCombination.size < cacheGroup.minChunks) continue; + // Select chunks by configuration + const { + chunks: selectedChunks, + key: selectedChunksKey + } = getSelectedChunks( + chunkCombination, + cacheGroup.chunksFilter + ); + + addModuleToChunksInfoMap( + cacheGroup, + cacheGroupIndex, + selectedChunks, + selectedChunksKey, + module + ); + } + cacheGroupIndex++; + } + } + + // Filter items were size < minSize + for (const pair of chunksInfoMap) { + const info = pair[1]; + if ( + info.cacheGroup._validateSize && + info.size < info.cacheGroup.minSize + ) { + chunksInfoMap.delete(pair[0]); + } + } + + /** @type {Map<Chunk, {minSize: number, maxSize: number, automaticNameDelimiter: string, keys: string[]}>} */ + const maxSizeQueueMap = new Map(); + + while (chunksInfoMap.size > 0) { + // Find best matching entry + let bestEntryKey; + let bestEntry; + for (const pair of chunksInfoMap) { + const key = pair[0]; + const info = pair[1]; + if (bestEntry === undefined) { + bestEntry = info; + bestEntryKey = key; + } else if (compareEntries(bestEntry, info) < 0) { + bestEntry = info; + bestEntryKey = key; + } + } + + const item = bestEntry; + chunksInfoMap.delete(bestEntryKey); + + let chunkName = item.name; + // Variable for the new chunk (lazy created) + /** @type {Chunk} */ + let newChunk; + // When no chunk name, check if we can reuse a chunk instead of creating a new one + let isReused = false; + if (item.cacheGroup.reuseExistingChunk) { + outer: for (const chunk of item.chunks) { + if (chunk.getNumberOfModules() !== item.modules.size) continue; + if (chunk.hasEntryModule()) continue; + for (const module of item.modules) { + if (!chunk.containsModule(module)) continue outer; + } + if (!newChunk || !newChunk.name) { + newChunk = chunk; + } else if ( + chunk.name && + chunk.name.length < newChunk.name.length + ) { + newChunk = chunk; + } else if ( + chunk.name && + chunk.name.length === newChunk.name.length && + chunk.name < newChunk.name + ) { + newChunk = chunk; + } + chunkName = undefined; + isReused = true; + } + } + // Check if maxRequests condition can be fulfilled + + const selectedChunks = Array.from(item.chunks).filter(chunk => { + // skip if we address ourself + return ( + (!chunkName || chunk.name !== chunkName) && chunk !== newChunk + ); + }); + + const enforced = + item.cacheGroup._conditionalEnforce && + item.size >= item.cacheGroup.enforceSizeThreshold; + + // Skip when no chunk selected + if (selectedChunks.length === 0) continue; + + const usedChunks = new Set(selectedChunks); + + // Check if maxRequests condition can be fulfilled + if ( + !enforced && + (Number.isFinite(item.cacheGroup.maxInitialRequests) || + Number.isFinite(item.cacheGroup.maxAsyncRequests)) + ) { + for (const chunk of usedChunks) { + // respect max requests + const maxRequests = chunk.isOnlyInitial() + ? item.cacheGroup.maxInitialRequests + : chunk.canBeInitial() + ? Math.min( + item.cacheGroup.maxInitialRequests, + item.cacheGroup.maxAsyncRequests + ) + : item.cacheGroup.maxAsyncRequests; + if ( + isFinite(maxRequests) && + getRequests(chunk) >= maxRequests + ) { + usedChunks.delete(chunk); + } + } + } + + outer: for (const chunk of usedChunks) { + for (const module of item.modules) { + if (chunk.containsModule(module)) continue outer; + } + usedChunks.delete(chunk); + } + + // Were some (invalid) chunks removed from usedChunks? + // => readd all modules to the queue, as things could have been changed + if (usedChunks.size < selectedChunks.length) { + if (usedChunks.size >= item.cacheGroup.minChunks) { + const chunksArr = Array.from(usedChunks); + for (const module of item.modules) { + addModuleToChunksInfoMap( + item.cacheGroup, + item.cacheGroupIndex, + chunksArr, + getKey(usedChunks), + module + ); + } + } + continue; + } + + // Create the new chunk if not reusing one + if (!isReused) { + newChunk = compilation.addChunk(chunkName); + } + // Walk through all chunks + for (const chunk of usedChunks) { + // Add graph connections for splitted chunk + chunk.split(newChunk); + } + + // Add a note to the chunk + newChunk.chunkReason = isReused + ? "reused as split chunk" + : "split chunk"; + if (item.cacheGroup.key) { + newChunk.chunkReason += ` (cache group: ${item.cacheGroup.key})`; + } + if (chunkName) { + newChunk.chunkReason += ` (name: ${chunkName})`; + // If the chosen name is already an entry point we remove the entry point + const entrypoint = compilation.entrypoints.get(chunkName); + if (entrypoint) { + compilation.entrypoints.delete(chunkName); + entrypoint.remove(); + newChunk.entryModule = undefined; + } + } + if (item.cacheGroup.filename) { + if (!newChunk.isOnlyInitial()) { + throw new Error( + "SplitChunksPlugin: You are trying to set a filename for a chunk which is (also) loaded on demand. " + + "The runtime can only handle loading of chunks which match the chunkFilename schema. " + + "Using a custom filename would fail at runtime. " + + `(cache group: ${item.cacheGroup.key})` + ); + } + newChunk.filenameTemplate = item.cacheGroup.filename; + } + if (!isReused) { + // Add all modules to the new chunk + for (const module of item.modules) { + if (typeof module.chunkCondition === "function") { + if (!module.chunkCondition(newChunk)) continue; + } + // Add module to new chunk + GraphHelpers.connectChunkAndModule(newChunk, module); + // Remove module from used chunks + for (const chunk of usedChunks) { + chunk.removeModule(module); + module.rewriteChunkInReasons(chunk, [newChunk]); + } + } + } else { + // Remove all modules from used chunks + for (const module of item.modules) { + for (const chunk of usedChunks) { + chunk.removeModule(module); + module.rewriteChunkInReasons(chunk, [newChunk]); + } + } + } + + if (item.cacheGroup.maxSize > 0) { + const oldMaxSizeSettings = maxSizeQueueMap.get(newChunk); + maxSizeQueueMap.set(newChunk, { + minSize: Math.max( + oldMaxSizeSettings ? oldMaxSizeSettings.minSize : 0, + item.cacheGroup.minSizeForMaxSize + ), + maxSize: Math.min( + oldMaxSizeSettings ? oldMaxSizeSettings.maxSize : Infinity, + item.cacheGroup.maxSize + ), + automaticNameDelimiter: item.cacheGroup.automaticNameDelimiter, + keys: oldMaxSizeSettings + ? oldMaxSizeSettings.keys.concat(item.cacheGroup.key) + : [item.cacheGroup.key] + }); + } + + // remove all modules from other entries and update size + for (const [key, info] of chunksInfoMap) { + if (isOverlap(info.chunks, usedChunks)) { + // update modules and total size + // may remove it from the map when < minSize + const oldSize = info.modules.size; + for (const module of item.modules) { + info.modules.delete(module); + } + if (info.modules.size !== oldSize) { + if (info.modules.size === 0) { + chunksInfoMap.delete(key); + continue; + } + info.size = getModulesSize(info.modules); + if ( + info.cacheGroup._validateSize && + info.size < info.cacheGroup.minSize + ) { + chunksInfoMap.delete(key); + } + if (info.modules.size === 0) { + chunksInfoMap.delete(key); + } + } + } + } + } + + const incorrectMinMaxSizeSet = new Set(); + + // Make sure that maxSize is fulfilled + for (const chunk of compilation.chunks.slice()) { + const { minSize, maxSize, automaticNameDelimiter, keys } = + maxSizeQueueMap.get(chunk) || this.options.fallbackCacheGroup; + if (!maxSize) continue; + if (minSize > maxSize) { + const warningKey = `${keys && keys.join()} ${minSize} ${maxSize}`; + if (!incorrectMinMaxSizeSet.has(warningKey)) { + incorrectMinMaxSizeSet.add(warningKey); + compilation.warnings.push( + new MinMaxSizeWarning(keys, minSize, maxSize) + ); + } + } + const results = deterministicGroupingForModules({ + maxSize: Math.max(minSize, maxSize), + minSize, + items: chunk.modulesIterable, + getKey(module) { + const ident = contextify( + compilation.options.context, + module.identifier() + ); + const name = module.nameForCondition + ? contextify( + compilation.options.context, + module.nameForCondition() + ) + : ident.replace(/^.*!|\?[^?!]*$/g, ""); + const fullKey = + name + automaticNameDelimiter + hashFilename(ident); + return fullKey.replace(/[\\/?]/g, "_"); + }, + getSize(module) { + return module.size(); + } + }); + results.sort((a, b) => { + if (a.key < b.key) return -1; + if (a.key > b.key) return 1; + return 0; + }); + for (let i = 0; i < results.length; i++) { + const group = results[i]; + const key = this.options.hidePathInfo + ? hashFilename(group.key) + : group.key; + let name = chunk.name + ? chunk.name + automaticNameDelimiter + key + : null; + if (name && name.length > 100) { + name = + name.slice(0, 100) + + automaticNameDelimiter + + hashFilename(name); + } + let newPart; + if (i !== results.length - 1) { + newPart = compilation.addChunk(name); + chunk.split(newPart); + newPart.chunkReason = chunk.chunkReason; + // Add all modules to the new chunk + for (const module of group.items) { + if (typeof module.chunkCondition === "function") { + if (!module.chunkCondition(newPart)) continue; + } + // Add module to new chunk + GraphHelpers.connectChunkAndModule(newPart, module); + // Remove module from used chunks + chunk.removeModule(module); + module.rewriteChunkInReasons(chunk, [newPart]); + } + } else { + // change the chunk to be a part + newPart = chunk; + chunk.name = name; + } + } + } + } + ); + }); + } +}; diff --git a/node_modules/webpack/lib/performance/AssetsOverSizeLimitWarning.js b/node_modules/webpack/lib/performance/AssetsOverSizeLimitWarning.js new file mode 100644 index 0000000..aac8b65 --- /dev/null +++ b/node_modules/webpack/lib/performance/AssetsOverSizeLimitWarning.js @@ -0,0 +1,30 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); +const SizeFormatHelpers = require("../SizeFormatHelpers"); + +module.exports = class AssetsOverSizeLimitWarning extends WebpackError { + constructor(assetsOverSizeLimit, assetLimit) { + const assetLists = assetsOverSizeLimit + .map( + asset => + `\n ${asset.name} (${SizeFormatHelpers.formatSize(asset.size)})` + ) + .join(""); + + super(`asset size limit: The following asset(s) exceed the recommended size limit (${SizeFormatHelpers.formatSize( + assetLimit + )}). +This can impact web performance. +Assets: ${assetLists}`); + + this.name = "AssetsOverSizeLimitWarning"; + this.assets = assetsOverSizeLimit; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/performance/EntrypointsOverSizeLimitWarning.js b/node_modules/webpack/lib/performance/EntrypointsOverSizeLimitWarning.js new file mode 100644 index 0000000..3c29553 --- /dev/null +++ b/node_modules/webpack/lib/performance/EntrypointsOverSizeLimitWarning.js @@ -0,0 +1,30 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); +const SizeFormatHelpers = require("../SizeFormatHelpers"); + +module.exports = class EntrypointsOverSizeLimitWarning extends WebpackError { + constructor(entrypoints, entrypointLimit) { + const entrypointList = entrypoints + .map( + entrypoint => + `\n ${entrypoint.name} (${SizeFormatHelpers.formatSize( + entrypoint.size + )})\n${entrypoint.files.map(asset => ` ${asset}`).join("\n")}` + ) + .join(""); + super(`entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (${SizeFormatHelpers.formatSize( + entrypointLimit + )}). This can impact web performance. +Entrypoints:${entrypointList}\n`); + + this.name = "EntrypointsOverSizeLimitWarning"; + this.entrypoints = entrypoints; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/performance/NoAsyncChunksWarning.js b/node_modules/webpack/lib/performance/NoAsyncChunksWarning.js new file mode 100644 index 0000000..c64475f --- /dev/null +++ b/node_modules/webpack/lib/performance/NoAsyncChunksWarning.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); + +module.exports = class NoAsyncChunksWarning extends WebpackError { + constructor() { + super( + "webpack performance recommendations: \n" + + "You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.\n" + + "For more info visit https://webpack.js.org/guides/code-splitting/" + ); + + this.name = "NoAsyncChunksWarning"; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/performance/SizeLimitsPlugin.js b/node_modules/webpack/lib/performance/SizeLimitsPlugin.js new file mode 100644 index 0000000..7b45740 --- /dev/null +++ b/node_modules/webpack/lib/performance/SizeLimitsPlugin.js @@ -0,0 +1,125 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Sean Larkin @thelarkinn +*/ +"use strict"; +const EntrypointsOverSizeLimitWarning = require("./EntrypointsOverSizeLimitWarning"); +const AssetsOverSizeLimitWarning = require("./AssetsOverSizeLimitWarning"); +const NoAsyncChunksWarning = require("./NoAsyncChunksWarning"); + +/** @typedef {import("../Compiler")} Compiler */ +/** @typedef {import("../Entrypoint")} Entrypoint */ + +module.exports = class SizeLimitsPlugin { + constructor(options) { + this.hints = options.hints; + this.maxAssetSize = options.maxAssetSize; + this.maxEntrypointSize = options.maxEntrypointSize; + this.assetFilter = options.assetFilter; + } + + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ + apply(compiler) { + const entrypointSizeLimit = this.maxEntrypointSize; + const assetSizeLimit = this.maxAssetSize; + const hints = this.hints; + const assetFilter = + this.assetFilter || ((name, source, info) => !info.development); + + compiler.hooks.afterEmit.tap("SizeLimitsPlugin", compilation => { + const warnings = []; + + /** + * @param {Entrypoint} entrypoint an entrypoint + * @returns {number} the size of the entrypoint + */ + const getEntrypointSize = entrypoint => + entrypoint.getFiles().reduce((currentSize, file) => { + const asset = compilation.getAsset(file); + if ( + asset && + assetFilter(asset.name, asset.source, asset.info) && + asset.source + ) { + return currentSize + (asset.info.size || asset.source.size()); + } + + return currentSize; + }, 0); + + const assetsOverSizeLimit = []; + for (const { name, source, info } of compilation.getAssets()) { + if (!assetFilter(name, source, info) || !source) { + continue; + } + + const size = info.size || source.size(); + if (size > assetSizeLimit) { + assetsOverSizeLimit.push({ + name, + size + }); + /** @type {any} */ (source).isOverSizeLimit = true; + } + } + + const fileFilter = name => { + const asset = compilation.getAsset(name); + return asset && assetFilter(asset.name, asset.source, asset.info); + }; + + const entrypointsOverLimit = []; + for (const [name, entry] of compilation.entrypoints) { + const size = getEntrypointSize(entry); + + if (size > entrypointSizeLimit) { + entrypointsOverLimit.push({ + name: name, + size: size, + files: entry.getFiles().filter(fileFilter) + }); + /** @type {any} */ (entry).isOverSizeLimit = true; + } + } + + if (hints) { + // 1. Individual Chunk: Size < 250kb + // 2. Collective Initial Chunks [entrypoint] (Each Set?): Size < 250kb + // 3. No Async Chunks + // if !1, then 2, if !2 return + if (assetsOverSizeLimit.length > 0) { + warnings.push( + new AssetsOverSizeLimitWarning(assetsOverSizeLimit, assetSizeLimit) + ); + } + if (entrypointsOverLimit.length > 0) { + warnings.push( + new EntrypointsOverSizeLimitWarning( + entrypointsOverLimit, + entrypointSizeLimit + ) + ); + } + + if (warnings.length > 0) { + const hasAsyncChunks = + compilation.chunks.filter(chunk => !chunk.canBeInitial()).length > + 0; + + if (!hasAsyncChunks) { + warnings.push(new NoAsyncChunksWarning()); + } + + if (hints === "error") { + compilation.errors.push(...warnings); + } else { + compilation.warnings.push(...warnings); + } + } + } + }); + } +}; diff --git a/node_modules/webpack/lib/util/LazyBucketSortedSet.js b/node_modules/webpack/lib/util/LazyBucketSortedSet.js new file mode 100644 index 0000000..61d3d3f --- /dev/null +++ b/node_modules/webpack/lib/util/LazyBucketSortedSet.js @@ -0,0 +1,235 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const SortableSet = require("./SortableSet"); + +/** + * @template T + * @template K + * Multi layer bucket sorted set + * Supports adding non-existing items (DO NOT ADD ITEM TWICE) + * Supports removing exiting items (DO NOT REMOVE ITEM NOT IN SET) + * Supports popping the first items according to defined order + * Supports iterating all items without order + * Supports updating an item in an efficient way + * Supports size property, which is the number of items + * Items are lazy partially sorted when needed + */ +class LazyBucketSortedSet { + /** + * @param {function(T): K} getKey function to get key from item + * @param {function(K, K): number} comparator comparator to sort keys + * @param {...((function(T): any) | (function(any, any): number))} args more pairs of getKey and comparator plus optional final comparator for the last layer + */ + constructor(getKey, comparator, ...args) { + this._getKey = getKey; + this._innerArgs = args; + this._leaf = args.length <= 1; + this._keys = new SortableSet(undefined, comparator); + /** @type {Map<K, LazyBucketSortedSet<T, any> | SortableSet<T>>} */ + this._map = new Map(); + this._unsortedItems = new Set(); + this.size = 0; + } + + /** + * @param {T} item an item + * @returns {void} + */ + add(item) { + this.size++; + this._unsortedItems.add(item); + } + + /** + * @param {K} key key of item + * @param {T} item the item + * @returns {void} + */ + _addInternal(key, item) { + let entry = this._map.get(key); + if (entry === undefined) { + entry = this._leaf + ? new SortableSet(undefined, this._innerArgs[0]) + : new /** @type {any} */ (LazyBucketSortedSet)(...this._innerArgs); + this._keys.add(key); + this._map.set(key, entry); + } + entry.add(item); + } + + /** + * @param {T} item an item + * @returns {void} + */ + delete(item) { + this.size--; + if (this._unsortedItems.has(item)) { + this._unsortedItems.delete(item); + return; + } + const key = this._getKey(item); + const entry = this._map.get(key); + entry.delete(item); + if (entry.size === 0) { + this._deleteKey(key); + } + } + + /** + * @param {K} key key to be removed + * @returns {void} + */ + _deleteKey(key) { + this._keys.delete(key); + this._map.delete(key); + } + + /** + * @returns {T | undefined} an item + */ + popFirst() { + if (this.size === 0) return undefined; + this.size--; + if (this._unsortedItems.size > 0) { + for (const item of this._unsortedItems) { + const key = this._getKey(item); + this._addInternal(key, item); + } + this._unsortedItems.clear(); + } + this._keys.sort(); + const key = this._keys.values().next().value; + const entry = this._map.get(key); + if (this._leaf) { + const leafEntry = /** @type {SortableSet<T>} */ (entry); + leafEntry.sort(); + const item = leafEntry.values().next().value; + leafEntry.delete(item); + if (leafEntry.size === 0) { + this._deleteKey(key); + } + return item; + } else { + const nodeEntry = /** @type {LazyBucketSortedSet<T, any>} */ (entry); + const item = nodeEntry.popFirst(); + if (nodeEntry.size === 0) { + this._deleteKey(key); + } + return item; + } + } + + /** + * @param {T} item to be updated item + * @returns {function(true=): void} finish update + */ + startUpdate(item) { + if (this._unsortedItems.has(item)) { + return remove => { + if (remove) { + this._unsortedItems.delete(item); + this.size--; + return; + } + }; + } + const key = this._getKey(item); + if (this._leaf) { + const oldEntry = /** @type {SortableSet<T>} */ (this._map.get(key)); + return remove => { + if (remove) { + this.size--; + oldEntry.delete(item); + if (oldEntry.size === 0) { + this._deleteKey(key); + } + return; + } + const newKey = this._getKey(item); + if (key === newKey) { + // This flags the sortable set as unordered + oldEntry.add(item); + } else { + oldEntry.delete(item); + if (oldEntry.size === 0) { + this._deleteKey(key); + } + this._addInternal(newKey, item); + } + }; + } else { + const oldEntry = /** @type {LazyBucketSortedSet<T, any>} */ (this._map.get( + key + )); + const finishUpdate = oldEntry.startUpdate(item); + return remove => { + if (remove) { + this.size--; + finishUpdate(true); + if (oldEntry.size === 0) { + this._deleteKey(key); + } + return; + } + const newKey = this._getKey(item); + if (key === newKey) { + finishUpdate(); + } else { + finishUpdate(true); + if (oldEntry.size === 0) { + this._deleteKey(key); + } + this._addInternal(newKey, item); + } + }; + } + } + + /** + * @param {Iterator<T>[]} iterators list of iterators to append to + * @returns {void} + */ + _appendIterators(iterators) { + if (this._unsortedItems.size > 0) + iterators.push(this._unsortedItems[Symbol.iterator]()); + for (const key of this._keys) { + const entry = this._map.get(key); + if (this._leaf) { + const leafEntry = /** @type {SortableSet<T>} */ (entry); + const iterator = leafEntry[Symbol.iterator](); + iterators.push(iterator); + } else { + const nodeEntry = /** @type {LazyBucketSortedSet<T, any>} */ (entry); + nodeEntry._appendIterators(iterators); + } + } + } + + /** + * @returns {Iterator<T>} the iterator + */ + [Symbol.iterator]() { + const iterators = []; + this._appendIterators(iterators); + iterators.reverse(); + let currentIterator = iterators.pop(); + return { + next: () => { + const res = currentIterator.next(); + if (res.done) { + if (iterators.length === 0) return res; + currentIterator = iterators.pop(); + return currentIterator.next(); + } + return res; + } + }; + } +} + +module.exports = LazyBucketSortedSet; diff --git a/node_modules/webpack/lib/util/Queue.js b/node_modules/webpack/lib/util/Queue.js new file mode 100644 index 0000000..6615e9f --- /dev/null +++ b/node_modules/webpack/lib/util/Queue.js @@ -0,0 +1,46 @@ +"use strict"; + +/** + * @template T + */ +class Queue { + /** + * @param {Iterable<T>=} items The initial elements. + */ + constructor(items) { + /** @private @type {Set<T>} */ + this.set = new Set(items); + /** @private @type {Iterator<T>} */ + this.iterator = this.set[Symbol.iterator](); + } + + /** + * Returns the number of elements in this queue. + * @returns {number} The number of elements in this queue. + */ + get length() { + return this.set.size; + } + + /** + * Appends the specified element to this queue. + * @param {T} item The element to add. + * @returns {void} + */ + enqueue(item) { + this.set.add(item); + } + + /** + * Retrieves and removes the head of this queue. + * @returns {T | undefined} The head of the queue of `undefined` if this queue is empty. + */ + dequeue() { + const result = this.iterator.next(); + if (result.done) return undefined; + this.set.delete(result.value); + return result.value; + } +} + +module.exports = Queue; diff --git a/node_modules/webpack/lib/util/Semaphore.js b/node_modules/webpack/lib/util/Semaphore.js new file mode 100644 index 0000000..d6c8766 --- /dev/null +++ b/node_modules/webpack/lib/util/Semaphore.js @@ -0,0 +1,53 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class Semaphore { + /** + * Creates an instance of Semaphore. + * + * @param {number} available the amount available number of "tasks" + * in the Semaphore + */ + constructor(available) { + this.available = available; + /** @type {(function(): void)[]} */ + this.waiters = []; + /** @private */ + this._continue = this._continue.bind(this); + } + + /** + * @param {function(): void} callback function block to capture and run + * @returns {void} + */ + acquire(callback) { + if (this.available > 0) { + this.available--; + callback(); + } else { + this.waiters.push(callback); + } + } + + release() { + this.available++; + if (this.waiters.length > 0) { + process.nextTick(this._continue); + } + } + + _continue() { + if (this.available > 0) { + if (this.waiters.length > 0) { + this.available--; + const callback = this.waiters.pop(); + callback(); + } + } + } +} + +module.exports = Semaphore; diff --git a/node_modules/webpack/lib/util/SetHelpers.js b/node_modules/webpack/lib/util/SetHelpers.js new file mode 100644 index 0000000..96c063c --- /dev/null +++ b/node_modules/webpack/lib/util/SetHelpers.js @@ -0,0 +1,48 @@ +"use strict"; + +/** + * intersect creates Set containing the intersection of elements between all sets + * @param {Set[]} sets an array of sets being checked for shared elements + * @returns {Set<TODO>} returns a new Set containing the intersecting items + */ +const intersect = sets => { + if (sets.length === 0) return new Set(); + if (sets.length === 1) return new Set(sets[0]); + let minSize = Infinity; + let minIndex = -1; + for (let i = 0; i < sets.length; i++) { + const size = sets[i].size; + if (size < minSize) { + minIndex = i; + minSize = size; + } + } + const current = new Set(sets[minIndex]); + for (let i = 0; i < sets.length; i++) { + if (i === minIndex) continue; + const set = sets[i]; + for (const item of current) { + if (!set.has(item)) { + current.delete(item); + } + } + } + return current; +}; + +/** + * Checks if a set is the subset of another set + * @param {Set<TODO>} bigSet a Set which contains the original elements to compare against + * @param {Set<TODO>} smallSet the set whos elements might be contained inside of bigSet + * @returns {boolean} returns true if smallSet contains all elements inside of the bigSet + */ +const isSubset = (bigSet, smallSet) => { + if (bigSet.size < smallSet.size) return false; + for (const item of smallSet) { + if (!bigSet.has(item)) return false; + } + return true; +}; + +exports.intersect = intersect; +exports.isSubset = isSubset; diff --git a/node_modules/webpack/lib/util/SortableSet.js b/node_modules/webpack/lib/util/SortableSet.js new file mode 100644 index 0000000..44b692f --- /dev/null +++ b/node_modules/webpack/lib/util/SortableSet.js @@ -0,0 +1,140 @@ +"use strict"; + +/** + * A subset of Set that offers sorting functionality + * @template T item type in set + * @extends {Set<T>} + */ +class SortableSet extends Set { + /** + * Create a new sortable set + * @param {Iterable<T>=} initialIterable The initial iterable value + * @typedef {function(T, T): number} SortFunction + * @param {SortFunction=} defaultSort Default sorting function + */ + constructor(initialIterable, defaultSort) { + super(initialIterable); + /** @private @type {function(T, T): number}} */ + this._sortFn = defaultSort; + /** @private @type {function(T, T): number} | null} */ + this._lastActiveSortFn = null; + /** @private @type {Map<Function, T[]> | undefined} */ + this._cache = undefined; + /** @private @type {Map<Function, T[]|string|number> | undefined} */ + this._cacheOrderIndependent = undefined; + } + + /** + * @param {T} value value to add to set + * @returns {this} returns itself + */ + add(value) { + this._lastActiveSortFn = null; + this._invalidateCache(); + this._invalidateOrderedCache(); + super.add(value); + return this; + } + + /** + * @param {T} value value to delete + * @returns {boolean} true if value existed in set, false otherwise + */ + delete(value) { + this._invalidateCache(); + this._invalidateOrderedCache(); + return super.delete(value); + } + + /** + * @returns {void} + */ + clear() { + this._invalidateCache(); + this._invalidateOrderedCache(); + return super.clear(); + } + + /** + * Sort with a comparer function + * @param {SortFunction} sortFn Sorting comparer function + * @returns {void} + */ + sortWith(sortFn) { + if (this.size <= 1 || sortFn === this._lastActiveSortFn) { + // already sorted - nothing to do + return; + } + + const sortedArray = Array.from(this).sort(sortFn); + super.clear(); + for (let i = 0; i < sortedArray.length; i += 1) { + super.add(sortedArray[i]); + } + this._lastActiveSortFn = sortFn; + this._invalidateCache(); + } + + sort() { + this.sortWith(this._sortFn); + } + + /** + * Get data from cache + * @param {function(SortableSet<T>): T[]} fn function to calculate value + * @returns {T[]} returns result of fn(this), cached until set changes + */ + getFromCache(fn) { + if (this._cache === undefined) { + this._cache = new Map(); + } else { + const data = this._cache.get(fn); + if (data !== undefined) { + return data; + } + } + const newData = fn(this); + this._cache.set(fn, newData); + return newData; + } + + /** + * @param {function(SortableSet<T>): string|number|T[]} fn function to calculate value + * @returns {any} returns result of fn(this), cached until set changes + */ + getFromUnorderedCache(fn) { + if (this._cacheOrderIndependent === undefined) { + this._cacheOrderIndependent = new Map(); + } else { + const data = this._cacheOrderIndependent.get(fn); + if (data !== undefined) { + return data; + } + } + const newData = fn(this); + this._cacheOrderIndependent.set(fn, newData); + return newData; + } + + /** + * @private + * @returns {void} + */ + _invalidateCache() { + if (this._cache !== undefined) { + this._cache.clear(); + } + } + + /** + * @private + * @returns {void} + */ + _invalidateOrderedCache() { + if (this._cacheOrderIndependent !== undefined) { + this._cacheOrderIndependent.clear(); + } + } +} + +module.exports = SortableSet; diff --git a/node_modules/webpack/lib/util/StackedSetMap.js b/node_modules/webpack/lib/util/StackedSetMap.js new file mode 100644 index 0000000..1805155 --- /dev/null +++ b/node_modules/webpack/lib/util/StackedSetMap.js @@ -0,0 +1,142 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const util = require("util"); + +const TOMBSTONE = {}; +const UNDEFINED_MARKER = {}; + +class StackedSetMap { + constructor(parentStack) { + this.stack = parentStack === undefined ? [] : parentStack.slice(); + this.map = new Map(); + this.stack.push(this.map); + } + + add(item) { + this.map.set(item, true); + } + + set(item, value) { + this.map.set(item, value === undefined ? UNDEFINED_MARKER : value); + } + + delete(item) { + if (this.stack.length > 1) { + this.map.set(item, TOMBSTONE); + } else { + this.map.delete(item); + } + } + + has(item) { + const topValue = this.map.get(item); + if (topValue !== undefined) return topValue !== TOMBSTONE; + if (this.stack.length > 1) { + for (var i = this.stack.length - 2; i >= 0; i--) { + const value = this.stack[i].get(item); + if (value !== undefined) { + this.map.set(item, value); + return value !== TOMBSTONE; + } + } + this.map.set(item, TOMBSTONE); + } + return false; + } + + get(item) { + const topValue = this.map.get(item); + if (topValue !== undefined) { + return topValue === TOMBSTONE || topValue === UNDEFINED_MARKER + ? undefined + : topValue; + } + if (this.stack.length > 1) { + for (var i = this.stack.length - 2; i >= 0; i--) { + const value = this.stack[i].get(item); + if (value !== undefined) { + this.map.set(item, value); + return value === TOMBSTONE || value === UNDEFINED_MARKER + ? undefined + : value; + } + } + this.map.set(item, TOMBSTONE); + } + return undefined; + } + + _compress() { + if (this.stack.length === 1) return; + this.map = new Map(); + for (const data of this.stack) { + for (const pair of data) { + if (pair[1] === TOMBSTONE) { + this.map.delete(pair[0]); + } else { + this.map.set(pair[0], pair[1]); + } + } + } + this.stack = [this.map]; + } + + asArray() { + this._compress(); + return Array.from(this.map.entries(), pair => pair[0]); + } + + asSet() { + return new Set(this.asArray()); + } + + asPairArray() { + this._compress(); + return Array.from(this.map.entries(), pair => + /** @type {[TODO, TODO]} */ (pair[1] === UNDEFINED_MARKER + ? [pair[0], undefined] + : pair) + ); + } + + asMap() { + return new Map(this.asPairArray()); + } + + get size() { + this._compress(); + return this.map.size; + } + + createChild() { + return new StackedSetMap(this.stack); + } + + get length() { + throw new Error("This is no longer an Array"); + } + + set length(value) { + throw new Error("This is no longer an Array"); + } +} + +// TODO remove in webpack 5 +StackedSetMap.prototype.push = util.deprecate( + /** + * @deprecated + * @this {StackedSetMap} + * @param {any} item Item to add + * @returns {void} + */ + function(item) { + this.add(item); + }, + "This is no longer an Array: Use add instead." +); + +module.exports = StackedSetMap; diff --git a/node_modules/webpack/lib/util/TrackingSet.js b/node_modules/webpack/lib/util/TrackingSet.js new file mode 100644 index 0000000..b52a440 --- /dev/null +++ b/node_modules/webpack/lib/util/TrackingSet.js @@ -0,0 +1,35 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +module.exports = class TrackingSet { + constructor(set) { + this.set = set; + this.set2 = new Set(); + this.stack = set.stack; + } + + add(item) { + this.set2.add(item); + return this.set.add(item); + } + + delete(item) { + this.set2.delete(item); + return this.set.delete(item); + } + + has(item) { + return this.set.has(item); + } + + createChild() { + return this.set.createChild(); + } + + getAddedItems() { + return this.set2; + } +}; diff --git a/node_modules/webpack/lib/util/cachedMerge.js b/node_modules/webpack/lib/util/cachedMerge.js new file mode 100644 index 0000000..124f647 --- /dev/null +++ b/node_modules/webpack/lib/util/cachedMerge.js @@ -0,0 +1,35 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const mergeCache = new WeakMap(); + +/** + * Merges two given objects and caches the result to avoid computation if same objects passed as arguments again. + * @example + * // performs Object.assign(first, second), stores the result in WeakMap and returns result + * cachedMerge({a: 1}, {a: 2}) + * {a: 2} + * // when same arguments passed, gets the result from WeakMap and returns it. + * cachedMerge({a: 1}, {a: 2}) + * {a: 2} + * @param {object} first first object + * @param {object} second second object + * @returns {object} merged object of first and second object + */ +const cachedMerge = (first, second) => { + let innerCache = mergeCache.get(first); + if (innerCache === undefined) { + innerCache = new WeakMap(); + mergeCache.set(first, innerCache); + } + const prevMerge = innerCache.get(second); + if (prevMerge !== undefined) return prevMerge; + const newMerge = Object.assign({}, first, second); + innerCache.set(second, newMerge); + return newMerge; +}; + +module.exports = cachedMerge; diff --git a/node_modules/webpack/lib/util/cleverMerge.js b/node_modules/webpack/lib/util/cleverMerge.js new file mode 100644 index 0000000..23060ce --- /dev/null +++ b/node_modules/webpack/lib/util/cleverMerge.js @@ -0,0 +1,77 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const mergeCache = new WeakMap(); + +/** + * Merges two given objects and caches the result to avoid computation if same objects passed as arguments again. + * @example + * // performs cleverMerge(first, second), stores the result in WeakMap and returns result + * cachedCleverMerge({a: 1}, {a: 2}) + * {a: 2} + * // when same arguments passed, gets the result from WeakMap and returns it. + * cachedCleverMerge({a: 1}, {a: 2}) + * {a: 2} + * @param {object} first first object + * @param {object} second second object + * @returns {object} merged object of first and second object + */ +const cachedCleverMerge = (first, second) => { + let innerCache = mergeCache.get(first); + if (innerCache === undefined) { + innerCache = new WeakMap(); + mergeCache.set(first, innerCache); + } + const prevMerge = innerCache.get(second); + if (prevMerge !== undefined) return prevMerge; + const newMerge = cleverMerge(first, second); + innerCache.set(second, newMerge); + return newMerge; +}; + +/** + * Merges two objects. Objects are not deeply merged. + * TODO webpack 5: merge objects deeply clever. + * Arrays might reference the old value with "..." + * @param {object} first first object + * @param {object} second second object + * @returns {object} merged object of first and second object + */ +const cleverMerge = (first, second) => { + const newObject = Object.assign({}, first); + for (const key of Object.keys(second)) { + if (!(key in newObject)) { + newObject[key] = second[key]; + continue; + } + const secondValue = second[key]; + if (!Array.isArray(secondValue)) { + newObject[key] = secondValue; + continue; + } + const firstValue = newObject[key]; + if (Array.isArray(firstValue)) { + const newArray = []; + for (const item of secondValue) { + if (item === "...") { + for (const item of firstValue) { + newArray.push(item); + } + } else { + newArray.push(item); + } + } + newObject[key] = newArray; + } else { + newObject[key] = secondValue; + } + } + return newObject; +}; + +exports.cachedCleverMerge = cachedCleverMerge; +exports.cleverMerge = cleverMerge; diff --git a/node_modules/webpack/lib/util/createHash.js b/node_modules/webpack/lib/util/createHash.js new file mode 100644 index 0000000..64de510 --- /dev/null +++ b/node_modules/webpack/lib/util/createHash.js @@ -0,0 +1,137 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const AbstractMethodError = require("../AbstractMethodError"); + +const BULK_SIZE = 1000; + +class Hash { + /** + * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding} + * @param {string|Buffer} data data + * @param {string=} inputEncoding data encoding + * @returns {this} updated hash + */ + update(data, inputEncoding) { + throw new AbstractMethodError(); + } + + /** + * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding} + * @param {string=} encoding encoding of the return value + * @returns {string|Buffer} digest + */ + digest(encoding) { + throw new AbstractMethodError(); + } +} + +exports.Hash = Hash; +/** @typedef {typeof Hash} HashConstructor */ + +class BulkUpdateDecorator extends Hash { + /** + * @param {Hash} hash hash + */ + constructor(hash) { + super(); + this.hash = hash; + this.buffer = ""; + } + + /** + * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding} + * @param {string|Buffer} data data + * @param {string=} inputEncoding data encoding + * @returns {this} updated hash + */ + update(data, inputEncoding) { + if ( + inputEncoding !== undefined || + typeof data !== "string" || + data.length > BULK_SIZE + ) { + if (this.buffer.length > 0) { + this.hash.update(this.buffer); + this.buffer = ""; + } + this.hash.update(data, inputEncoding); + } else { + this.buffer += data; + if (this.buffer.length > BULK_SIZE) { + this.hash.update(this.buffer); + this.buffer = ""; + } + } + return this; + } + + /** + * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding} + * @param {string=} encoding encoding of the return value + * @returns {string|Buffer} digest + */ + digest(encoding) { + if (this.buffer.length > 0) { + this.hash.update(this.buffer); + } + var digestResult = this.hash.digest(encoding); + return typeof digestResult === "string" + ? digestResult + : digestResult.toString(); + } +} + +/** + * istanbul ignore next + */ +class DebugHash extends Hash { + constructor() { + super(); + this.string = ""; + } + + /** + * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding} + * @param {string|Buffer} data data + * @param {string=} inputEncoding data encoding + * @returns {this} updated hash + */ + update(data, inputEncoding) { + if (typeof data !== "string") data = data.toString("utf-8"); + this.string += data; + return this; + } + + /** + * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding} + * @param {string=} encoding encoding of the return value + * @returns {string|Buffer} digest + */ + digest(encoding) { + return this.string.replace(/[^a-z0-9]+/gi, m => + Buffer.from(m).toString("hex") + ); + } +} + +/** + * Creates a hash by name or function + * @param {string | HashConstructor} algorithm the algorithm name or a constructor creating a hash + * @returns {Hash} the hash + */ +module.exports = algorithm => { + if (typeof algorithm === "function") { + return new BulkUpdateDecorator(new algorithm()); + } + switch (algorithm) { + // TODO add non-cryptographic algorithm here + case "debug": + return new DebugHash(); + default: + return new BulkUpdateDecorator(require("crypto").createHash(algorithm)); + } +}; diff --git a/node_modules/webpack/lib/util/deterministicGrouping.js b/node_modules/webpack/lib/util/deterministicGrouping.js new file mode 100644 index 0000000..825e4bc --- /dev/null +++ b/node_modules/webpack/lib/util/deterministicGrouping.js @@ -0,0 +1,274 @@ +"use strict"; + +// Simulations show these probabilities for a single change +// 93.1% that one group is invalidated +// 4.8% that two groups are invalidated +// 1.1% that 3 groups are invalidated +// 0.1% that 4 or more groups are invalidated +// +// And these for removing/adding 10 lexically adjacent files +// 64.5% that one group is invalidated +// 24.8% that two groups are invalidated +// 7.8% that 3 groups are invalidated +// 2.7% that 4 or more groups are invalidated +// +// And these for removing/adding 3 random files +// 0% that one group is invalidated +// 3.7% that two groups are invalidated +// 80.8% that 3 groups are invalidated +// 12.3% that 4 groups are invalidated +// 3.2% that 5 or more groups are invalidated + +/** + * + * @param {string} a key + * @param {string} b key + * @returns {number} the similarity as number + */ +const similarity = (a, b) => { + const l = Math.min(a.length, b.length); + let dist = 0; + for (let i = 0; i < l; i++) { + const ca = a.charCodeAt(i); + const cb = b.charCodeAt(i); + dist += Math.max(0, 10 - Math.abs(ca - cb)); + } + return dist; +}; + +/** + * @param {string} a key + * @param {string} b key + * @returns {string} the common part and a single char for the difference + */ +const getName = (a, b) => { + const l = Math.min(a.length, b.length); + let r = ""; + for (let i = 0; i < l; i++) { + const ca = a.charAt(i); + const cb = b.charAt(i); + r += ca; + if (ca === cb) { + continue; + } + return r; + } + return a; +}; + +/** + * @template T + */ +class Node { + /** + * @param {T} item item + * @param {string} key key + * @param {number} size size + */ + constructor(item, key, size) { + this.item = item; + this.key = key; + this.size = size; + } +} + +/** + * @template T + */ +class Group { + /** + * @param {Node<T>[]} nodes nodes + * @param {number[]} similarities similarities between the nodes (length = nodes.length - 1) + */ + constructor(nodes, similarities) { + this.nodes = nodes; + this.similarities = similarities; + this.size = nodes.reduce((size, node) => size + node.size, 0); + /** @type {string} */ + this.key = undefined; + } +} + +/** + * @template T + * @typedef {Object} GroupedItems<T> + * @property {string} key + * @property {T[]} items + * @property {number} size + */ + +/** + * @template T + * @typedef {Object} Options + * @property {number} maxSize maximum size of a group + * @property {number} minSize minimum size of a group (preferred over maximum size) + * @property {Iterable<T>} items a list of items + * @property {function(T): number} getSize function to get size of an item + * @property {function(T): string} getKey function to get the key of an item + */ + +/** + * @template T + * @param {Options<T>} options options object + * @returns {GroupedItems<T>[]} grouped items + */ +module.exports = ({ maxSize, minSize, items, getSize, getKey }) => { + /** @type {Group<T>[]} */ + const result = []; + + const nodes = Array.from( + items, + item => new Node(item, getKey(item), getSize(item)) + ); + + /** @type {Node<T>[]} */ + const initialNodes = []; + + // lexically ordering of keys + nodes.sort((a, b) => { + if (a.key < b.key) return -1; + if (a.key > b.key) return 1; + return 0; + }); + + // return nodes bigger than maxSize directly as group + for (const node of nodes) { + if (node.size >= maxSize) { + result.push(new Group([node], [])); + } else { + initialNodes.push(node); + } + } + + if (initialNodes.length > 0) { + // calculate similarities between lexically adjacent nodes + /** @type {number[]} */ + const similarities = []; + for (let i = 1; i < initialNodes.length; i++) { + const a = initialNodes[i - 1]; + const b = initialNodes[i]; + similarities.push(similarity(a.key, b.key)); + } + + const initialGroup = new Group(initialNodes, similarities); + + if (initialGroup.size < minSize) { + // We hit an edgecase where the working set is already smaller than minSize + // We merge it with the smallest result node to keep minSize intact + if (result.length > 0) { + const smallestGroup = result.reduce((min, group) => + min.size > group.size ? group : min + ); + for (const node of initialGroup.nodes) smallestGroup.nodes.push(node); + smallestGroup.nodes.sort((a, b) => { + if (a.key < b.key) return -1; + if (a.key > b.key) return 1; + return 0; + }); + } else { + // There are no other nodes + // We use all nodes and have to accept that it's smaller than minSize + result.push(initialGroup); + } + } else { + const queue = [initialGroup]; + + while (queue.length) { + const group = queue.pop(); + // only groups bigger than maxSize need to be splitted + if (group.size < maxSize) { + result.push(group); + continue; + } + + // find unsplittable area from left and right + // going minSize from left and right + // at least one node need to be included otherwise we get stuck + let left = 0; + let leftSize = 0; + while (leftSize <= minSize) { + leftSize += group.nodes[left].size; + left++; + } + let right = group.nodes.length - 1; + let rightSize = 0; + while (rightSize <= minSize) { + rightSize += group.nodes[right].size; + right--; + } + + if (left - 1 > right) { + // can't split group while holding minSize + // because minSize is preferred of maxSize we return + // the group here even while it's too big + // To avoid this make sure maxSize > minSize * 3 + result.push(group); + continue; + } + if (left <= right) { + // when there is a area between left and right + // we look for best split point + // we split at the minimum similarity + // here key space is separated the most + let best = left - 1; + let bestSimilarity = group.similarities[best]; + for (let i = left; i <= right; i++) { + const similarity = group.similarities[i]; + if (similarity < bestSimilarity) { + best = i; + bestSimilarity = similarity; + } + } + left = best + 1; + right = best; + } + + // create two new groups for left and right area + // and queue them up + const rightNodes = [group.nodes[right + 1]]; + /** @type {number[]} */ + const rightSimilaries = []; + for (let i = right + 2; i < group.nodes.length; i++) { + rightSimilaries.push(group.similarities[i - 1]); + rightNodes.push(group.nodes[i]); + } + queue.push(new Group(rightNodes, rightSimilaries)); + + const leftNodes = [group.nodes[0]]; + /** @type {number[]} */ + const leftSimilaries = []; + for (let i = 1; i < left; i++) { + leftSimilaries.push(group.similarities[i - 1]); + leftNodes.push(group.nodes[i]); + } + queue.push(new Group(leftNodes, leftSimilaries)); + } + } + } + + // lexically ordering + result.sort((a, b) => { + if (a.nodes[0].key < b.nodes[0].key) return -1; + if (a.nodes[0].key > b.nodes[0].key) return 1; + return 0; + }); + + // give every group a name + for (let i = 0; i < result.length; i++) { + const group = result[i]; + const first = group.nodes[0]; + const last = group.nodes[group.nodes.length - 1]; + let name = getName(first.key, last.key); + group.key = name; + } + + // return the results + return result.map(group => { + /** @type {GroupedItems} */ + return { + key: group.key, + items: group.nodes.map(node => node.item), + size: group.size + }; + }); +}; diff --git a/node_modules/webpack/lib/util/identifier.js b/node_modules/webpack/lib/util/identifier.js new file mode 100644 index 0000000..0c573e8 --- /dev/null +++ b/node_modules/webpack/lib/util/identifier.js @@ -0,0 +1,127 @@ +"use strict"; +const path = require("path"); + +/** + * @param {string} context context for relative path + * @param {string} relativePath path + * @returns {string} absolute path + */ +const requestToAbsolute = (context, relativePath) => { + if (relativePath.startsWith("./") || relativePath.startsWith("../")) + return path.join(context, relativePath); + return relativePath; +}; + +/** + * @typedef {Object} MakeRelativePathsCache + * @property {Map<string, Map<string, string>>=} relativePaths + */ + +/** + * + * @param {string} maybeAbsolutePath path to check + * @returns {boolean} returns true if path is "Absolute Path"-like + */ +const looksLikeAbsolutePath = maybeAbsolutePath => { + if (/^\/.*\/$/.test(maybeAbsolutePath)) { + // this 'path' is actually a regexp generated by dynamic requires. + // Don't treat it as an absolute path. + return false; + } + return /^(?:[a-z]:\\|\/)/i.test(maybeAbsolutePath); +}; + +/** + * + * @param {string} p path to normalize + * @returns {string} normalized version of path + */ +const normalizePathSeparator = p => p.replace(/\\/g, "/"); + +/** + * + * @param {string} context context for relative path + * @param {string} identifier identifier for path + * @returns {string} a converted relative path + */ +const _makePathsRelative = (context, identifier) => { + return identifier + .split(/([|! ])/) + .map(str => + looksLikeAbsolutePath(str) + ? normalizePathSeparator(path.relative(context, str)) + : str + ) + .join(""); +}; + +/** + * + * @param {string} context context used to create relative path + * @param {string} identifier identifier used to create relative path + * @param {MakeRelativePathsCache=} cache the cache object being set + * @returns {string} the returned relative path + */ +exports.makePathsRelative = (context, identifier, cache) => { + if (!cache) return _makePathsRelative(context, identifier); + + const relativePaths = + cache.relativePaths || (cache.relativePaths = new Map()); + + let cachedResult; + let contextCache = relativePaths.get(context); + if (contextCache === undefined) { + relativePaths.set(context, (contextCache = new Map())); + } else { + cachedResult = contextCache.get(identifier); + } + + if (cachedResult !== undefined) { + return cachedResult; + } else { + const relativePath = _makePathsRelative(context, identifier); + contextCache.set(identifier, relativePath); + return relativePath; + } +}; + +/** + * @param {string} context absolute context path + * @param {string} request any request string may containing absolute paths, query string, etc. + * @returns {string} a new request string avoiding absolute paths when possible + */ +exports.contextify = (context, request) => { + return request + .split("!") + .map(r => { + const splitPath = r.split("?", 2); + if (/^[a-zA-Z]:\\/.test(splitPath[0])) { + splitPath[0] = path.win32.relative(context, splitPath[0]); + if (!/^[a-zA-Z]:\\/.test(splitPath[0])) { + splitPath[0] = splitPath[0].replace(/\\/g, "/"); + } + } + if (/^\//.test(splitPath[0])) { + splitPath[0] = path.posix.relative(context, splitPath[0]); + } + if (!/^(\.\.\/|\/|[a-zA-Z]:\\)/.test(splitPath[0])) { + splitPath[0] = "./" + splitPath[0]; + } + return splitPath.join("?"); + }) + .join("!"); +}; + +/** + * @param {string} context absolute context path + * @param {string} request any request string + * @returns {string} a new request string using absolute paths when possible + */ +const _absolutify = (context, request) => { + return request + .split("!") + .map(r => requestToAbsolute(context, r)) + .join("!"); +}; + +exports.absolutify = _absolutify; diff --git a/node_modules/webpack/lib/util/objectToMap.js b/node_modules/webpack/lib/util/objectToMap.js new file mode 100644 index 0000000..f8c13c2 --- /dev/null +++ b/node_modules/webpack/lib/util/objectToMap.js @@ -0,0 +1,16 @@ +/** + * convert an object into its 2D array equivalent to be turned + * into an ES6 map + * + * @param {object} obj any object type that works with Object.keys() + * @returns {Map<TODO, TODO>} an ES6 Map of KV pairs + */ +module.exports = function objectToMap(obj) { + return new Map( + Object.keys(obj).map(key => { + /** @type {[string, string]} */ + const pair = [key, obj[key]]; + return pair; + }) + ); +}; diff --git a/node_modules/webpack/lib/validateSchema.js b/node_modules/webpack/lib/validateSchema.js new file mode 100644 index 0000000..b748c2c --- /dev/null +++ b/node_modules/webpack/lib/validateSchema.js @@ -0,0 +1,67 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Gajus Kuizinas @gajus +*/ +"use strict"; + +const Ajv = require("ajv"); +const ajv = new Ajv({ + errorDataPath: "configuration", + allErrors: true, + verbose: true +}); +require("ajv-keywords")(ajv, ["instanceof"]); +require("../schemas/ajv.absolutePath")(ajv); + +const validateSchema = (schema, options) => { + if (Array.isArray(options)) { + const errors = options.map(options => validateObject(schema, options)); + errors.forEach((list, idx) => { + const applyPrefix = err => { + err.dataPath = `[${idx}]${err.dataPath}`; + if (err.children) { + err.children.forEach(applyPrefix); + } + }; + list.forEach(applyPrefix); + }); + return errors.reduce((arr, items) => { + return arr.concat(items); + }, []); + } else { + return validateObject(schema, options); + } +}; + +const validateObject = (schema, options) => { + const validate = ajv.compile(schema); + const valid = validate(options); + return valid ? [] : filterErrors(validate.errors); +}; + +const filterErrors = errors => { + let newErrors = []; + for (const err of errors) { + const dataPath = err.dataPath; + let children = []; + newErrors = newErrors.filter(oldError => { + if (oldError.dataPath.includes(dataPath)) { + if (oldError.children) { + children = children.concat(oldError.children.slice(0)); + } + oldError.children = undefined; + children.push(oldError); + return false; + } + return true; + }); + if (children.length) { + err.children = children; + } + newErrors.push(err); + } + + return newErrors; +}; + +module.exports = validateSchema; diff --git a/node_modules/webpack/lib/wasm/UnsupportedWebAssemblyFeatureError.js b/node_modules/webpack/lib/wasm/UnsupportedWebAssemblyFeatureError.js new file mode 100644 index 0000000..fede4eb --- /dev/null +++ b/node_modules/webpack/lib/wasm/UnsupportedWebAssemblyFeatureError.js @@ -0,0 +1,17 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); + +module.exports = class UnsupportedWebAssemblyFeatureError extends WebpackError { + /** @param {string} message Error message */ + constructor(message) { + super(message); + this.name = "UnsupportedWebAssemblyFeatureError"; + this.hideStack = true; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/wasm/WasmFinalizeExportsPlugin.js b/node_modules/webpack/lib/wasm/WasmFinalizeExportsPlugin.js new file mode 100644 index 0000000..52df869 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WasmFinalizeExportsPlugin.js @@ -0,0 +1,69 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ +"use strict"; + +const UnsupportedWebAssemblyFeatureError = require("./UnsupportedWebAssemblyFeatureError"); + +class WasmFinalizeExportsPlugin { + apply(compiler) { + compiler.hooks.compilation.tap("WasmFinalizeExportsPlugin", compilation => { + compilation.hooks.finishModules.tap( + "WasmFinalizeExportsPlugin", + modules => { + for (const module of modules) { + // 1. if a WebAssembly module + if (module.type.startsWith("webassembly") === true) { + const jsIncompatibleExports = + module.buildMeta.jsIncompatibleExports; + + if (jsIncompatibleExports === undefined) { + continue; + } + + for (const reason of module.reasons) { + // 2. is referenced by a non-WebAssembly module + if (reason.module.type.startsWith("webassembly") === false) { + const ref = compilation.getDependencyReference( + reason.module, + reason.dependency + ); + + if (!ref) continue; + + const importedNames = ref.importedNames; + + if (Array.isArray(importedNames)) { + importedNames.forEach(name => { + // 3. and uses a func with an incompatible JS signature + if ( + Object.prototype.hasOwnProperty.call( + jsIncompatibleExports, + name + ) + ) { + // 4. error + /** @type {any} */ + const error = new UnsupportedWebAssemblyFeatureError( + `Export "${name}" with ${jsIncompatibleExports[name]} can only be used for direct wasm to wasm dependencies` + ); + error.module = module; + error.origin = reason.module; + error.originLoc = reason.dependency.loc; + error.dependencies = [reason.dependency]; + compilation.errors.push(error); + } + }); + } + } + } + } + } + } + ); + }); + } +} + +module.exports = WasmFinalizeExportsPlugin; diff --git a/node_modules/webpack/lib/wasm/WasmMainTemplatePlugin.js b/node_modules/webpack/lib/wasm/WasmMainTemplatePlugin.js new file mode 100644 index 0000000..494c8ec --- /dev/null +++ b/node_modules/webpack/lib/wasm/WasmMainTemplatePlugin.js @@ -0,0 +1,341 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("../Template"); +const WebAssemblyUtils = require("./WebAssemblyUtils"); + +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../MainTemplate")} MainTemplate */ + +// Get all wasm modules +const getAllWasmModules = chunk => { + const wasmModules = chunk.getAllAsyncChunks(); + const array = []; + for (const chunk of wasmModules) { + for (const m of chunk.modulesIterable) { + if (m.type.startsWith("webassembly")) { + array.push(m); + } + } + } + + return array; +}; + +/** + * generates the import object function for a module + * @param {Module} module the module + * @param {boolean} mangle mangle imports + * @returns {string} source code + */ +const generateImportObject = (module, mangle) => { + const waitForInstances = new Map(); + const properties = []; + const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies( + module, + mangle + ); + for (const usedDep of usedWasmDependencies) { + const dep = usedDep.dependency; + const importedModule = dep.module; + const exportName = dep.name; + const usedName = importedModule && importedModule.isUsed(exportName); + const description = dep.description; + const direct = dep.onlyDirectImport; + + const module = usedDep.module; + const name = usedDep.name; + + if (direct) { + const instanceVar = `m${waitForInstances.size}`; + waitForInstances.set(instanceVar, importedModule.id); + properties.push({ + module, + name, + value: `${instanceVar}[${JSON.stringify(usedName)}]` + }); + } else { + const params = description.signature.params.map( + (param, k) => "p" + k + param.valtype + ); + + const mod = `installedModules[${JSON.stringify(importedModule.id)}]`; + const func = `${mod}.exports[${JSON.stringify(usedName)}]`; + + properties.push({ + module, + name, + value: Template.asString([ + (importedModule.type.startsWith("webassembly") + ? `${mod} ? ${func} : ` + : "") + `function(${params}) {`, + Template.indent([`return ${func}(${params});`]), + "}" + ]) + }); + } + } + + let importObject; + if (mangle) { + importObject = [ + "return {", + Template.indent([ + properties.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n") + ]), + "};" + ]; + } else { + const propertiesByModule = new Map(); + for (const p of properties) { + let list = propertiesByModule.get(p.module); + if (list === undefined) { + propertiesByModule.set(p.module, (list = [])); + } + list.push(p); + } + importObject = [ + "return {", + Template.indent([ + Array.from(propertiesByModule, ([module, list]) => { + return Template.asString([ + `${JSON.stringify(module)}: {`, + Template.indent([ + list.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n") + ]), + "}" + ]); + }).join(",\n") + ]), + "};" + ]; + } + + if (waitForInstances.size === 1) { + const moduleId = Array.from(waitForInstances.values())[0]; + const promise = `installedWasmModules[${JSON.stringify(moduleId)}]`; + const variable = Array.from(waitForInstances.keys())[0]; + return Template.asString([ + `${JSON.stringify(module.id)}: function() {`, + Template.indent([ + `return promiseResolve().then(function() { return ${promise}; }).then(function(${variable}) {`, + Template.indent(importObject), + "});" + ]), + "}," + ]); + } else if (waitForInstances.size > 0) { + const promises = Array.from( + waitForInstances.values(), + id => `installedWasmModules[${JSON.stringify(id)}]` + ).join(", "); + const variables = Array.from( + waitForInstances.keys(), + (name, i) => `${name} = array[${i}]` + ).join(", "); + return Template.asString([ + `${JSON.stringify(module.id)}: function() {`, + Template.indent([ + `return promiseResolve().then(function() { return Promise.all([${promises}]); }).then(function(array) {`, + Template.indent([`var ${variables};`, ...importObject]), + "});" + ]), + "}," + ]); + } else { + return Template.asString([ + `${JSON.stringify(module.id)}: function() {`, + Template.indent(importObject), + "}," + ]); + } +}; + +class WasmMainTemplatePlugin { + constructor({ generateLoadBinaryCode, supportsStreaming, mangleImports }) { + this.generateLoadBinaryCode = generateLoadBinaryCode; + this.supportsStreaming = supportsStreaming; + this.mangleImports = mangleImports; + } + + /** + * @param {MainTemplate} mainTemplate main template + * @returns {void} + */ + apply(mainTemplate) { + mainTemplate.hooks.localVars.tap( + "WasmMainTemplatePlugin", + (source, chunk) => { + const wasmModules = getAllWasmModules(chunk); + if (wasmModules.length === 0) return source; + const importObjects = wasmModules.map(module => { + return generateImportObject(module, this.mangleImports); + }); + return Template.asString([ + source, + "", + "// object to store loaded and loading wasm modules", + "var installedWasmModules = {};", + "", + // This function is used to delay reading the installed wasm module promises + // by a microtask. Sorting them doesn't help because there are egdecases where + // sorting is not possible (modules splitted into different chunks). + // So we not even trying and solve this by a microtask delay. + "function promiseResolve() { return Promise.resolve(); }", + "", + "var wasmImportObjects = {", + Template.indent(importObjects), + "};" + ]); + } + ); + mainTemplate.hooks.requireEnsure.tap( + "WasmMainTemplatePlugin", + (source, chunk, hash) => { + const webassemblyModuleFilename = + mainTemplate.outputOptions.webassemblyModuleFilename; + + const chunkModuleMaps = chunk.getChunkModuleMaps(m => + m.type.startsWith("webassembly") + ); + if (Object.keys(chunkModuleMaps.id).length === 0) return source; + const wasmModuleSrcPath = mainTemplate.getAssetPath( + JSON.stringify(webassemblyModuleFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + module: { + id: '" + wasmModuleId + "', + hash: `" + ${JSON.stringify( + chunkModuleMaps.hash + )}[wasmModuleId] + "`, + hashWithLength(length) { + const shortChunkHashMap = Object.create(null); + for (const wasmModuleId of Object.keys(chunkModuleMaps.hash)) { + if (typeof chunkModuleMaps.hash[wasmModuleId] === "string") { + shortChunkHashMap[wasmModuleId] = chunkModuleMaps.hash[ + wasmModuleId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap + )}[wasmModuleId] + "`; + } + } + } + ); + const createImportObject = content => + this.mangleImports + ? `{ ${JSON.stringify( + WebAssemblyUtils.MANGLED_MODULE + )}: ${content} }` + : content; + return Template.asString([ + source, + "", + "// Fetch + compile chunk loading for webassembly", + "", + `var wasmModules = ${JSON.stringify( + chunkModuleMaps.id + )}[chunkId] || [];`, + "", + "wasmModules.forEach(function(wasmModuleId) {", + Template.indent([ + "var installedWasmModuleData = installedWasmModules[wasmModuleId];", + "", + '// a Promise means "currently loading" or "already loaded".', + "if(installedWasmModuleData)", + Template.indent(["promises.push(installedWasmModuleData);"]), + "else {", + Template.indent([ + `var importObject = wasmImportObjects[wasmModuleId]();`, + `var req = ${this.generateLoadBinaryCode(wasmModuleSrcPath)};`, + "var promise;", + this.supportsStreaming + ? Template.asString([ + "if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {", + Template.indent([ + "promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {", + Template.indent([ + `return WebAssembly.instantiate(items[0], ${createImportObject( + "items[1]" + )});` + ]), + "});" + ]), + "} else if(typeof WebAssembly.instantiateStreaming === 'function') {", + Template.indent([ + `promise = WebAssembly.instantiateStreaming(req, ${createImportObject( + "importObject" + )});` + ]) + ]) + : Template.asString([ + "if(importObject instanceof Promise) {", + Template.indent([ + "var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });", + "promise = Promise.all([", + Template.indent([ + "bytesPromise.then(function(bytes) { return WebAssembly.compile(bytes); }),", + "importObject" + ]), + "]).then(function(items) {", + Template.indent([ + `return WebAssembly.instantiate(items[0], ${createImportObject( + "items[1]" + )});` + ]), + "});" + ]) + ]), + "} else {", + Template.indent([ + "var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });", + "promise = bytesPromise.then(function(bytes) {", + Template.indent([ + `return WebAssembly.instantiate(bytes, ${createImportObject( + "importObject" + )});` + ]), + "});" + ]), + "}", + "promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {", + Template.indent([ + `return ${mainTemplate.requireFn}.w[wasmModuleId] = (res.instance || res).exports;` + ]), + "}));" + ]), + "}" + ]), + "});" + ]); + } + ); + mainTemplate.hooks.requireExtensions.tap( + "WasmMainTemplatePlugin", + (source, chunk) => { + if (!chunk.hasModuleInGraph(m => m.type.startsWith("webassembly"))) { + return source; + } + return Template.asString([ + source, + "", + "// object with all WebAssembly.instance exports", + `${mainTemplate.requireFn}.w = {};` + ]); + } + ); + mainTemplate.hooks.hash.tap("WasmMainTemplatePlugin", hash => { + hash.update("WasmMainTemplatePlugin"); + hash.update("2"); + }); + } +} + +module.exports = WasmMainTemplatePlugin; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyGenerator.js b/node_modules/webpack/lib/wasm/WebAssemblyGenerator.js new file mode 100644 index 0000000..dbee5bd --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyGenerator.js @@ -0,0 +1,458 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Generator = require("../Generator"); +const Template = require("../Template"); +const WebAssemblyUtils = require("./WebAssemblyUtils"); +const { RawSource } = require("webpack-sources"); + +const { editWithAST, addWithAST } = require("@webassemblyjs/wasm-edit"); +const { decode } = require("@webassemblyjs/wasm-parser"); +const t = require("@webassemblyjs/ast"); +const { + moduleContextFromModuleAST +} = require("@webassemblyjs/helper-module-context"); + +const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); + +/** @typedef {import("../Module")} Module */ +/** @typedef {import("./WebAssemblyUtils").UsedWasmDependency} UsedWasmDependency */ +/** @typedef {import("../NormalModule")} NormalModule */ +/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("../Dependency").DependencyTemplate} DependencyTemplate */ + +/** + * @typedef {(ArrayBuffer) => ArrayBuffer} ArrayBufferTransform + */ + +/** + * @template T + * @param {Function[]} fns transforms + * @returns {Function} composed transform + */ +const compose = (...fns) => { + return fns.reduce( + (prevFn, nextFn) => { + return value => nextFn(prevFn(value)); + }, + value => value + ); +}; + +// TODO replace with @callback + +/** + * Removes the start instruction + * + * @param {Object} state unused state + * @returns {ArrayBufferTransform} transform + */ +const removeStartFunc = state => bin => { + return editWithAST(state.ast, bin, { + Start(path) { + path.remove(); + } + }); +}; + +/** + * Get imported globals + * + * @param {Object} ast Module's AST + * @returns {Array<t.ModuleImport>} - nodes + */ +const getImportedGlobals = ast => { + const importedGlobals = []; + + t.traverse(ast, { + ModuleImport({ node }) { + if (t.isGlobalType(node.descr)) { + importedGlobals.push(node); + } + } + }); + + return importedGlobals; +}; + +/** + * Get the count for imported func + * + * @param {Object} ast Module's AST + * @returns {Number} - count + */ +const getCountImportedFunc = ast => { + let count = 0; + + t.traverse(ast, { + ModuleImport({ node }) { + if (t.isFuncImportDescr(node.descr)) { + count++; + } + } + }); + + return count; +}; + +/** + * Get next type index + * + * @param {Object} ast Module's AST + * @returns {t.Index} - index + */ +const getNextTypeIndex = ast => { + const typeSectionMetadata = t.getSectionMetadata(ast, "type"); + + if (typeSectionMetadata === undefined) { + return t.indexLiteral(0); + } + + return t.indexLiteral(typeSectionMetadata.vectorOfSize.value); +}; + +/** + * Get next func index + * + * The Func section metadata provide informations for implemented funcs + * in order to have the correct index we shift the index by number of external + * functions. + * + * @param {Object} ast Module's AST + * @param {Number} countImportedFunc number of imported funcs + * @returns {t.Index} - index + */ +const getNextFuncIndex = (ast, countImportedFunc) => { + const funcSectionMetadata = t.getSectionMetadata(ast, "func"); + + if (funcSectionMetadata === undefined) { + return t.indexLiteral(0 + countImportedFunc); + } + + const vectorOfSize = funcSectionMetadata.vectorOfSize.value; + + return t.indexLiteral(vectorOfSize + countImportedFunc); +}; + +/** + * Creates an init instruction for a global type + * @param {t.GlobalType} globalType the global type + * @returns {t.Instruction} init expression + */ +const createDefaultInitForGlobal = globalType => { + if (globalType.valtype[0] === "i") { + // create NumberLiteral global initializer + return t.objectInstruction("const", globalType.valtype, [ + t.numberLiteralFromRaw(66) + ]); + } else if (globalType.valtype[0] === "f") { + // create FloatLiteral global initializer + return t.objectInstruction("const", globalType.valtype, [ + t.floatLiteral(66, false, false, "66") + ]); + } else { + throw new Error("unknown type: " + globalType.valtype); + } +}; + +/** + * Rewrite the import globals: + * - removes the ModuleImport instruction + * - injects at the same offset a mutable global of the same type + * + * Since the imported globals are before the other global declarations, our + * indices will be preserved. + * + * Note that globals will become mutable. + * + * @param {Object} state unused state + * @returns {ArrayBufferTransform} transform + */ +const rewriteImportedGlobals = state => bin => { + const additionalInitCode = state.additionalInitCode; + const newGlobals = []; + + bin = editWithAST(state.ast, bin, { + ModuleImport(path) { + if (t.isGlobalType(path.node.descr)) { + const globalType = path.node.descr; + + globalType.mutability = "var"; + + const init = [ + createDefaultInitForGlobal(globalType), + t.instruction("end") + ]; + + newGlobals.push(t.global(globalType, init)); + + path.remove(); + } + }, + + // in order to preserve non-imported global's order we need to re-inject + // those as well + Global(path) { + const { node } = path; + const [init] = node.init; + + if (init.id === "get_global") { + node.globalType.mutability = "var"; + + const initialGlobalidx = init.args[0]; + + node.init = [ + createDefaultInitForGlobal(node.globalType), + t.instruction("end") + ]; + + additionalInitCode.push( + /** + * get_global in global initializer only works for imported globals. + * They have the same indices as the init params, so use the + * same index. + */ + t.instruction("get_local", [initialGlobalidx]), + t.instruction("set_global", [t.indexLiteral(newGlobals.length)]) + ); + } + + newGlobals.push(node); + + path.remove(); + } + }); + + // Add global declaration instructions + return addWithAST(state.ast, bin, newGlobals); +}; + +/** + * Rewrite the export names + * @param {Object} state state + * @param {Object} state.ast Module's ast + * @param {Module} state.module Module + * @param {Set<string>} state.externalExports Module + * @returns {ArrayBufferTransform} transform + */ +const rewriteExportNames = ({ ast, module, externalExports }) => bin => { + return editWithAST(ast, bin, { + ModuleExport(path) { + const isExternal = externalExports.has(path.node.name); + if (isExternal) { + path.remove(); + return; + } + const usedName = module.isUsed(path.node.name); + if (!usedName) { + path.remove(); + return; + } + path.node.name = usedName; + } + }); +}; + +/** + * Mangle import names and modules + * @param {Object} state state + * @param {Object} state.ast Module's ast + * @param {Map<string, UsedWasmDependency>} state.usedDependencyMap mappings to mangle names + * @returns {ArrayBufferTransform} transform + */ +const rewriteImports = ({ ast, usedDependencyMap }) => bin => { + return editWithAST(ast, bin, { + ModuleImport(path) { + const result = usedDependencyMap.get( + path.node.module + ":" + path.node.name + ); + + if (result !== undefined) { + path.node.module = result.module; + path.node.name = result.name; + } + } + }); +}; + +/** + * Add an init function. + * + * The init function fills the globals given input arguments. + * + * @param {Object} state transformation state + * @param {Object} state.ast Module's ast + * @param {t.Identifier} state.initFuncId identifier of the init function + * @param {t.Index} state.startAtFuncOffset index of the start function + * @param {t.ModuleImport[]} state.importedGlobals list of imported globals + * @param {t.Instruction[]} state.additionalInitCode list of addition instructions for the init function + * @param {t.Index} state.nextFuncIndex index of the next function + * @param {t.Index} state.nextTypeIndex index of the next type + * @returns {ArrayBufferTransform} transform + */ +const addInitFunction = ({ + ast, + initFuncId, + startAtFuncOffset, + importedGlobals, + additionalInitCode, + nextFuncIndex, + nextTypeIndex +}) => bin => { + const funcParams = importedGlobals.map(importedGlobal => { + // used for debugging + const id = t.identifier(`${importedGlobal.module}.${importedGlobal.name}`); + + return t.funcParam(importedGlobal.descr.valtype, id); + }); + + const funcBody = importedGlobals.reduce((acc, importedGlobal, index) => { + const args = [t.indexLiteral(index)]; + const body = [ + t.instruction("get_local", args), + t.instruction("set_global", args) + ]; + + return [...acc, ...body]; + }, []); + + if (typeof startAtFuncOffset === "number") { + funcBody.push(t.callInstruction(t.numberLiteralFromRaw(startAtFuncOffset))); + } + + for (const instr of additionalInitCode) { + funcBody.push(instr); + } + + funcBody.push(t.instruction("end")); + + const funcResults = []; + + // Code section + const funcSignature = t.signature(funcParams, funcResults); + const func = t.func(initFuncId, funcSignature, funcBody); + + // Type section + const functype = t.typeInstruction(undefined, funcSignature); + + // Func section + const funcindex = t.indexInFuncSection(nextTypeIndex); + + // Export section + const moduleExport = t.moduleExport( + initFuncId.value, + t.moduleExportDescr("Func", nextFuncIndex) + ); + + return addWithAST(ast, bin, [func, moduleExport, funcindex, functype]); +}; + +/** + * Extract mangle mappings from module + * @param {Module} module current module + * @param {boolean} mangle mangle imports + * @returns {Map<string, UsedWasmDependency>} mappings to mangled names + */ +const getUsedDependencyMap = (module, mangle) => { + /** @type {Map<string, UsedWasmDependency>} */ + const map = new Map(); + for (const usedDep of WebAssemblyUtils.getUsedDependencies(module, mangle)) { + const dep = usedDep.dependency; + const request = dep.request; + const exportName = dep.name; + map.set(request + ":" + exportName, usedDep); + } + return map; +}; + +class WebAssemblyGenerator extends Generator { + constructor(options) { + super(); + this.options = options; + } + + /** + * @param {NormalModule} module module for which the code should be generated + * @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates + * @param {RuntimeTemplate} runtimeTemplate the runtime template + * @param {string} type which kind of code should be generated + * @returns {Source} generated code + */ + generate(module, dependencyTemplates, runtimeTemplate, type) { + let bin = module.originalSource().source(); + + const initFuncId = t.identifier( + Array.isArray(module.usedExports) + ? Template.numberToIdentifer(module.usedExports.length) + : "__webpack_init__" + ); + + // parse it + const ast = decode(bin, { + ignoreDataSection: true, + ignoreCodeSection: true, + ignoreCustomNameSection: true + }); + + const moduleContext = moduleContextFromModuleAST(ast.body[0]); + + const importedGlobals = getImportedGlobals(ast); + const countImportedFunc = getCountImportedFunc(ast); + const startAtFuncOffset = moduleContext.getStart(); + const nextFuncIndex = getNextFuncIndex(ast, countImportedFunc); + const nextTypeIndex = getNextTypeIndex(ast); + + const usedDependencyMap = getUsedDependencyMap( + module, + this.options.mangleImports + ); + const externalExports = new Set( + module.dependencies + .filter(d => d instanceof WebAssemblyExportImportedDependency) + .map(d => { + const wasmDep = /** @type {WebAssemblyExportImportedDependency} */ (d); + return wasmDep.exportName; + }) + ); + + /** @type {t.Instruction[]} */ + const additionalInitCode = []; + + const transform = compose( + rewriteExportNames({ + ast, + module, + externalExports + }), + + removeStartFunc({ ast }), + + rewriteImportedGlobals({ ast, additionalInitCode }), + + rewriteImports({ + ast, + usedDependencyMap + }), + + addInitFunction({ + ast, + initFuncId, + importedGlobals, + additionalInitCode, + startAtFuncOffset, + nextFuncIndex, + nextTypeIndex + }) + ); + + const newBin = transform(bin); + + return new RawSource(newBin); + } +} + +module.exports = WebAssemblyGenerator; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyInInitialChunkError.js b/node_modules/webpack/lib/wasm/WebAssemblyInInitialChunkError.js new file mode 100644 index 0000000..319e757 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyInInitialChunkError.js @@ -0,0 +1,88 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php +*/ +"use strict"; + +const WebpackError = require("../WebpackError"); + +/** @typedef {import("../Module")} Module */ +/** @typedef {import("../RequestShortener")} RequestShortener */ + +/** + * @param {Module} module module to get chains from + * @param {RequestShortener} requestShortener to make readable identifiers + * @returns {string[]} all chains to the module + */ +const getInitialModuleChains = (module, requestShortener) => { + const queue = [ + { head: module, message: module.readableIdentifier(requestShortener) } + ]; + /** @type {Set<string>} */ + const results = new Set(); + /** @type {Set<string>} */ + const incompleteResults = new Set(); + /** @type {Set<Module>} */ + const visitedModules = new Set(); + + for (const chain of queue) { + const { head, message } = chain; + let final = true; + /** @type {Set<Module>} */ + const alreadyReferencedModules = new Set(); + for (const reason of head.reasons) { + const newHead = reason.module; + if (newHead) { + if (!newHead.getChunks().some(c => c.canBeInitial())) continue; + final = false; + if (alreadyReferencedModules.has(newHead)) continue; + alreadyReferencedModules.add(newHead); + const moduleName = newHead.readableIdentifier(requestShortener); + const detail = reason.explanation ? ` (${reason.explanation})` : ""; + const newMessage = `${moduleName}${detail} --> ${message}`; + if (visitedModules.has(newHead)) { + incompleteResults.add(`... --> ${newMessage}`); + continue; + } + visitedModules.add(newHead); + queue.push({ + head: newHead, + message: newMessage + }); + } else { + final = false; + const newMessage = reason.explanation + ? `(${reason.explanation}) --> ${message}` + : message; + results.add(newMessage); + } + } + if (final) { + results.add(message); + } + } + for (const result of incompleteResults) { + results.add(result); + } + return Array.from(results); +}; + +module.exports = class WebAssemblyInInitialChunkError extends WebpackError { + /** + * @param {Module} module WASM module + * @param {RequestShortener} requestShortener request shortener + */ + constructor(module, requestShortener) { + const moduleChains = getInitialModuleChains(module, requestShortener); + const message = `WebAssembly module is included in initial chunk. +This is not allowed, because WebAssembly download and compilation must happen asynchronous. +Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module: +${moduleChains.map(s => `* ${s}`).join("\n")}`; + + super(message); + this.name = "WebAssemblyInInitialChunkError"; + this.hideStack = true; + this.module = module; + + Error.captureStackTrace(this, this.constructor); + } +}; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyJavascriptGenerator.js b/node_modules/webpack/lib/wasm/WebAssemblyJavascriptGenerator.js new file mode 100644 index 0000000..22dfb79 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyJavascriptGenerator.js @@ -0,0 +1,152 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Generator = require("../Generator"); +const Template = require("../Template"); +const { RawSource } = require("webpack-sources"); +const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); +const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); + +/** @typedef {import("../NormalModule")} NormalModule */ +/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("../Dependency").DependencyTemplate} DependencyTemplate */ + +class WebAssemblyJavascriptGenerator extends Generator { + /** + * @param {NormalModule} module module for which the code should be generated + * @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates + * @param {RuntimeTemplate} runtimeTemplate the runtime template + * @param {string} type which kind of code should be generated + * @returns {Source} generated code + */ + generate(module, dependencyTemplates, runtimeTemplate, type) { + const initIdentifer = Array.isArray(module.usedExports) + ? Template.numberToIdentifer(module.usedExports.length) + : "__webpack_init__"; + + let needExportsCopy = false; + const importedModules = new Map(); + const initParams = []; + let index = 0; + for (const dep of module.dependencies) { + const depAsAny = /** @type {any} */ (dep); + if (dep.module) { + let importData = importedModules.get(dep.module); + if (importData === undefined) { + importedModules.set( + dep.module, + (importData = { + importVar: `m${index}`, + index, + request: + "userRequest" in depAsAny ? depAsAny.userRequest : undefined, + names: new Set(), + reexports: [] + }) + ); + index++; + } + if (dep instanceof WebAssemblyImportDependency) { + importData.names.add(dep.name); + if (dep.description.type === "GlobalType") { + const exportName = dep.name; + const usedName = dep.module && dep.module.isUsed(exportName); + + if (dep.module) { + if (usedName) { + initParams.push( + runtimeTemplate.exportFromImport({ + module: dep.module, + request: dep.request, + importVar: importData.importVar, + originModule: module, + exportName: dep.name, + asiSafe: true, + isCall: false, + callContext: null + }) + ); + } + } + } + } + if (dep instanceof WebAssemblyExportImportedDependency) { + importData.names.add(dep.name); + const usedName = module.isUsed(dep.exportName); + if (usedName) { + const exportProp = `${module.exportsArgument}[${JSON.stringify( + usedName + )}]`; + const defineStatement = Template.asString([ + `${exportProp} = ${runtimeTemplate.exportFromImport({ + module: dep.module, + request: dep.request, + importVar: importData.importVar, + originModule: module, + exportName: dep.name, + asiSafe: true, + isCall: false, + callContext: null + })};`, + `if(WebAssembly.Global) ${exportProp} = ` + + `new WebAssembly.Global({ value: ${JSON.stringify( + dep.valueType + )} }, ${exportProp});` + ]); + importData.reexports.push(defineStatement); + needExportsCopy = true; + } + } + } + } + const importsCode = Template.asString( + Array.from( + importedModules, + ([module, { importVar, request, reexports }]) => { + const importStatement = runtimeTemplate.importStatement({ + module, + request, + importVar, + originModule: module + }); + return importStatement + reexports.join("\n"); + } + ) + ); + + // create source + const source = new RawSource( + [ + '"use strict";', + "// Instantiate WebAssembly module", + "var wasmExports = __webpack_require__.w[module.i];", + + !Array.isArray(module.usedExports) + ? `__webpack_require__.r(${module.exportsArgument});` + : "", + + // this must be before import for circular dependencies + "// export exports from WebAssembly module", + Array.isArray(module.usedExports) && !needExportsCopy + ? `${module.moduleArgument}.exports = wasmExports;` + : "for(var name in wasmExports) " + + `if(name != ${JSON.stringify(initIdentifer)}) ` + + `${module.exportsArgument}[name] = wasmExports[name];`, + "// exec imports from WebAssembly module (for esm order)", + importsCode, + "", + "// exec wasm module", + `wasmExports[${JSON.stringify(initIdentifer)}](${initParams.join( + ", " + )})` + ].join("\n") + ); + return source; + } +} + +module.exports = WebAssemblyJavascriptGenerator; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyModulesPlugin.js b/node_modules/webpack/lib/wasm/WebAssemblyModulesPlugin.js new file mode 100644 index 0000000..a4dd8a5 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyModulesPlugin.js @@ -0,0 +1,128 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Generator = require("../Generator"); +const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); +const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); +const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError"); + +/** @typedef {import("../Compiler")} Compiler */ + +let WebAssemblyGenerator; +let WebAssemblyJavascriptGenerator; +let WebAssemblyParser; + +class WebAssemblyModulesPlugin { + constructor(options) { + this.options = options; + } + + /** + * @param {Compiler} compiler compiler + * @returns {void} + */ + apply(compiler) { + compiler.hooks.compilation.tap( + "WebAssemblyModulesPlugin", + (compilation, { normalModuleFactory }) => { + compilation.dependencyFactories.set( + WebAssemblyImportDependency, + normalModuleFactory + ); + + compilation.dependencyFactories.set( + WebAssemblyExportImportedDependency, + normalModuleFactory + ); + + normalModuleFactory.hooks.createParser + .for("webassembly/experimental") + .tap("WebAssemblyModulesPlugin", () => { + if (WebAssemblyParser === undefined) { + WebAssemblyParser = require("./WebAssemblyParser"); + } + return new WebAssemblyParser(); + }); + + normalModuleFactory.hooks.createGenerator + .for("webassembly/experimental") + .tap("WebAssemblyModulesPlugin", () => { + if (WebAssemblyGenerator === undefined) { + WebAssemblyGenerator = require("./WebAssemblyGenerator"); + } + if (WebAssemblyJavascriptGenerator === undefined) { + WebAssemblyJavascriptGenerator = require("./WebAssemblyJavascriptGenerator"); + } + return Generator.byType({ + javascript: new WebAssemblyJavascriptGenerator(), + webassembly: new WebAssemblyGenerator(this.options) + }); + }); + + compilation.chunkTemplate.hooks.renderManifest.tap( + "WebAssemblyModulesPlugin", + (result, options) => { + const chunk = options.chunk; + const outputOptions = options.outputOptions; + const moduleTemplates = options.moduleTemplates; + const dependencyTemplates = options.dependencyTemplates; + + for (const module of chunk.modulesIterable) { + if (module.type && module.type.startsWith("webassembly")) { + const filenameTemplate = + outputOptions.webassemblyModuleFilename; + + result.push({ + render: () => + this.renderWebAssembly( + module, + moduleTemplates.webassembly, + dependencyTemplates + ), + filenameTemplate, + pathOptions: { + module + }, + identifier: `webassemblyModule${module.id}`, + hash: module.hash + }); + } + } + + return result; + } + ); + + compilation.hooks.afterChunks.tap("WebAssemblyModulesPlugin", () => { + const initialWasmModules = new Set(); + for (const chunk of compilation.chunks) { + if (chunk.canBeInitial()) { + for (const module of chunk.modulesIterable) { + if (module.type.startsWith("webassembly")) { + initialWasmModules.add(module); + } + } + } + } + for (const module of initialWasmModules) { + compilation.errors.push( + new WebAssemblyInInitialChunkError( + module, + compilation.requestShortener + ) + ); + } + }); + } + ); + } + + renderWebAssembly(module, moduleTemplate, dependencyTemplates) { + return moduleTemplate.render(module, dependencyTemplates, {}); + } +} + +module.exports = WebAssemblyModulesPlugin; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyParser.js b/node_modules/webpack/lib/wasm/WebAssemblyParser.js new file mode 100644 index 0000000..eb49fb1 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyParser.js @@ -0,0 +1,175 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const t = require("@webassemblyjs/ast"); +const { decode } = require("@webassemblyjs/wasm-parser"); +const { + moduleContextFromModuleAST +} = require("@webassemblyjs/helper-module-context"); + +const { Tapable } = require("tapable"); +const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); +const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); + +/** @typedef {import("../Module")} Module */ + +const JS_COMPAT_TYPES = new Set(["i32", "f32", "f64"]); + +/** + * @param {t.Signature} signature the func signature + * @returns {null | string} the type incompatible with js types + */ +const getJsIncompatibleType = signature => { + for (const param of signature.params) { + if (!JS_COMPAT_TYPES.has(param.valtype)) { + return `${param.valtype} as parameter`; + } + } + for (const type of signature.results) { + if (!JS_COMPAT_TYPES.has(type)) return `${type} as result`; + } + return null; +}; + +/** + * TODO why are there two different Signature types? + * @param {t.FuncSignature} signature the func signature + * @returns {null | string} the type incompatible with js types + */ +const getJsIncompatibleTypeOfFuncSignature = signature => { + for (const param of signature.args) { + if (!JS_COMPAT_TYPES.has(param)) { + return `${param} as parameter`; + } + } + for (const type of signature.result) { + if (!JS_COMPAT_TYPES.has(type)) return `${type} as result`; + } + return null; +}; + +const decoderOpts = { + ignoreCodeSection: true, + ignoreDataSection: true, + + // this will avoid having to lookup with identifiers in the ModuleContext + ignoreCustomNameSection: true +}; + +class WebAssemblyParser extends Tapable { + constructor(options) { + super(); + this.hooks = {}; + this.options = options; + } + + parse(binary, state) { + // flag it as ESM + state.module.buildMeta.exportsType = "namespace"; + + // parse it + const program = decode(binary, decoderOpts); + const module = program.body[0]; + + const moduleContext = moduleContextFromModuleAST(module); + + // extract imports and exports + const exports = (state.module.buildMeta.providedExports = []); + const jsIncompatibleExports = (state.module.buildMeta.jsIncompatibleExports = []); + + const importedGlobals = []; + t.traverse(module, { + ModuleExport({ node }) { + const descriptor = node.descr; + + if (descriptor.exportType === "Func") { + const funcidx = descriptor.id.value; + + /** @type {t.FuncSignature} */ + const funcSignature = moduleContext.getFunction(funcidx); + + const incompatibleType = getJsIncompatibleTypeOfFuncSignature( + funcSignature + ); + + if (incompatibleType) { + jsIncompatibleExports[node.name] = incompatibleType; + } + } + + exports.push(node.name); + + if (node.descr && node.descr.exportType === "Global") { + const refNode = importedGlobals[node.descr.id.value]; + if (refNode) { + const dep = new WebAssemblyExportImportedDependency( + node.name, + refNode.module, + refNode.name, + refNode.descr.valtype + ); + + state.module.addDependency(dep); + } + } + }, + + Global({ node }) { + const init = node.init[0]; + + let importNode = null; + + if (init.id === "get_global") { + const globalIdx = init.args[0].value; + + if (globalIdx < importedGlobals.length) { + importNode = importedGlobals[globalIdx]; + } + } + + importedGlobals.push(importNode); + }, + + ModuleImport({ node }) { + /** @type {false | string} */ + let onlyDirectImport = false; + + if (t.isMemory(node.descr) === true) { + onlyDirectImport = "Memory"; + } else if (t.isTable(node.descr) === true) { + onlyDirectImport = "Table"; + } else if (t.isFuncImportDescr(node.descr) === true) { + const incompatibleType = getJsIncompatibleType(node.descr.signature); + if (incompatibleType) { + onlyDirectImport = `Non-JS-compatible Func Sigurature (${incompatibleType})`; + } + } else if (t.isGlobalType(node.descr) === true) { + const type = node.descr.valtype; + if (!JS_COMPAT_TYPES.has(type)) { + onlyDirectImport = `Non-JS-compatible Global Type (${type})`; + } + } + + const dep = new WebAssemblyImportDependency( + node.module, + node.name, + node.descr, + onlyDirectImport + ); + + state.module.addDependency(dep); + + if (t.isGlobalType(node.descr)) { + importedGlobals.push(node); + } + } + }); + + return state; + } +} + +module.exports = WebAssemblyParser; diff --git a/node_modules/webpack/lib/wasm/WebAssemblyUtils.js b/node_modules/webpack/lib/wasm/WebAssemblyUtils.js new file mode 100644 index 0000000..75eb6d2 --- /dev/null +++ b/node_modules/webpack/lib/wasm/WebAssemblyUtils.js @@ -0,0 +1,59 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("../Template"); +const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); + +/** @typedef {import("../Module")} Module */ + +/** @typedef {Object} UsedWasmDependency + * @property {WebAssemblyImportDependency} dependency the dependency + * @property {string} name the export name + * @property {string} module the module name + */ + +const MANGLED_MODULE = "a"; + +/** + * @param {Module} module the module + * @param {boolean} mangle mangle module and export names + * @returns {UsedWasmDependency[]} used dependencies and (mangled) name + */ +const getUsedDependencies = (module, mangle) => { + /** @type {UsedWasmDependency[]} */ + const array = []; + let importIndex = 0; + for (const dep of module.dependencies) { + if (dep instanceof WebAssemblyImportDependency) { + if (dep.description.type === "GlobalType" || dep.module === null) { + continue; + } + + const exportName = dep.name; + // TODO add the following 3 lines when removing of ModuleExport is possible + // const importedModule = dep.module; + // const usedName = importedModule && importedModule.isUsed(exportName); + // if (usedName !== false) { + if (mangle) { + array.push({ + dependency: dep, + name: Template.numberToIdentifer(importIndex++), + module: MANGLED_MODULE + }); + } else { + array.push({ + dependency: dep, + name: exportName, + module: dep.request + }); + } + } + } + return array; +}; + +exports.getUsedDependencies = getUsedDependencies; +exports.MANGLED_MODULE = MANGLED_MODULE; diff --git a/node_modules/webpack/lib/web/FetchCompileWasmTemplatePlugin.js b/node_modules/webpack/lib/web/FetchCompileWasmTemplatePlugin.js new file mode 100644 index 0000000..025921f --- /dev/null +++ b/node_modules/webpack/lib/web/FetchCompileWasmTemplatePlugin.js @@ -0,0 +1,37 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WasmMainTemplatePlugin = require("../wasm/WasmMainTemplatePlugin"); + +class FetchCompileWasmTemplatePlugin { + constructor(options) { + this.options = options || {}; + } + + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "FetchCompileWasmTemplatePlugin", + compilation => { + const mainTemplate = compilation.mainTemplate; + const generateLoadBinaryCode = path => + `fetch(${mainTemplate.requireFn}.p + ${path})`; + + const plugin = new WasmMainTemplatePlugin( + Object.assign( + { + generateLoadBinaryCode, + supportsStreaming: true + }, + this.options + ) + ); + plugin.apply(mainTemplate); + } + ); + } +} + +module.exports = FetchCompileWasmTemplatePlugin; diff --git a/node_modules/webpack/lib/web/JsonpChunkTemplatePlugin.js b/node_modules/webpack/lib/web/JsonpChunkTemplatePlugin.js new file mode 100644 index 0000000..123dd52 --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpChunkTemplatePlugin.js @@ -0,0 +1,71 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +/** @typedef {import("../ChunkTemplate")} ChunkTemplate */ + +const getEntryInfo = chunk => { + return [chunk.entryModule].filter(Boolean).map(m => + [m.id].concat( + Array.from(chunk.groupsIterable)[0] + .chunks.filter(c => c !== chunk) + .map(c => c.id) + ) + ); +}; + +class JsonpChunkTemplatePlugin { + /** + * @param {ChunkTemplate} chunkTemplate the chunk template + * @returns {void} + */ + apply(chunkTemplate) { + chunkTemplate.hooks.render.tap( + "JsonpChunkTemplatePlugin", + (modules, chunk) => { + const jsonpFunction = chunkTemplate.outputOptions.jsonpFunction; + const globalObject = chunkTemplate.outputOptions.globalObject; + const source = new ConcatSource(); + const prefetchChunks = chunk.getChildIdsByOrders().prefetch; + source.add( + `(${globalObject}[${JSON.stringify( + jsonpFunction + )}] = ${globalObject}[${JSON.stringify( + jsonpFunction + )}] || []).push([${JSON.stringify(chunk.ids)},` + ); + source.add(modules); + const entries = getEntryInfo(chunk); + if (entries.length > 0) { + source.add(`,${JSON.stringify(entries)}`); + } else if (prefetchChunks && prefetchChunks.length) { + source.add(`,0`); + } + + if (prefetchChunks && prefetchChunks.length) { + source.add(`,${JSON.stringify(prefetchChunks)}`); + } + source.add("])"); + return source; + } + ); + chunkTemplate.hooks.hash.tap("JsonpChunkTemplatePlugin", hash => { + hash.update("JsonpChunkTemplatePlugin"); + hash.update("4"); + hash.update(`${chunkTemplate.outputOptions.jsonpFunction}`); + hash.update(`${chunkTemplate.outputOptions.globalObject}`); + }); + chunkTemplate.hooks.hashForChunk.tap( + "JsonpChunkTemplatePlugin", + (hash, chunk) => { + hash.update(JSON.stringify(getEntryInfo(chunk))); + hash.update(JSON.stringify(chunk.getChildIdsByOrders().prefetch) || ""); + } + ); + } +} +module.exports = JsonpChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/web/JsonpExportMainTemplatePlugin.js b/node_modules/webpack/lib/web/JsonpExportMainTemplatePlugin.js new file mode 100644 index 0000000..064b249 --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpExportMainTemplatePlugin.js @@ -0,0 +1,50 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +class JsonpExportMainTemplatePlugin { + /** + * @param {string} name jsonp function name + */ + constructor(name) { + this.name = name; + } + + apply(compilation) { + const { mainTemplate, chunkTemplate } = compilation; + + const onRenderWithEntry = (source, chunk, hash) => { + const name = mainTemplate.getAssetPath(this.name || "", { + hash, + chunk + }); + return new ConcatSource(`${name}(`, source, ");"); + }; + + for (const template of [mainTemplate, chunkTemplate]) { + template.hooks.renderWithEntry.tap( + "JsonpExportMainTemplatePlugin", + onRenderWithEntry + ); + } + + mainTemplate.hooks.globalHashPaths.tap( + "JsonpExportMainTemplatePlugin", + paths => { + if (this.name) paths.push(this.name); + return paths; + } + ); + + mainTemplate.hooks.hash.tap("JsonpExportMainTemplatePlugin", hash => { + hash.update("jsonp export"); + hash.update(`${this.name}`); + }); + } +} + +module.exports = JsonpExportMainTemplatePlugin; diff --git a/node_modules/webpack/lib/web/JsonpHotUpdateChunkTemplatePlugin.js b/node_modules/webpack/lib/web/JsonpHotUpdateChunkTemplatePlugin.js new file mode 100644 index 0000000..bff023c --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpHotUpdateChunkTemplatePlugin.js @@ -0,0 +1,39 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +class JsonpHotUpdateChunkTemplatePlugin { + apply(hotUpdateChunkTemplate) { + hotUpdateChunkTemplate.hooks.render.tap( + "JsonpHotUpdateChunkTemplatePlugin", + (modulesSource, modules, removedModules, hash, id) => { + const source = new ConcatSource(); + source.add( + `${ + hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + }(${JSON.stringify(id)},` + ); + source.add(modulesSource); + source.add(")"); + return source; + } + ); + hotUpdateChunkTemplate.hooks.hash.tap( + "JsonpHotUpdateChunkTemplatePlugin", + hash => { + hash.update("JsonpHotUpdateChunkTemplatePlugin"); + hash.update("3"); + hash.update( + `${hotUpdateChunkTemplate.outputOptions.hotUpdateFunction}` + ); + hash.update(`${hotUpdateChunkTemplate.outputOptions.library}`); + } + ); + } +} + +module.exports = JsonpHotUpdateChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/web/JsonpMainTemplate.runtime.js b/node_modules/webpack/lib/web/JsonpMainTemplate.runtime.js new file mode 100644 index 0000000..cbaa01e --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpMainTemplate.runtime.js @@ -0,0 +1,71 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// eslint-disable-next-line no-unused-vars +var hotAddUpdateChunk = undefined; +var parentHotUpdateCallback = undefined; +var $require$ = undefined; +var $hotMainFilename$ = undefined; +var $hotChunkFilename$ = undefined; +var $crossOriginLoading$ = undefined; + +module.exports = function() { + // eslint-disable-next-line no-unused-vars + function webpackHotUpdateCallback(chunkId, moreModules) { + hotAddUpdateChunk(chunkId, moreModules); + if (parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules); + } //$semicolon + + // eslint-disable-next-line no-unused-vars + function hotDownloadUpdateChunk(chunkId) { + var script = document.createElement("script"); + script.charset = "utf-8"; + script.src = $require$.p + $hotChunkFilename$; + if ($crossOriginLoading$) script.crossOrigin = $crossOriginLoading$; + document.head.appendChild(script); + } + + // eslint-disable-next-line no-unused-vars + function hotDownloadManifest(requestTimeout) { + requestTimeout = requestTimeout || 10000; + return new Promise(function(resolve, reject) { + if (typeof XMLHttpRequest === "undefined") { + return reject(new Error("No browser support")); + } + try { + var request = new XMLHttpRequest(); + var requestPath = $require$.p + $hotMainFilename$; + request.open("GET", requestPath, true); + request.timeout = requestTimeout; + request.send(null); + } catch (err) { + return reject(err); + } + request.onreadystatechange = function() { + if (request.readyState !== 4) return; + if (request.status === 0) { + // timeout + reject( + new Error("Manifest request to " + requestPath + " timed out.") + ); + } else if (request.status === 404) { + // no update available + resolve(); + } else if (request.status !== 200 && request.status !== 304) { + // other failure + reject(new Error("Manifest request to " + requestPath + " failed.")); + } else { + // success + try { + var update = JSON.parse(request.responseText); + } catch (e) { + reject(e); + return; + } + resolve(update); + } + }; + }); + } +}; diff --git a/node_modules/webpack/lib/web/JsonpMainTemplatePlugin.js b/node_modules/webpack/lib/web/JsonpMainTemplatePlugin.js new file mode 100644 index 0000000..5fcc8d8 --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpMainTemplatePlugin.js @@ -0,0 +1,615 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { SyncWaterfallHook } = require("tapable"); +const Template = require("../Template"); + +class JsonpMainTemplatePlugin { + apply(mainTemplate) { + const needChunkOnDemandLoadingCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.getNumberOfChildren() > 0) return true; + } + return false; + }; + const needChunkLoadingCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.chunks.length > 1) return true; + if (chunkGroup.getNumberOfChildren() > 0) return true; + } + return false; + }; + const needEntryDeferringCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.chunks.length > 1) return true; + } + return false; + }; + const needPrefetchingCode = chunk => { + const allPrefetchChunks = chunk.getChildIdsByOrdersMap(true).prefetch; + return allPrefetchChunks && Object.keys(allPrefetchChunks).length; + }; + + // TODO webpack 5, no adding to .hooks, use WeakMap and static methods + ["jsonpScript", "linkPreload", "linkPrefetch"].forEach(hook => { + if (!mainTemplate.hooks[hook]) { + mainTemplate.hooks[hook] = new SyncWaterfallHook([ + "source", + "chunk", + "hash" + ]); + } + }); + + const getScriptSrcPath = (hash, chunk, chunkIdExpression) => { + const chunkFilename = mainTemplate.outputOptions.chunkFilename; + const chunkMaps = chunk.getChunkMaps(); + return mainTemplate.getAssetPath(JSON.stringify(chunkFilename), { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + chunk: { + id: `" + ${chunkIdExpression} + "`, + hash: `" + ${JSON.stringify( + chunkMaps.hash + )}[${chunkIdExpression}] + "`, + hashWithLength(length) { + const shortChunkHashMap = Object.create(null); + for (const chunkId of Object.keys(chunkMaps.hash)) { + if (typeof chunkMaps.hash[chunkId] === "string") { + shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr( + 0, + length + ); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap + )}[${chunkIdExpression}] + "`; + }, + name: `" + (${JSON.stringify( + chunkMaps.name + )}[${chunkIdExpression}]||${chunkIdExpression}) + "`, + contentHash: { + javascript: `" + ${JSON.stringify( + chunkMaps.contentHash.javascript + )}[${chunkIdExpression}] + "` + }, + contentHashWithLength: { + javascript: length => { + const shortContentHashMap = {}; + const contentHash = chunkMaps.contentHash.javascript; + for (const chunkId of Object.keys(contentHash)) { + if (typeof contentHash[chunkId] === "string") { + shortContentHashMap[chunkId] = contentHash[chunkId].substr( + 0, + length + ); + } + } + return `" + ${JSON.stringify( + shortContentHashMap + )}[${chunkIdExpression}] + "`; + } + } + }, + contentHashType: "javascript" + }); + }; + mainTemplate.hooks.localVars.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + const extraCode = []; + if (needChunkLoadingCode(chunk)) { + extraCode.push( + "", + "// object to store loaded and loading chunks", + "// undefined = chunk not loaded, null = chunk preloaded/prefetched", + "// Promise = chunk loading, 0 = chunk loaded", + "var installedChunks = {", + Template.indent( + chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(",\n") + ), + "};", + "", + needEntryDeferringCode(chunk) + ? needPrefetchingCode(chunk) + ? "var deferredModules = [], deferredPrefetch = [];" + : "var deferredModules = [];" + : "" + ); + } + if (needChunkOnDemandLoadingCode(chunk)) { + extraCode.push( + "", + "// script path function", + "function jsonpScriptSrc(chunkId) {", + Template.indent([ + `return ${mainTemplate.requireFn}.p + ${getScriptSrcPath( + hash, + chunk, + "chunkId" + )}` + ]), + "}" + ); + } + if (extraCode.length === 0) return source; + return Template.asString([source, ...extraCode]); + } + ); + + mainTemplate.hooks.jsonpScript.tap( + "JsonpMainTemplatePlugin", + (_, chunk, hash) => { + const crossOriginLoading = + mainTemplate.outputOptions.crossOriginLoading; + const chunkLoadTimeout = mainTemplate.outputOptions.chunkLoadTimeout; + const jsonpScriptType = mainTemplate.outputOptions.jsonpScriptType; + + return Template.asString([ + "var script = document.createElement('script');", + "var onScriptComplete;", + jsonpScriptType + ? `script.type = ${JSON.stringify(jsonpScriptType)};` + : "", + "script.charset = 'utf-8';", + `script.timeout = ${chunkLoadTimeout / 1000};`, + `if (${mainTemplate.requireFn}.nc) {`, + Template.indent( + `script.setAttribute("nonce", ${mainTemplate.requireFn}.nc);` + ), + "}", + "script.src = jsonpScriptSrc(chunkId);", + crossOriginLoading + ? Template.asString([ + "if (script.src.indexOf(window.location.origin + '/') !== 0) {", + Template.indent( + `script.crossOrigin = ${JSON.stringify(crossOriginLoading)};` + ), + "}" + ]) + : "", + "// create error before stack unwound to get useful stacktrace later", + "var error = new Error();", + "onScriptComplete = function (event) {", + Template.indent([ + "// avoid mem leaks in IE.", + "script.onerror = script.onload = null;", + "clearTimeout(timeout);", + "var chunk = installedChunks[chunkId];", + "if(chunk !== 0) {", + Template.indent([ + "if(chunk) {", + Template.indent([ + "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", + "var realSrc = event && event.target && event.target.src;", + "error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';", + "error.name = 'ChunkLoadError';", + "error.type = errorType;", + "error.request = realSrc;", + "chunk[1](error);" + ]), + "}", + "installedChunks[chunkId] = undefined;" + ]), + "}" + ]), + "};", + "var timeout = setTimeout(function(){", + Template.indent([ + "onScriptComplete({ type: 'timeout', target: script });" + ]), + `}, ${chunkLoadTimeout});`, + "script.onerror = script.onload = onScriptComplete;" + ]); + } + ); + mainTemplate.hooks.linkPreload.tap( + "JsonpMainTemplatePlugin", + (_, chunk, hash) => { + const crossOriginLoading = + mainTemplate.outputOptions.crossOriginLoading; + const jsonpScriptType = mainTemplate.outputOptions.jsonpScriptType; + + return Template.asString([ + "var link = document.createElement('link');", + jsonpScriptType + ? `link.type = ${JSON.stringify(jsonpScriptType)};` + : "", + "link.charset = 'utf-8';", + `if (${mainTemplate.requireFn}.nc) {`, + Template.indent( + `link.setAttribute("nonce", ${mainTemplate.requireFn}.nc);` + ), + "}", + 'link.rel = "preload";', + 'link.as = "script";', + "link.href = jsonpScriptSrc(chunkId);", + crossOriginLoading + ? Template.asString([ + "if (link.href.indexOf(window.location.origin + '/') !== 0) {", + Template.indent( + `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};` + ), + "}" + ]) + : "" + ]); + } + ); + mainTemplate.hooks.linkPrefetch.tap( + "JsonpMainTemplatePlugin", + (_, chunk, hash) => { + const crossOriginLoading = + mainTemplate.outputOptions.crossOriginLoading; + + return Template.asString([ + "var link = document.createElement('link');", + crossOriginLoading + ? `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};` + : "", + `if (${mainTemplate.requireFn}.nc) {`, + Template.indent( + `link.setAttribute("nonce", ${mainTemplate.requireFn}.nc);` + ), + "}", + 'link.rel = "prefetch";', + 'link.as = "script";', + "link.href = jsonpScriptSrc(chunkId);" + ]); + } + ); + mainTemplate.hooks.requireEnsure.tap( + "JsonpMainTemplatePlugin load", + (source, chunk, hash) => { + return Template.asString([ + source, + "", + "// JSONP chunk loading for javascript", + "", + "var installedChunkData = installedChunks[chunkId];", + 'if(installedChunkData !== 0) { // 0 means "already installed".', + Template.indent([ + "", + '// a Promise means "currently loading".', + "if(installedChunkData) {", + Template.indent(["promises.push(installedChunkData[2]);"]), + "} else {", + Template.indent([ + "// setup Promise in chunk cache", + "var promise = new Promise(function(resolve, reject) {", + Template.indent([ + "installedChunkData = installedChunks[chunkId] = [resolve, reject];" + ]), + "});", + "promises.push(installedChunkData[2] = promise);", + "", + "// start chunk loading", + mainTemplate.hooks.jsonpScript.call("", chunk, hash), + "document.head.appendChild(script);" + ]), + "}" + ]), + "}" + ]); + } + ); + mainTemplate.hooks.requireEnsure.tap( + { + name: "JsonpMainTemplatePlugin preload", + stage: 10 + }, + (source, chunk, hash) => { + const chunkMap = chunk.getChildIdsByOrdersMap().preload; + if (!chunkMap || Object.keys(chunkMap).length === 0) return source; + return Template.asString([ + source, + "", + "// chunk preloadng for javascript", + "", + `var chunkPreloadMap = ${JSON.stringify(chunkMap, null, "\t")};`, + "", + "var chunkPreloadData = chunkPreloadMap[chunkId];", + "if(chunkPreloadData) {", + Template.indent([ + "chunkPreloadData.forEach(function(chunkId) {", + Template.indent([ + "if(installedChunks[chunkId] === undefined) {", + Template.indent([ + "installedChunks[chunkId] = null;", + mainTemplate.hooks.linkPreload.call("", chunk, hash), + "document.head.appendChild(link);" + ]), + "}" + ]), + "});" + ]), + "}" + ]); + } + ); + mainTemplate.hooks.requireExtensions.tap( + "JsonpMainTemplatePlugin", + (source, chunk) => { + if (!needChunkOnDemandLoadingCode(chunk)) return source; + + return Template.asString([ + source, + "", + "// on error function for async loading", + `${mainTemplate.requireFn}.oe = function(err) { console.error(err); throw err; };` + ]); + } + ); + mainTemplate.hooks.bootstrap.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + if (needChunkLoadingCode(chunk)) { + const withDefer = needEntryDeferringCode(chunk); + const withPrefetch = needPrefetchingCode(chunk); + return Template.asString([ + source, + "", + "// install a JSONP callback for chunk loading", + "function webpackJsonpCallback(data) {", + Template.indent([ + "var chunkIds = data[0];", + "var moreModules = data[1];", + withDefer ? "var executeModules = data[2];" : "", + withPrefetch ? "var prefetchChunks = data[3] || [];" : "", + '// add "moreModules" to the modules object,', + '// then flag all "chunkIds" as loaded and fire callback', + "var moduleId, chunkId, i = 0, resolves = [];", + "for(;i < chunkIds.length; i++) {", + Template.indent([ + "chunkId = chunkIds[i];", + "if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {", + Template.indent("resolves.push(installedChunks[chunkId][0]);"), + "}", + "installedChunks[chunkId] = 0;" + ]), + "}", + "for(moduleId in moreModules) {", + Template.indent([ + "if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {", + Template.indent( + mainTemplate.renderAddModule( + hash, + chunk, + "moduleId", + "moreModules[moduleId]" + ) + ), + "}" + ]), + "}", + "if(parentJsonpFunction) parentJsonpFunction(data);", + withPrefetch + ? withDefer + ? "deferredPrefetch.push.apply(deferredPrefetch, prefetchChunks);" + : Template.asString([ + "// chunk prefetching for javascript", + "prefetchChunks.forEach(function(chunkId) {", + Template.indent([ + "if(installedChunks[chunkId] === undefined) {", + Template.indent([ + "installedChunks[chunkId] = null;", + mainTemplate.hooks.linkPrefetch.call("", chunk, hash), + "document.head.appendChild(link);" + ]), + "}" + ]), + "});" + ]) + : "", + "while(resolves.length) {", + Template.indent("resolves.shift()();"), + "}", + withDefer + ? Template.asString([ + "", + "// add entry modules from loaded chunk to deferred list", + "deferredModules.push.apply(deferredModules, executeModules || []);", + "", + "// run deferred modules when all chunks ready", + "return checkDeferredModules();" + ]) + : "" + ]), + "};", + withDefer + ? Template.asString([ + "function checkDeferredModules() {", + Template.indent([ + "var result;", + "for(var i = 0; i < deferredModules.length; i++) {", + Template.indent([ + "var deferredModule = deferredModules[i];", + "var fulfilled = true;", + "for(var j = 1; j < deferredModule.length; j++) {", + Template.indent([ + "var depId = deferredModule[j];", + "if(installedChunks[depId] !== 0) fulfilled = false;" + ]), + "}", + "if(fulfilled) {", + Template.indent([ + "deferredModules.splice(i--, 1);", + "result = " + + mainTemplate.requireFn + + "(" + + mainTemplate.requireFn + + ".s = deferredModule[0]);" + ]), + "}" + ]), + "}", + withPrefetch + ? Template.asString([ + "if(deferredModules.length === 0) {", + Template.indent([ + "// chunk prefetching for javascript", + "deferredPrefetch.forEach(function(chunkId) {", + Template.indent([ + "if(installedChunks[chunkId] === undefined) {", + Template.indent([ + "installedChunks[chunkId] = null;", + mainTemplate.hooks.linkPrefetch.call( + "", + chunk, + hash + ), + "document.head.appendChild(link);" + ]), + "}" + ]), + "});", + "deferredPrefetch.length = 0;" + ]), + "}" + ]) + : "", + "return result;" + ]), + "}" + ]) + : "" + ]); + } + return source; + } + ); + mainTemplate.hooks.beforeStartup.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + if (needChunkLoadingCode(chunk)) { + var jsonpFunction = mainTemplate.outputOptions.jsonpFunction; + var globalObject = mainTemplate.outputOptions.globalObject; + return Template.asString([ + `var jsonpArray = ${globalObject}[${JSON.stringify( + jsonpFunction + )}] = ${globalObject}[${JSON.stringify(jsonpFunction)}] || [];`, + "var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);", + "jsonpArray.push = webpackJsonpCallback;", + "jsonpArray = jsonpArray.slice();", + "for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);", + "var parentJsonpFunction = oldJsonpFunction;", + "", + source + ]); + } + return source; + } + ); + mainTemplate.hooks.afterStartup.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + const prefetchChunks = chunk.getChildIdsByOrders().prefetch; + if ( + needChunkLoadingCode(chunk) && + prefetchChunks && + prefetchChunks.length + ) { + return Template.asString([ + source, + `webpackJsonpCallback([[], {}, 0, ${JSON.stringify( + prefetchChunks + )}]);` + ]); + } + return source; + } + ); + mainTemplate.hooks.startup.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + if (needEntryDeferringCode(chunk)) { + if (chunk.hasEntryModule()) { + const entries = [chunk.entryModule].filter(Boolean).map(m => + [m.id].concat( + Array.from(chunk.groupsIterable)[0] + .chunks.filter(c => c !== chunk) + .map(c => c.id) + ) + ); + return Template.asString([ + "// add entry module to deferred list", + `deferredModules.push(${entries + .map(e => JSON.stringify(e)) + .join(", ")});`, + "// run deferred modules when ready", + "return checkDeferredModules();" + ]); + } else { + return Template.asString([ + "// run deferred modules from other chunks", + "checkDeferredModules();" + ]); + } + } + return source; + } + ); + mainTemplate.hooks.hotBootstrap.tap( + "JsonpMainTemplatePlugin", + (source, chunk, hash) => { + const globalObject = mainTemplate.outputOptions.globalObject; + const hotUpdateChunkFilename = + mainTemplate.outputOptions.hotUpdateChunkFilename; + const hotUpdateMainFilename = + mainTemplate.outputOptions.hotUpdateMainFilename; + const crossOriginLoading = + mainTemplate.outputOptions.crossOriginLoading; + const hotUpdateFunction = mainTemplate.outputOptions.hotUpdateFunction; + const currentHotUpdateChunkFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateChunkFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + chunk: { + id: '" + chunkId + "' + } + } + ); + const currentHotUpdateMainFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateMainFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "` + } + ); + const runtimeSource = Template.getFunctionContent( + require("./JsonpMainTemplate.runtime") + ) + .replace(/\/\/\$semicolon/g, ";") + .replace(/\$require\$/g, mainTemplate.requireFn) + .replace( + /\$crossOriginLoading\$/g, + crossOriginLoading ? JSON.stringify(crossOriginLoading) : "null" + ) + .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) + .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename) + .replace(/\$hash\$/g, JSON.stringify(hash)); + return `${source} +function hotDisposeChunk(chunkId) { + delete installedChunks[chunkId]; +} +var parentHotUpdateCallback = ${globalObject}[${JSON.stringify( + hotUpdateFunction + )}]; +${globalObject}[${JSON.stringify(hotUpdateFunction)}] = ${runtimeSource}`; + } + ); + mainTemplate.hooks.hash.tap("JsonpMainTemplatePlugin", hash => { + hash.update("jsonp"); + hash.update("6"); + }); + } +} +module.exports = JsonpMainTemplatePlugin; diff --git a/node_modules/webpack/lib/web/JsonpTemplatePlugin.js b/node_modules/webpack/lib/web/JsonpTemplatePlugin.js new file mode 100644 index 0000000..80a6b5b --- /dev/null +++ b/node_modules/webpack/lib/web/JsonpTemplatePlugin.js @@ -0,0 +1,23 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const JsonpMainTemplatePlugin = require("./JsonpMainTemplatePlugin"); +const JsonpChunkTemplatePlugin = require("./JsonpChunkTemplatePlugin"); +const JsonpHotUpdateChunkTemplatePlugin = require("./JsonpHotUpdateChunkTemplatePlugin"); + +class JsonpTemplatePlugin { + apply(compiler) { + compiler.hooks.thisCompilation.tap("JsonpTemplatePlugin", compilation => { + new JsonpMainTemplatePlugin().apply(compilation.mainTemplate); + new JsonpChunkTemplatePlugin().apply(compilation.chunkTemplate); + new JsonpHotUpdateChunkTemplatePlugin().apply( + compilation.hotUpdateChunkTemplate + ); + }); + } +} + +module.exports = JsonpTemplatePlugin; diff --git a/node_modules/webpack/lib/web/WebEnvironmentPlugin.js b/node_modules/webpack/lib/web/WebEnvironmentPlugin.js new file mode 100644 index 0000000..9b0df57 --- /dev/null +++ b/node_modules/webpack/lib/web/WebEnvironmentPlugin.js @@ -0,0 +1,18 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class WebEnvironmentPlugin { + constructor(inputFileSystem, outputFileSystem) { + this.inputFileSystem = inputFileSystem; + this.outputFileSystem = outputFileSystem; + } + + apply(compiler) { + compiler.outputFileSystem = this.outputFileSystem; + } +} + +module.exports = WebEnvironmentPlugin; diff --git a/node_modules/webpack/lib/webpack.js b/node_modules/webpack/lib/webpack.js new file mode 100644 index 0000000..80f810b --- /dev/null +++ b/node_modules/webpack/lib/webpack.js @@ -0,0 +1,206 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Compiler = require("./Compiler"); +const MultiCompiler = require("./MultiCompiler"); +const NodeEnvironmentPlugin = require("./node/NodeEnvironmentPlugin"); +const WebpackOptionsApply = require("./WebpackOptionsApply"); +const WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter"); +const validateSchema = require("./validateSchema"); +const WebpackOptionsValidationError = require("./WebpackOptionsValidationError"); +const webpackOptionsSchema = require("../schemas/WebpackOptions.json"); +const RemovedPluginError = require("./RemovedPluginError"); +const version = require("../package.json").version; + +/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */ + +/** + * @param {WebpackOptions} options options object + * @param {function(Error=, Stats=): void=} callback callback + * @returns {Compiler | MultiCompiler} the compiler object + */ +const webpack = (options, callback) => { + const webpackOptionsValidationErrors = validateSchema( + webpackOptionsSchema, + options + ); + if (webpackOptionsValidationErrors.length) { + throw new WebpackOptionsValidationError(webpackOptionsValidationErrors); + } + let compiler; + if (Array.isArray(options)) { + compiler = new MultiCompiler( + Array.from(options).map(options => webpack(options)) + ); + } else if (typeof options === "object") { + options = new WebpackOptionsDefaulter().process(options); + + compiler = new Compiler(options.context); + compiler.options = options; + new NodeEnvironmentPlugin({ + infrastructureLogging: options.infrastructureLogging + }).apply(compiler); + if (options.plugins && Array.isArray(options.plugins)) { + for (const plugin of options.plugins) { + if (typeof plugin === "function") { + plugin.call(compiler, compiler); + } else { + plugin.apply(compiler); + } + } + } + compiler.hooks.environment.call(); + compiler.hooks.afterEnvironment.call(); + compiler.options = new WebpackOptionsApply().process(options, compiler); + } else { + throw new Error("Invalid argument: options"); + } + if (callback) { + if (typeof callback !== "function") { + throw new Error("Invalid argument: callback"); + } + if ( + options.watch === true || + (Array.isArray(options) && options.some(o => o.watch)) + ) { + const watchOptions = Array.isArray(options) + ? options.map(o => o.watchOptions || {}) + : options.watchOptions || {}; + return compiler.watch(watchOptions, callback); + } + compiler.run(callback); + } + return compiler; +}; + +exports = module.exports = webpack; +exports.version = version; + +webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter; +webpack.WebpackOptionsApply = WebpackOptionsApply; +webpack.Compiler = Compiler; +webpack.MultiCompiler = MultiCompiler; +webpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin; +// @ts-ignore Global @this directive is not supported +webpack.validate = validateSchema.bind(this, webpackOptionsSchema); +webpack.validateSchema = validateSchema; +webpack.WebpackOptionsValidationError = WebpackOptionsValidationError; + +const exportPlugins = (obj, mappings) => { + for (const name of Object.keys(mappings)) { + Object.defineProperty(obj, name, { + configurable: false, + enumerable: true, + get: mappings[name] + }); + } +}; + +exportPlugins(exports, { + AutomaticPrefetchPlugin: () => require("./AutomaticPrefetchPlugin"), + BannerPlugin: () => require("./BannerPlugin"), + CachePlugin: () => require("./CachePlugin"), + ContextExclusionPlugin: () => require("./ContextExclusionPlugin"), + ContextReplacementPlugin: () => require("./ContextReplacementPlugin"), + DefinePlugin: () => require("./DefinePlugin"), + Dependency: () => require("./Dependency"), + DllPlugin: () => require("./DllPlugin"), + DllReferencePlugin: () => require("./DllReferencePlugin"), + EnvironmentPlugin: () => require("./EnvironmentPlugin"), + EvalDevToolModulePlugin: () => require("./EvalDevToolModulePlugin"), + EvalSourceMapDevToolPlugin: () => require("./EvalSourceMapDevToolPlugin"), + ExtendedAPIPlugin: () => require("./ExtendedAPIPlugin"), + ExternalsPlugin: () => require("./ExternalsPlugin"), + HashedModuleIdsPlugin: () => require("./HashedModuleIdsPlugin"), + HotModuleReplacementPlugin: () => require("./HotModuleReplacementPlugin"), + IgnorePlugin: () => require("./IgnorePlugin"), + LibraryTemplatePlugin: () => require("./LibraryTemplatePlugin"), + LoaderOptionsPlugin: () => require("./LoaderOptionsPlugin"), + LoaderTargetPlugin: () => require("./LoaderTargetPlugin"), + MemoryOutputFileSystem: () => require("./MemoryOutputFileSystem"), + Module: () => require("./Module"), + ModuleFilenameHelpers: () => require("./ModuleFilenameHelpers"), + NamedChunksPlugin: () => require("./NamedChunksPlugin"), + NamedModulesPlugin: () => require("./NamedModulesPlugin"), + NoEmitOnErrorsPlugin: () => require("./NoEmitOnErrorsPlugin"), + NormalModuleReplacementPlugin: () => + require("./NormalModuleReplacementPlugin"), + PrefetchPlugin: () => require("./PrefetchPlugin"), + ProgressPlugin: () => require("./ProgressPlugin"), + ProvidePlugin: () => require("./ProvidePlugin"), + SetVarMainTemplatePlugin: () => require("./SetVarMainTemplatePlugin"), + SingleEntryPlugin: () => require("./SingleEntryPlugin"), + SourceMapDevToolPlugin: () => require("./SourceMapDevToolPlugin"), + Stats: () => require("./Stats"), + Template: () => require("./Template"), + UmdMainTemplatePlugin: () => require("./UmdMainTemplatePlugin"), + WatchIgnorePlugin: () => require("./WatchIgnorePlugin") +}); +exportPlugins((exports.dependencies = {}), { + DependencyReference: () => require("./dependencies/DependencyReference") +}); +exportPlugins((exports.optimize = {}), { + AggressiveMergingPlugin: () => require("./optimize/AggressiveMergingPlugin"), + AggressiveSplittingPlugin: () => + require("./optimize/AggressiveSplittingPlugin"), + ChunkModuleIdRangePlugin: () => + require("./optimize/ChunkModuleIdRangePlugin"), + LimitChunkCountPlugin: () => require("./optimize/LimitChunkCountPlugin"), + MinChunkSizePlugin: () => require("./optimize/MinChunkSizePlugin"), + ModuleConcatenationPlugin: () => + require("./optimize/ModuleConcatenationPlugin"), + OccurrenceOrderPlugin: () => require("./optimize/OccurrenceOrderPlugin"), + OccurrenceModuleOrderPlugin: () => + require("./optimize/OccurrenceModuleOrderPlugin"), + OccurrenceChunkOrderPlugin: () => + require("./optimize/OccurrenceChunkOrderPlugin"), + RuntimeChunkPlugin: () => require("./optimize/RuntimeChunkPlugin"), + SideEffectsFlagPlugin: () => require("./optimize/SideEffectsFlagPlugin"), + SplitChunksPlugin: () => require("./optimize/SplitChunksPlugin") +}); +exportPlugins((exports.web = {}), { + FetchCompileWasmTemplatePlugin: () => + require("./web/FetchCompileWasmTemplatePlugin"), + JsonpTemplatePlugin: () => require("./web/JsonpTemplatePlugin") +}); +exportPlugins((exports.webworker = {}), { + WebWorkerTemplatePlugin: () => require("./webworker/WebWorkerTemplatePlugin") +}); +exportPlugins((exports.node = {}), { + NodeTemplatePlugin: () => require("./node/NodeTemplatePlugin"), + ReadFileCompileWasmTemplatePlugin: () => + require("./node/ReadFileCompileWasmTemplatePlugin") +}); +exportPlugins((exports.debug = {}), { + ProfilingPlugin: () => require("./debug/ProfilingPlugin") +}); +exportPlugins((exports.util = {}), { + createHash: () => require("./util/createHash") +}); + +const defineMissingPluginError = (namespace, pluginName, errorMessage) => { + Object.defineProperty(namespace, pluginName, { + configurable: false, + enumerable: true, + get() { + throw new RemovedPluginError(errorMessage); + } + }); +}; + +// TODO remove in webpack 5 +defineMissingPluginError( + exports.optimize, + "UglifyJsPlugin", + "webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead." +); + +// TODO remove in webpack 5 +defineMissingPluginError( + exports.optimize, + "CommonsChunkPlugin", + "webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead." +); diff --git a/node_modules/webpack/lib/webpack.web.js b/node_modules/webpack/lib/webpack.web.js new file mode 100644 index 0000000..1f60eab --- /dev/null +++ b/node_modules/webpack/lib/webpack.web.js @@ -0,0 +1,31 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Compiler = require("./Compiler"); +const WebEnvironmentPlugin = require("./web/WebEnvironmentPlugin"); +const WebpackOptionsApply = require("./WebpackOptionsApply"); +const WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter"); + +const webpack = (options, callback) => { + new WebpackOptionsDefaulter().process(options); + + const compiler = new Compiler(); + compiler.options = new WebpackOptionsApply().process(options, compiler); + new WebEnvironmentPlugin( + options.inputFileSystem, + options.outputFileSystem + ).apply(compiler); + if (callback) { + compiler.run(callback); + } + return compiler; +}; +module.exports = webpack; + +webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter; +webpack.WebpackOptionsApply = WebpackOptionsApply; +webpack.Compiler = Compiler; +webpack.WebEnvironmentPlugin = WebEnvironmentPlugin; diff --git a/node_modules/webpack/lib/webworker/WebWorkerChunkTemplatePlugin.js b/node_modules/webpack/lib/webworker/WebWorkerChunkTemplatePlugin.js new file mode 100644 index 0000000..f44ca26 --- /dev/null +++ b/node_modules/webpack/lib/webworker/WebWorkerChunkTemplatePlugin.js @@ -0,0 +1,35 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const { ConcatSource } = require("webpack-sources"); + +class WebWorkerChunkTemplatePlugin { + apply(chunkTemplate) { + chunkTemplate.hooks.render.tap( + "WebWorkerChunkTemplatePlugin", + (modules, chunk) => { + const chunkCallbackName = chunkTemplate.outputOptions.chunkCallbackName; + const globalObject = chunkTemplate.outputOptions.globalObject; + const source = new ConcatSource(); + source.add( + `${globalObject}[${JSON.stringify( + chunkCallbackName + )}](${JSON.stringify(chunk.ids)},` + ); + source.add(modules); + source.add(")"); + return source; + } + ); + chunkTemplate.hooks.hash.tap("WebWorkerChunkTemplatePlugin", hash => { + hash.update("webworker"); + hash.update("3"); + hash.update(`${chunkTemplate.outputOptions.chunkCallbackName}`); + hash.update(`${chunkTemplate.outputOptions.globalObject}`); + }); + } +} +module.exports = WebWorkerChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/webworker/WebWorkerHotUpdateChunkTemplatePlugin.js b/node_modules/webpack/lib/webworker/WebWorkerHotUpdateChunkTemplatePlugin.js new file mode 100644 index 0000000..8b02611 --- /dev/null +++ b/node_modules/webpack/lib/webworker/WebWorkerHotUpdateChunkTemplatePlugin.js @@ -0,0 +1,40 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +const { ConcatSource } = require("webpack-sources"); + +class WebWorkerHotUpdateChunkTemplatePlugin { + apply(hotUpdateChunkTemplate) { + hotUpdateChunkTemplate.hooks.render.tap( + "WebWorkerHotUpdateChunkTemplatePlugin", + (modulesSource, modules, removedModules, hash, id) => { + const hotUpdateFunction = + hotUpdateChunkTemplate.outputOptions.hotUpdateFunction; + const globalObject = hotUpdateChunkTemplate.outputOptions.globalObject; + const source = new ConcatSource(); + source.add( + `${globalObject}[${JSON.stringify( + hotUpdateFunction + )}](${JSON.stringify(id)},` + ); + source.add(modulesSource); + source.add(")"); + return source; + } + ); + hotUpdateChunkTemplate.hooks.hash.tap( + "WebWorkerHotUpdateChunkTemplatePlugin", + hash => { + hash.update("WebWorkerHotUpdateChunkTemplatePlugin"); + hash.update("3"); + hash.update( + hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + "" + ); + hash.update(hotUpdateChunkTemplate.outputOptions.globalObject + ""); + } + ); + } +} +module.exports = WebWorkerHotUpdateChunkTemplatePlugin; diff --git a/node_modules/webpack/lib/webworker/WebWorkerMainTemplate.runtime.js b/node_modules/webpack/lib/webworker/WebWorkerMainTemplate.runtime.js new file mode 100644 index 0000000..aa240b2 --- /dev/null +++ b/node_modules/webpack/lib/webworker/WebWorkerMainTemplate.runtime.js @@ -0,0 +1,73 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// eslint-disable-next-line no-unused-vars +var hotAddUpdateChunk = undefined; +var parentHotUpdateCallback = undefined; +var $require$ = undefined; +var $hotChunkFilename$ = undefined; +var $hotMainFilename$ = undefined; +var installedChunks = undefined; +var importScripts = undefined; + +module.exports = function() { + // eslint-disable-next-line no-unused-vars + function webpackHotUpdateCallback(chunkId, moreModules) { + hotAddUpdateChunk(chunkId, moreModules); + if (parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules); + } //$semicolon + + // eslint-disable-next-line no-unused-vars + function hotDownloadUpdateChunk(chunkId) { + importScripts($require$.p + $hotChunkFilename$); + } + + // eslint-disable-next-line no-unused-vars + function hotDownloadManifest(requestTimeout) { + requestTimeout = requestTimeout || 10000; + return new Promise(function(resolve, reject) { + if (typeof XMLHttpRequest === "undefined") { + return reject(new Error("No browser support")); + } + try { + var request = new XMLHttpRequest(); + var requestPath = $require$.p + $hotMainFilename$; + request.open("GET", requestPath, true); + request.timeout = requestTimeout; + request.send(null); + } catch (err) { + return reject(err); + } + request.onreadystatechange = function() { + if (request.readyState !== 4) return; + if (request.status === 0) { + // timeout + reject( + new Error("Manifest request to " + requestPath + " timed out.") + ); + } else if (request.status === 404) { + // no update available + resolve(); + } else if (request.status !== 200 && request.status !== 304) { + // other failure + reject(new Error("Manifest request to " + requestPath + " failed.")); + } else { + // success + try { + var update = JSON.parse(request.responseText); + } catch (e) { + reject(e); + return; + } + resolve(update); + } + }; + }); + } + + //eslint-disable-next-line no-unused-vars + function hotDisposeChunk(chunkId) { + delete installedChunks[chunkId]; + } +}; diff --git a/node_modules/webpack/lib/webworker/WebWorkerMainTemplatePlugin.js b/node_modules/webpack/lib/webworker/WebWorkerMainTemplatePlugin.js new file mode 100644 index 0000000..0cc84c6 --- /dev/null +++ b/node_modules/webpack/lib/webworker/WebWorkerMainTemplatePlugin.js @@ -0,0 +1,192 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Template = require("../Template"); + +class WebWorkerMainTemplatePlugin { + apply(mainTemplate) { + const needChunkOnDemandLoadingCode = chunk => { + for (const chunkGroup of chunk.groupsIterable) { + if (chunkGroup.getNumberOfChildren() > 0) return true; + } + return false; + }; + mainTemplate.hooks.localVars.tap( + "WebWorkerMainTemplatePlugin", + (source, chunk) => { + if (needChunkOnDemandLoadingCode(chunk)) { + return Template.asString([ + source, + "", + "// object to store loaded chunks", + '// "1" means "already loaded"', + "var installedChunks = {", + Template.indent( + chunk.ids.map(id => `${JSON.stringify(id)}: 1`).join(",\n") + ), + "};" + ]); + } + return source; + } + ); + mainTemplate.hooks.requireEnsure.tap( + "WebWorkerMainTemplatePlugin", + (_, chunk, hash) => { + const chunkFilename = mainTemplate.outputOptions.chunkFilename; + const chunkMaps = chunk.getChunkMaps(); + return Template.asString([ + "promises.push(Promise.resolve().then(function() {", + Template.indent([ + '// "1" is the signal for "already loaded"', + "if(!installedChunks[chunkId]) {", + Template.indent([ + "importScripts(" + + "__webpack_require__.p + " + + mainTemplate.getAssetPath(JSON.stringify(chunkFilename), { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode( + hash, + length + )} + "`, + chunk: { + id: '" + chunkId + "', + hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`, + hashWithLength(length) { + const shortChunkHashMap = Object.create(null); + for (const chunkId of Object.keys(chunkMaps.hash)) { + if (typeof chunkMaps.hash[chunkId] === "string") { + shortChunkHashMap[chunkId] = chunkMaps.hash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap + )}[chunkId] + "`; + }, + contentHash: { + javascript: `" + ${JSON.stringify( + chunkMaps.contentHash.javascript + )}[chunkId] + "` + }, + contentHashWithLength: { + javascript: length => { + const shortContentHashMap = {}; + const contentHash = chunkMaps.contentHash.javascript; + for (const chunkId of Object.keys(contentHash)) { + if (typeof contentHash[chunkId] === "string") { + shortContentHashMap[chunkId] = contentHash[ + chunkId + ].substr(0, length); + } + } + return `" + ${JSON.stringify( + shortContentHashMap + )}[chunkId] + "`; + } + }, + name: `" + (${JSON.stringify( + chunkMaps.name + )}[chunkId]||chunkId) + "` + }, + contentHashType: "javascript" + }) + + ");" + ]), + "}" + ]), + "}));" + ]); + } + ); + mainTemplate.hooks.bootstrap.tap( + "WebWorkerMainTemplatePlugin", + (source, chunk, hash) => { + if (needChunkOnDemandLoadingCode(chunk)) { + const chunkCallbackName = + mainTemplate.outputOptions.chunkCallbackName; + const globalObject = mainTemplate.outputOptions.globalObject; + return Template.asString([ + source, + `${globalObject}[${JSON.stringify( + chunkCallbackName + )}] = function webpackChunkCallback(chunkIds, moreModules) {`, + Template.indent([ + "for(var moduleId in moreModules) {", + Template.indent( + mainTemplate.renderAddModule( + hash, + chunk, + "moduleId", + "moreModules[moduleId]" + ) + ), + "}", + "while(chunkIds.length)", + Template.indent("installedChunks[chunkIds.pop()] = 1;") + ]), + "};" + ]); + } + return source; + } + ); + mainTemplate.hooks.hotBootstrap.tap( + "WebWorkerMainTemplatePlugin", + (source, chunk, hash) => { + const hotUpdateChunkFilename = + mainTemplate.outputOptions.hotUpdateChunkFilename; + const hotUpdateMainFilename = + mainTemplate.outputOptions.hotUpdateMainFilename; + const hotUpdateFunction = mainTemplate.outputOptions.hotUpdateFunction; + const globalObject = mainTemplate.outputOptions.globalObject; + const currentHotUpdateChunkFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateChunkFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, + chunk: { + id: '" + chunkId + "' + } + } + ); + const currentHotUpdateMainFilename = mainTemplate.getAssetPath( + JSON.stringify(hotUpdateMainFilename), + { + hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, + hashWithLength: length => + `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "` + } + ); + + return ( + source + + "\n" + + `var parentHotUpdateCallback = ${globalObject}[${JSON.stringify( + hotUpdateFunction + )}];\n` + + `${globalObject}[${JSON.stringify(hotUpdateFunction)}] = ` + + Template.getFunctionContent( + require("./WebWorkerMainTemplate.runtime") + ) + .replace(/\/\/\$semicolon/g, ";") + .replace(/\$require\$/g, mainTemplate.requireFn) + .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename) + .replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename) + .replace(/\$hash\$/g, JSON.stringify(hash)) + ); + } + ); + mainTemplate.hooks.hash.tap("WebWorkerMainTemplatePlugin", hash => { + hash.update("webworker"); + hash.update("4"); + }); + } +} +module.exports = WebWorkerMainTemplatePlugin; diff --git a/node_modules/webpack/lib/webworker/WebWorkerTemplatePlugin.js b/node_modules/webpack/lib/webworker/WebWorkerTemplatePlugin.js new file mode 100644 index 0000000..5ad89f3 --- /dev/null +++ b/node_modules/webpack/lib/webworker/WebWorkerTemplatePlugin.js @@ -0,0 +1,25 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const WebWorkerMainTemplatePlugin = require("./WebWorkerMainTemplatePlugin"); +const WebWorkerChunkTemplatePlugin = require("./WebWorkerChunkTemplatePlugin"); +const WebWorkerHotUpdateChunkTemplatePlugin = require("./WebWorkerHotUpdateChunkTemplatePlugin"); + +class WebWorkerTemplatePlugin { + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "WebWorkerTemplatePlugin", + compilation => { + new WebWorkerMainTemplatePlugin().apply(compilation.mainTemplate); + new WebWorkerChunkTemplatePlugin().apply(compilation.chunkTemplate); + new WebWorkerHotUpdateChunkTemplatePlugin().apply( + compilation.hotUpdateChunkTemplate + ); + } + ); + } +} +module.exports = WebWorkerTemplatePlugin; |