diff --git a/cspell.json b/cspell.json index b52849246..7a869a224 100644 --- a/cspell.json +++ b/cspell.json @@ -310,7 +310,7 @@ "Wunder", "snitin", "Nitin", - "Kumarr", + "Kumar", "spacek", "thelarkinn" ], diff --git a/lib/Compilation.js b/lib/Compilation.js index 29bb2d65f..43defd8a3 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -107,12 +107,16 @@ const { isSourceEqual } = require("./util/source"); /** @typedef {import("./Module").BuildInfo} BuildInfo */ /** @typedef {import("./Module").ValueCacheVersions} ValueCacheVersions */ /** @typedef {import("./NormalModule").NormalModuleCompilationHooks} NormalModuleCompilationHooks */ +/** @typedef {import("./Module").FactoryMeta} FactoryMeta */ /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */ /** @typedef {import("./ModuleFactory")} ModuleFactory */ +/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */ /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */ /** @typedef {import("./ModuleGraphConnection")} ModuleGraphConnection */ /** @typedef {import("./ModuleFactory").ModuleFactoryCreateDataContextInfo} ModuleFactoryCreateDataContextInfo */ /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ +/** @typedef {import("./NormalModule").ParserOptions} ParserOptions */ +/** @typedef {import("./NormalModule").GeneratorOptions} GeneratorOptions */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeModule")} RuntimeModule */ /** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */ @@ -227,10 +231,17 @@ const { isSourceEqual } = require("./util/source"); * @property {LazySet} buildDependencies */ +/** @typedef {(id: string) => void} WebpackRequire */ + +/** + * @typedef {{ id: string | undefined, exports: any, loaded: boolean, error?: Error }} ModuleObject + */ + +/** + * @typedef {{ id: string | undefined, module: ModuleObject, require: WebpackRequire }} ExecuteOptions + */ + /** - * @typedef {{ id: string, exports: any, loaded: boolean }} ModuleObject - * - * /** * @typedef {object} ExecuteModuleArgument * @property {Module} module * @property {ModuleObject=} moduleObject @@ -364,7 +375,9 @@ const { isSourceEqual } = require("./util/source"); /** @typedef {Record & KnownCreateStatsOptionsContext} CreateStatsOptionsContext */ -/** @typedef {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} CodeGenerationJobs */ +/** @typedef {{ module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}} CodeGenerationJob */ + +/** @typedef {CodeGenerationJob[]} CodeGenerationJobs */ /** @typedef {{javascript: ModuleTemplate}} ModuleTemplates */ @@ -438,7 +451,17 @@ const compareErrors = concatComparators(byModule, byLocation, byMessage); /** @type {WeakMap} */ const unsafeCacheDependencies = new WeakMap(); -/** @type {WeakMap} */ +/** + * @typedef {object} KnownUnsafeCacheData + * @property {FactoryMeta} [factoryMeta] factory meta + * @property {ResolveOptions} [resolveOptions] resolve options + * @property {ParserOptions} [parserOptions] + * @property {GeneratorOptions} [generatorOptions] + */ + +/** @typedef {KnownUnsafeCacheData & Record} UnsafeCacheData */ + +/** @type {WeakMap} */ const unsafeCacheData = new WeakMap(); class Compilation { @@ -482,12 +505,18 @@ class Compilation { const { fn, additionalAssets, ...remainingTap } = tap; const additionalAssetsFn = additionalAssets === true ? fn : additionalAssets; + /** @typedef {WeakSet} ProcessedAssets */ + + /** @type {ProcessedAssets | undefined} */ const processedAssets = additionalAssetsFn ? new WeakSet() : undefined; switch (type) { case "sync": if (additionalAssetsFn) { this.hooks.processAdditionalAssets.tap(name, assets => { - if (processedAssets.has(this.assets)) + if ( + /** @type {ProcessedAssets} */ + (processedAssets).has(this.assets) + ) additionalAssetsFn(assets); }); } @@ -518,7 +547,10 @@ class Compilation { this.hooks.processAdditionalAssets.tapAsync( name, (assets, callback) => { - if (processedAssets.has(this.assets)) + if ( + /** @type {ProcessedAssets} */ + (processedAssets).has(this.assets) + ) return additionalAssetsFn(assets, callback); callback(); } @@ -546,7 +578,10 @@ class Compilation { case "promise": if (additionalAssetsFn) { this.hooks.processAdditionalAssets.tapPromise(name, assets => { - if (processedAssets.has(this.assets)) + if ( + /** @type {ProcessedAssets} */ + (processedAssets).has(this.assets) + ) return additionalAssetsFn(assets); return Promise.resolve(); }); @@ -2096,7 +2131,9 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si resolveOptions: originModule ? originModule.resolveOptions : undefined, context: context || - (originModule ? originModule.context : this.compiler.context), + (originModule + ? /** @type {string} */ (originModule.context) + : /** @type {string} */ (this.compiler.context)), dependencies }, (err, result) => { @@ -2271,7 +2308,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si ); } else { entryData[target].push(entry); - for (const key of Object.keys(options)) { + for (const _key of Object.keys(options)) { + const key = /** @type {keyof EntryOptions} */ (_key); if (options[key] === undefined) continue; if (entryData.options[key] === options[key]) continue; if ( @@ -2282,7 +2320,9 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si continue; } if (entryData.options[key] === undefined) { - entryData.options[key] = options[key]; + entryData.options[/** @type {TODO} */ (key)] = /** @type {TODO} */ ( + options[key] + ); } else { return callback( new WebpackError( @@ -2308,7 +2348,12 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si this.hooks.failedEntry.call(entry, options, err); return callback(err); } - this.hooks.succeedEntry.call(entry, options, module); + this.hooks.succeedEntry.call( + entry, + options, + /** @type {Module} */ + (module) + ); return callback(null, module); } ); @@ -3225,18 +3270,20 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o } this.hooks.afterProcessAssets.call(this.assets); this.logger.timeEnd("process assets"); - this.assets = /** @type {CompilationAssets} */ ( - this._backCompat - ? soonFrozenObjectDeprecation( - this.assets, - "Compilation.assets", - "DEP_WEBPACK_COMPILATION_ASSETS", - `BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation. + this.assets = + /** @type {CompilationAssets} */ + ( + this._backCompat + ? soonFrozenObjectDeprecation( + this.assets, + "Compilation.assets", + "DEP_WEBPACK_COMPILATION_ASSETS", + `BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation. Do changes to assets earlier, e. g. in Compilation.hooks.processAssets. Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.` - ) - : Object.freeze(this.assets) - ); + ) + : Object.freeze(this.assets) + ); this.summarizeDependencies(); if (shouldRecord) { @@ -3766,7 +3813,8 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o module, /** @type {DependencyLocation} */ (loc), - request + /** @type {string} */ + (request) ); } return chunkGroup; @@ -3778,7 +3826,8 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o module, /** @type {DependencyLocation} */ (loc), - request + /** @type {string} */ + (request) ); const chunk = this.addChunk(name); @@ -4322,9 +4371,9 @@ This prevents using hashes of each other and should be avoided.`); this.logger.timeEnd("hashing: sort chunks"); const fullHashChunks = new Set(); - /** @type {{module: Module, hash: string, runtime: RuntimeSpec, runtimes: RuntimeSpec[]}[]} */ + /** @type {CodeGenerationJobs} */ const codeGenerationJobs = []; - /** @type {Map>} */ + /** @type {Map>} */ const codeGenerationJobsMap = new Map(); /** @type {WebpackError[]} */ const errors = []; @@ -4441,7 +4490,11 @@ This prevents using hashes of each other and should be avoided.`); moduleHashDigest, moduleHashDigest.slice(0, hashDigestLength) ); - codeGenerationJobsMap.get(oldHash).get(module).hash = moduleHashDigest; + /** @type {CodeGenerationJob} */ + ( + /** @type {Map} */ + (codeGenerationJobsMap.get(oldHash)).get(module) + ).hash = moduleHashDigest; } const chunkHash = createHash(/** @type {Algorithm} */ (hashFunction)); chunkHash.update(chunk.hash); @@ -4491,7 +4544,7 @@ This prevents using hashes of each other and should be avoided.`); /** * @private * @param {string} file file name - * @param {AssetInfo} newInfo new asset information + * @param {AssetInfo=} newInfo new asset information * @param {AssetInfo=} oldInfo old asset information */ _setAssetInfo(file, newInfo, oldInfo = this.assetsInfo.get(file)) { @@ -4801,7 +4854,7 @@ This prevents using hashes of each other and should be avoided.`); manifest, (fileManifest, callback) => { const ident = fileManifest.identifier; - const usedHash = fileManifest.hash; + const usedHash = /** @type {string} */ (fileManifest.hash); const assetCacheItem = this._assetsCache.getItemCache( ident, @@ -5253,21 +5306,27 @@ This prevents using hashes of each other and should be avoided.`); strictModuleErrorHandling, strictModuleExceptionHandling } = this.outputOptions; + + /** @type {WebpackRequire} */ const __webpack_require__ = id => { const cached = moduleCache[id]; if (cached !== undefined) { if (cached.error) throw cached.error; return cached.exports; } - const moduleArgument = moduleArgumentsById.get(id); + const moduleArgument = + /** @type {TODO} */ + (moduleArgumentsById).get(id); return __webpack_require_module__(moduleArgument, id); }; + /** @type {((options: ExecuteOptions) => void)[]} */ const interceptModuleExecution = (__webpack_require__[ RuntimeGlobals.interceptModuleExecution.replace( `${RuntimeGlobals.require}.`, "" ) ] = []); + /** @type {Record} */ const moduleCache = (__webpack_require__[ RuntimeGlobals.moduleCache.replace( `${RuntimeGlobals.require}.`, @@ -5283,6 +5342,7 @@ This prevents using hashes of each other and should be avoided.`); * @returns {any} exports */ const __webpack_require_module__ = (moduleArgument, id) => { + /** @type {ExecuteOptions} */ const execOptions = { id, module: { @@ -5317,9 +5377,14 @@ This prevents using hashes of each other and should be avoided.`); if (strictModuleExceptionHandling) { if (id) delete moduleCache[id]; } else if (strictModuleErrorHandling) { - moduleObject.error = execErr; + moduleObject.error = /** @type {WebpackError} */ ( + execErr + ); + } + if (!(/** @type {WebpackError} */ (execErr).module)) { + /** @type {WebpackError} */ + (execErr).module = module; } - if (!execErr.module) execErr.module = module; throw execErr; } }; @@ -5334,13 +5399,16 @@ This prevents using hashes of each other and should be avoided.`); } exports = __webpack_require__(module.identifier()); } catch (execErr) { + const { message, stack, module } = /** @type {TODO} */ ( + execErr + ); const err = new WebpackError( `Execution of module code from module graph (${module.readableIdentifier( this.requestShortener - )}) failed: ${execErr.message}` + )}) failed: ${message}` ); - err.stack = execErr.stack; - err.module = execErr.module; + err.stack = stack; + err.module = module; return callback(err); } diff --git a/lib/ContextReplacementPlugin.js b/lib/ContextReplacementPlugin.js index ac425f313..a69296bd0 100644 --- a/lib/ContextReplacementPlugin.js +++ b/lib/ContextReplacementPlugin.js @@ -9,13 +9,16 @@ const ContextElementDependency = require("./dependencies/ContextElementDependenc const { join } = require("./util/fs"); /** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./ContextModule").ContextModuleOptions} ContextModuleOptions */ /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */ +/** @typedef {Record} NewContentCreateContextMap */ + class ContextReplacementPlugin { /** * @param {RegExp} resourceRegExp A regular expression that determines which files will be selected - * @param {TODO=} newContentResource A new resource to replace the match - * @param {TODO=} newContentRecursive If true, all subdirectories are searched for matches + * @param {(string | ((context: TODO) => void) | RegExp | boolean)=} newContentResource A new resource to replace the match + * @param {(boolean | NewContentCreateContextMap | RegExp)=} newContentRecursive If true, all subdirectories are searched for matches * @param {RegExp=} newContentRegExp A regular expression that determines which files will be selected */ constructor( @@ -26,35 +29,56 @@ class ContextReplacementPlugin { ) { this.resourceRegExp = resourceRegExp; + // new webpack.ContextReplacementPlugin(/selector/, (context) => { /* Logic */ }); if (typeof newContentResource === "function") { this.newContentCallback = newContentResource; - } else if ( + } + // new ContextReplacementPlugin(/selector/, './folder', { './request': './request' }); + else if ( typeof newContentResource === "string" && typeof newContentRecursive === "object" ) { this.newContentResource = newContentResource; + /** + * @param {InputFileSystem} fs input file system + * @param {(err: null | Error, newContentRecursive: NewContentCreateContextMap) => void} callback callback + */ this.newContentCreateContextMap = (fs, callback) => { - callback(null, newContentRecursive); + callback( + null, + /** @type {NewContentCreateContextMap} */ (newContentRecursive) + ); }; - } else if ( + } + // new ContextReplacementPlugin(/selector/, './folder', (context) => { /* Logic */ }); + else if ( typeof newContentResource === "string" && typeof newContentRecursive === "function" ) { this.newContentResource = newContentResource; this.newContentCreateContextMap = newContentRecursive; } else { + // new webpack.ContextReplacementPlugin(/selector/, false, /reg-exp/); if (typeof newContentResource !== "string") { - newContentRegExp = newContentRecursive; - newContentRecursive = newContentResource; + newContentRegExp = /** @type {RegExp} */ (newContentRecursive); + newContentRecursive = /** @type {boolean} */ (newContentResource); newContentResource = undefined; } + // new webpack.ContextReplacementPlugin(/selector/, /de|fr|hu/); if (typeof newContentRecursive !== "boolean") { - newContentRegExp = newContentRecursive; + newContentRegExp = /** @type {RegExp} */ (newContentRecursive); newContentRecursive = undefined; } - this.newContentResource = newContentResource; - this.newContentRecursive = newContentRecursive; - this.newContentRegExp = newContentRegExp; + // new webpack.ContextReplacementPlugin(/selector/, './folder', false, /selector/); + this.newContentResource = + /** @type {string | undefined} */ + (newContentResource); + this.newContentRecursive = + /** @type {boolean | undefined} */ + (newContentRecursive); + this.newContentRegExp = + /** @type {RegExp | undefined} */ + (newContentRegExp); } } @@ -150,8 +174,12 @@ class ContextReplacementPlugin { } } -const createResolveDependenciesFromContextMap = createContextMap => { - const resolveDependenciesFromContextMap = (fs, options, callback) => { +/** + * @param {(fs: InputFileSystem, callback: (err: null | Error, map: NewContentCreateContextMap) => void) => void} createContextMap create context map function + * @returns {(fs: InputFileSystem, options: ContextModuleOptions, callback: (err: null | Error, dependencies?: ContextElementDependency[]) => void) => void} resolve resolve dependencies from context map function + */ +const createResolveDependenciesFromContextMap = + createContextMap => (fs, options, callback) => { createContextMap(fs, (err, map) => { if (err) return callback(err); const dependencies = Object.keys(map).map( @@ -159,14 +187,13 @@ const createResolveDependenciesFromContextMap = createContextMap => { new ContextElementDependency( map[key] + options.resourceQuery + options.resourceFragment, key, - options.category, + options.typePrefix, + /** @type {string} */ (options.category), options.referencedExports ) ); callback(null, dependencies); }); }; - return resolveDependenciesFromContextMap; -}; module.exports = ContextReplacementPlugin; diff --git a/lib/ExportsInfo.js b/lib/ExportsInfo.js index f55dcf2d9..fedbb2742 100644 --- a/lib/ExportsInfo.js +++ b/lib/ExportsInfo.js @@ -34,6 +34,12 @@ const RETURNS_TRUE = () => true; const CIRCULAR = Symbol("circular target"); class RestoreProvidedData { + /** + * @param {TODO[]} exports exports + * @param {ExportInfo["provided"]} otherProvided other provided + * @param {ExportInfo["canMangleProvide"]} otherCanMangleProvide other can mangle provide + * @param {ExportInfo["terminalBinding"]} otherTerminalBinding other terminal binding + */ constructor( exports, otherProvided, @@ -78,7 +84,7 @@ class ExportsInfo { constructor() { /** @type {Exports} */ this._exports = new Map(); - this._otherExportsInfo = new ExportInfo(null); + this._otherExportsInfo = new ExportInfo(/** @type {TODO} */ (null)); this._sideEffectsOnlyInfo = new ExportInfo("*side effects only*"); this._exportsAreOrdered = false; /** @type {ExportsInfo=} */ @@ -809,9 +815,13 @@ class ExportsInfo { } } +/** @typedef {Map} UsedInRuntime */ + /** @typedef {{ module: Module, export: string[] }} TargetItemWithoutConnection */ + /** @typedef {{ module: Module, connection: ModuleGraphConnection, export: string[] | undefined }} TargetItem */ -/** @typedef {Map} Target */ + +/** @typedef {Map} Target */ class ExportInfo { /** @@ -833,7 +843,7 @@ class ExportInfo { this._globalUsed = initFrom ? initFrom._globalUsed : undefined; /** * @private - * @type {Map} + * @type {UsedInRuntime | undefined} */ this._usedInRuntime = initFrom && initFrom._usedInRuntime @@ -1015,7 +1025,8 @@ class ExportInfo { if (newValue !== UsageState.Unused && condition(UsageState.Unused)) { this._usedInRuntime = new Map(); forEachRuntime(runtime, runtime => - this._usedInRuntime.set(/** @type {string} */ (runtime), newValue) + /** @type {UsedInRuntime} */ + (this._usedInRuntime).set(/** @type {string} */ (runtime), newValue) ); return true; } @@ -1023,15 +1034,18 @@ class ExportInfo { let changed = false; forEachRuntime(runtime, _runtime => { const runtime = /** @type {string} */ (_runtime); + const usedInRuntime = + /** @type {UsedInRuntime} */ + (this._usedInRuntime); let oldValue = /** @type {UsageStateType} */ - (this._usedInRuntime.get(runtime)); + (usedInRuntime.get(runtime)); if (oldValue === undefined) oldValue = UsageState.Unused; if (newValue !== oldValue && condition(oldValue)) { if (newValue === UsageState.Unused) { - this._usedInRuntime.delete(runtime); + usedInRuntime.delete(runtime); } else { - this._usedInRuntime.set(runtime, newValue); + usedInRuntime.set(runtime, newValue); } changed = true; } @@ -1059,7 +1073,8 @@ class ExportInfo { if (newValue !== UsageState.Unused) { this._usedInRuntime = new Map(); forEachRuntime(runtime, runtime => - this._usedInRuntime.set(/** @type {string} */ (runtime), newValue) + /** @type {UsedInRuntime} */ + (this._usedInRuntime).set(/** @type {string} */ (runtime), newValue) ); return true; } @@ -1067,15 +1082,18 @@ class ExportInfo { let changed = false; forEachRuntime(runtime, _runtime => { const runtime = /** @type {string} */ (_runtime); + const usedInRuntime = + /** @type {UsedInRuntime} */ + (this._usedInRuntime); let oldValue = /** @type {UsageStateType} */ - (this._usedInRuntime.get(runtime)); + (usedInRuntime.get(runtime)); if (oldValue === undefined) oldValue = UsageState.Unused; if (newValue !== oldValue) { if (newValue === UsageState.Unused) { - this._usedInRuntime.delete(runtime); + usedInRuntime.delete(runtime); } else { - this._usedInRuntime.set(runtime, newValue); + usedInRuntime.set(runtime, newValue); } changed = true; } @@ -1203,7 +1221,8 @@ class ExportInfo { } else if ( runtime !== undefined && Array.from(runtime).every( - runtime => !this._usedInRuntime.has(runtime) + runtime => + !(/** @type {UsedInRuntime} */ (this._usedInRuntime).has(runtime)) ) ) { return false; @@ -1262,6 +1281,7 @@ class ExportInfo { if (maxPriority === minPriority) return (this._maxTarget = this._target); // This is an edge case + /** @type {Target} */ const map = new Map(); for (const [key, value] of /** @type {Target} */ (this._target)) { if (maxPriority === value.priority) { @@ -1441,9 +1461,10 @@ class ExportInfo { const target = this._getTarget(moduleGraph, resolveTargetFilter, undefined); if (target === CIRCULAR) return; if (!target) return; - const originalTarget = + const originalTarget = /** @type {TargetItem} */ ( /** @type {Target} */ - (this._getMaxTarget()).values().next().value; + (this._getMaxTarget()).values().next().value + ); if ( originalTarget.connection === target.connection && originalTarget.export === target.export diff --git a/lib/ExternalModule.js b/lib/ExternalModule.js index c3fa3357a..ec9881e5d 100644 --- a/lib/ExternalModule.js +++ b/lib/ExternalModule.js @@ -31,6 +31,7 @@ const { register } = require("./util/serialization"); /** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./ChunkGraph")} ChunkGraph */ /** @typedef {import("./Compilation")} Compilation */ +/** @typedef {import("./Compilation").UnsafeCacheData} UnsafeCacheData */ /** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ /** @typedef {import("./ExportsInfo")} ExportsInfo */ @@ -647,7 +648,7 @@ class ExternalModule extends Module { /** * restore unsafe cache data - * @param {object} unsafeCacheData data from getUnsafeCacheData + * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching */ restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) { diff --git a/lib/Module.js b/lib/Module.js index b3d2abbfb..95e542f54 100644 --- a/lib/Module.js +++ b/lib/Module.js @@ -24,6 +24,7 @@ const makeSerializable = require("./util/makeSerializable"); /** @typedef {import("./CodeGenerationResults")} CodeGenerationResults */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./Compilation").AssetInfo} AssetInfo */ +/** @typedef {import("./Compilation").UnsafeCacheData} UnsafeCacheData */ /** @typedef {import("./ConcatenationScope")} ConcatenationScope */ /** @typedef {import("./Dependency")} Dependency */ /** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */ @@ -141,8 +142,6 @@ const makeSerializable = require("./util/makeSerializable"); * @property {boolean=} sideEffectFree */ -/** @typedef {{ factoryMeta: FactoryMeta | undefined, resolveOptions: ResolveOptions | undefined }} UnsafeCacheData */ - const EMPTY_RESOLVE_OPTIONS = {}; let debugId = 1000; @@ -1030,7 +1029,7 @@ class Module extends DependenciesBlock { /** * restore unsafe cache data - * @param {object} unsafeCacheData data from getUnsafeCacheData + * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching */ _restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) { diff --git a/lib/NormalModule.js b/lib/NormalModule.js index f0cd39397..e8ac0e9c6 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -97,8 +97,6 @@ const memoize = require("./util/memoize"); /** @typedef {{[k: string]: any}} ParserOptions */ /** @typedef {{[k: string]: any}} GeneratorOptions */ -/** @typedef {UnsafeCacheData & { parser: undefined | Parser, parserOptions: undefined | ParserOptions, generator: undefined | Generator, generatorOptions: undefined | GeneratorOptions }} NormalModuleUnsafeCacheData */ - /** * @template T * @typedef {import("../declarations/LoaderContext").LoaderContext} LoaderContext @@ -499,9 +497,7 @@ class NormalModule extends Module { * @returns {UnsafeCacheData} cached data */ getUnsafeCacheData() { - const data = - /** @type {NormalModuleUnsafeCacheData} */ - (super.getUnsafeCacheData()); + const data = super.getUnsafeCacheData(); data.parserOptions = this.parserOptions; data.generatorOptions = this.generatorOptions; return data; @@ -509,7 +505,7 @@ class NormalModule extends Module { /** * restore unsafe cache data - * @param {NormalModuleUnsafeCacheData} unsafeCacheData data from getUnsafeCacheData + * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching */ restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) { @@ -518,7 +514,7 @@ class NormalModule extends Module { /** * restore unsafe cache data - * @param {object} unsafeCacheData data from getUnsafeCacheData + * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching */ _restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) { diff --git a/lib/NormalModuleFactory.js b/lib/NormalModuleFactory.js index 22d82ead4..51f1a6921 100644 --- a/lib/NormalModuleFactory.js +++ b/lib/NormalModuleFactory.js @@ -186,20 +186,13 @@ const mergeGlobalOptions = (globalOptions, type, localOptions) => { // TODO webpack 6 remove /** + * @template {import("tapable").Hook} T * @param {string} name name - * @param {TODO} hook hook + * @param {T} hook hook * @returns {string} result */ const deprecationChangedHookMessage = (name, hook) => { - const names = hook.taps - .map( - /** - * @param {TODO} tapped tapped - * @returns {string} name - */ - tapped => tapped.name - ) - .join(", "); + const names = hook.taps.map(tapped => tapped.name).join(", "); return ( `NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` + @@ -281,9 +274,9 @@ class NormalModuleFactory extends ModuleFactory { beforeResolve: new AsyncSeriesBailHook(["resolveData"]), /** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */ afterResolve: new AsyncSeriesBailHook(["resolveData"]), - /** @type {AsyncSeriesBailHook<[ResolveData["createData"], ResolveData], Module | void>} */ + /** @type {AsyncSeriesBailHook<[CreateData, ResolveData], Module | void>} */ createModule: new AsyncSeriesBailHook(["createData", "resolveData"]), - /** @type {SyncWaterfallHook<[Module, ResolveData["createData"], ResolveData]>} */ + /** @type {SyncWaterfallHook<[Module, CreateData, ResolveData]>} */ module: new SyncWaterfallHook(["module", "createData", "resolveData"]), /** @type {HookMap>} */ createParser: new HookMap(() => new SyncBailHook(["parserOptions"])), @@ -459,6 +452,7 @@ class NormalModuleFactory extends ModuleFactory { matchResource = join(this.fs, context, matchResource); } } + matchResourceData = { resource: matchResource, ...cacheParseResource(matchResource) @@ -546,7 +540,11 @@ class NormalModuleFactory extends ModuleFactory { if (!resourceData) { // ignored - return callback(null, dependencies[0].createIgnoredModule(context)); + return callback( + null, + /** @type {TODO} */ + (dependencies[0].createIgnoredModule(context)) + ); } const userRequest = @@ -624,12 +622,11 @@ class NormalModuleFactory extends ModuleFactory { ] === "object" && settings[/** @type {keyof ModuleSettings} */ (r.type)] !== null ) { - settings[r.type] = cachedCleverMerge( - settings[/** @type {keyof ModuleSettings} */ (r.type)], - r.value - ); + const type = /** @type {TODO} */ (r.type); + settings[type] = cachedCleverMerge(settings[type], r.value); } else { - settings[r.type] = r.value; + const type = /** @type {TODO} */ (r.type); + settings[type] = r.value; } } } diff --git a/lib/cache/PackFileCacheStrategy.js b/lib/cache/PackFileCacheStrategy.js index e7fee666f..b5fd33231 100644 --- a/lib/cache/PackFileCacheStrategy.js +++ b/lib/cache/PackFileCacheStrategy.js @@ -598,7 +598,10 @@ class Pack { const content = this.content[i]; if (content !== undefined) { write(content.items); - content.writeLazy(lazy => writeSeparate(lazy, { name: `${i}` })); + content.writeLazy(lazy => + /** @type {NonNullable} */ + (writeSeparate)(lazy, { name: `${i}` }) + ); } else { write(undefined); // undefined marks an empty content slot } @@ -671,7 +674,7 @@ class PackContentItems { } /** - * @param {ObjectSerializerContext & { snapshot: TODO, rollback: TODO, logger: Logger, profile: boolean | undefined }} context context + * @param {ObjectSerializerContext & { logger: Logger, profile: boolean | undefined }} context context */ serialize({ write, snapshot, rollback, logger, profile }) { if (profile) { @@ -792,7 +795,7 @@ makeSerializable( "PackContentItems" ); -/** @typedef {(function(): Promise | PackContentItems)} LazyFn */ +/** @typedef {(function(): Promise | PackContentItems)} LazyFunction */ class PackContent { /* @@ -823,7 +826,7 @@ class PackContent { */ constructor(items, usedItems, dataOrFn, logger, lazyName) { this.items = items; - /** @type {LazyFn | undefined} */ + /** @type {TODO | undefined} */ this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined; /** @type {Content | undefined} */ this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map; @@ -861,7 +864,7 @@ class PackContent { ); logger.time(timeMessage); } - const value = /** @type {LazyFn} */ (this.lazy)(); + const value = /** @type {LazyFunction} */ (this.lazy)(); if ("then" in value) { return value.then(data => { const map = data.map; @@ -871,7 +874,7 @@ class PackContent { // Move to state C this.content = map; this.lazy = SerializerMiddleware.unMemoizeLazy( - /** @type {LazyFn} */ + /** @type {LazyFunction} */ (this.lazy) ); return map.get(identifier); @@ -885,7 +888,7 @@ class PackContent { // Move to state C this.content = map; this.lazy = SerializerMiddleware.unMemoizeLazy( - /** @type {LazyFn} */ + /** @type {LazyFunction} */ (this.lazy) ); return map.get(identifier); @@ -917,7 +920,9 @@ class PackContent { ); logger.time(timeMessage); } - const value = this.lazy(); + const value = + /** @type {PackContentItems | Promise} */ + (this.lazy()); if ("then" in value) { return value.then(data => { if (timeMessage) { @@ -1008,7 +1013,7 @@ class PackContent { ); logger.time(timeMessage); } - const value = /** @type {LazyFn} */ (this.lazy)(); + const value = /** @type {LazyFunction} */ (this.lazy)(); this.outdated = false; if ("then" in value) { // Move to state B1 @@ -1026,7 +1031,7 @@ class PackContent { // Move to state C1 (or maybe C2) this.content = map; this.lazy = SerializerMiddleware.unMemoizeLazy( - /** @type {LazyFn} */ + /** @type {LazyFunction} */ (this.lazy) ); diff --git a/lib/cache/ResolverCachePlugin.js b/lib/cache/ResolverCachePlugin.js index adb320b2c..84618ebc4 100644 --- a/lib/cache/ResolverCachePlugin.js +++ b/lib/cache/ResolverCachePlugin.js @@ -26,6 +26,11 @@ const makeSerializable = require("../util/makeSerializable"); * @typedef {import("tapable").SyncHook} SyncHook */ +/** + * @template H + * @typedef {import("tapable").HookMapInterceptor} HookMapInterceptor + */ + class CacheEntry { /** * @param {ResolveRequest} result result @@ -125,7 +130,7 @@ class ResolverCachePlugin { }); }); - /** @typedef {function((Error | null)=, ResolveRequest=): void} Callback */ + /** @typedef {function((Error | null)=, (ResolveRequest | null)=): void} Callback */ /** @typedef {ResolveRequest & { _ResolverCachePluginCacheMiss: true }} ResolveRequestWithCacheMiss */ /** @@ -244,13 +249,15 @@ class ResolverCachePlugin { ); }; compiler.resolverFactory.hooks.resolver.intercept({ - factory(type, hook) { + factory(type, _hook) { /** @type {Map} */ const activeRequests = new Map(); /** @type {Map][]>} */ const activeRequestsWithYield = new Map(); - /** @type {SyncHook<[Resolver, ResolveOptions, ResolveOptionsWithDependencyType]>} */ - (hook).tap("ResolverCachePlugin", (resolver, options, userOptions) => { + const hook = + /** @type {SyncHook<[Resolver, ResolveOptions, ResolveOptionsWithDependencyType]>} */ + (_hook); + hook.tap("ResolverCachePlugin", (resolver, options, userOptions) => { if (/** @type {TODO} */ (options).cache !== true) return; const optionsIdent = objectToString(userOptions, false); const cacheWithContext = @@ -299,7 +306,7 @@ class ResolverCachePlugin { let yields; /** - * @type {function((Error | null)=, ResolveRequest | ResolveRequest[]=): void} + * @type {function((Error | null)=, (ResolveRequest | ResolveRequest[] | null)=): void} */ const done = withYield ? (err, result) => { diff --git a/lib/config/defaults.js b/lib/config/defaults.js index e0d2c03eb..ef305edf3 100644 --- a/lib/config/defaults.js +++ b/lib/config/defaults.js @@ -1656,7 +1656,8 @@ const getResolveDefaults = ({ styleConditions.push(mode === "development" ? "development" : "production"); styleConditions.push("style"); - resolveOptions.byDependency["css-import"] = { + /** @type {NonNullable} */ + (resolveOptions.byDependency)["css-import"] = { // We avoid using any main files because we have to be consistent with CSS `@import` // and CSS `@import` does not handle `main` files in directories, // you should always specify the full URL for styles diff --git a/lib/config/target.js b/lib/config/target.js index 2a7ed046c..de8e06295 100644 --- a/lib/config/target.js +++ b/lib/config/target.js @@ -22,12 +22,12 @@ const getDefaultTarget = context => { /** * @typedef {object} PlatformTargetProperties - * @property {boolean | null} web web platform, importing of http(s) and std: is available - * @property {boolean | null} browser browser platform, running in a normal web browser - * @property {boolean | null} webworker (Web)Worker platform, running in a web/shared/service worker - * @property {boolean | null} node node platform, require of node built-in modules is available - * @property {boolean | null} nwjs nwjs platform, require of legacy nw.gui is available - * @property {boolean | null} electron electron platform, require of some electron built-in modules is available + * @property {boolean | null} [web] web platform, importing of http(s) and std: is available + * @property {boolean | null} [browser] browser platform, running in a normal web browser + * @property {boolean | null} [webworker] (Web)Worker platform, running in a web/shared/service worker + * @property {boolean | null} [node] node platform, require of node built-in modules is available + * @property {boolean | null} [nwjs] nwjs platform, require of legacy nw.gui is available + * @property {boolean | null} [electron] electron platform, require of some electron built-in modules is available */ /** diff --git a/lib/debug/ProfilingPlugin.js b/lib/debug/ProfilingPlugin.js index f1493f3f0..669ee8332 100644 --- a/lib/debug/ProfilingPlugin.js +++ b/lib/debug/ProfilingPlugin.js @@ -16,6 +16,7 @@ const { const createSchemaValidation = require("../util/create-schema-validation"); const { dirname, mkdirpSync } = require("../util/fs"); +/** @typedef {import("tapable").FullTap} FullTap */ /** @typedef {import("../../declarations/plugins/debug/ProfilingPlugin").ProfilingPluginOptions} ProfilingPluginOptions */ /** @typedef {import("../Compilation")} Compilation */ /** @typedef {import("../Compiler")} Compiler */ @@ -89,7 +90,7 @@ class Profiler { /** * @param {string} method method name - * @param {object} [params] params + * @param {Record} [params] params * @returns {Promise} Promise for the result */ sendCommand(method, params) { @@ -408,29 +409,33 @@ const interceptAllJavascriptModulesPluginHooks = (compilation, tracer) => { ); }; +/** @typedef {(...args: EXPECTED_ANY[]) => EXPECTED_ANY | Promise<(...args: EXPECTED_ANY[]) => EXPECTED_ANY>} PluginFunction */ + /** * @param {string} instance instance * @param {Trace} tracer tracer - * @returns {TODO} interceptor + * @returns {(hookName: string) => TODO} interceptor */ const makeInterceptorFor = (instance, tracer) => hookName => ({ + /** + * @param {FullTap} tapInfo tap info + * @returns {FullTap} modified full tap + */ register: tapInfo => { - const { name, type, fn } = tapInfo; + const { name, type, fn: internalFn } = tapInfo; const newFn = // Don't tap our own hooks to ensure stream can close cleanly name === PLUGIN_NAME - ? fn + ? internalFn : makeNewProfiledTapFn(hookName, tracer, { name, type, - fn + fn: /** @type {PluginFunction} */ (internalFn) }); return { ...tapInfo, fn: newFn }; } }); -/** @typedef {(...args: TODO[]) => void | Promise} PluginFunction */ - /** * @param {string} hookName Name of the hook to profile. * @param {Trace} tracer The trace object. @@ -452,7 +457,9 @@ const makeNewProfiledTapFn = (hookName, tracer, { name, type, fn }) => { id, cat: defaultCategory }); - const promise = /** @type {Promise<*>} */ (fn(...args)); + const promise = + /** @type {Promise<(...args: EXPECTED_ANY[]) => EXPECTED_ANY>} */ + (fn(...args)); return promise.then(r => { tracer.trace.end({ name, @@ -471,14 +478,20 @@ const makeNewProfiledTapFn = (hookName, tracer, { name, type, fn }) => { cat: defaultCategory }); const callback = args.pop(); - fn(...args, (...r) => { - tracer.trace.end({ - name, - id, - cat: defaultCategory - }); - callback(...r); - }); + fn( + ...args, + /** + * @param {...EXPECTED_ANY[]} r result + */ + (...r) => { + tracer.trace.end({ + name, + id, + cat: defaultCategory + }); + callback(...r); + } + ); }; case "sync": return (...args) => { @@ -513,7 +526,7 @@ const makeNewProfiledTapFn = (hookName, tracer, { name, type, fn }) => { return r; }; default: - break; + return fn; } }; diff --git a/lib/dependencies/AMDDefineDependencyParserPlugin.js b/lib/dependencies/AMDDefineDependencyParserPlugin.js index 14fbe4af2..678f042d0 100644 --- a/lib/dependencies/AMDDefineDependencyParserPlugin.js +++ b/lib/dependencies/AMDDefineDependencyParserPlugin.js @@ -385,7 +385,7 @@ class AMDDefineDependencyParserPlugin { let inTry; if (fn && isUnboundFunctionExpression(fn)) { inTry = parser.scope.inTry; - parser.inScope(fnParams, () => { + parser.inScope(/** @type {Identifier[]} */ (fnParams), () => { for (const [name, varInfo] of fnRenames) { parser.setVariable(name, varInfo); } diff --git a/lib/library/ModernModuleLibraryPlugin.js b/lib/library/ModernModuleLibraryPlugin.js index 23a9510c2..25a52a1ea 100644 --- a/lib/library/ModernModuleLibraryPlugin.js +++ b/lib/library/ModernModuleLibraryPlugin.js @@ -122,6 +122,7 @@ class ModernModuleLibraryPlugin extends AbstractLibraryPlugin { chunk.runtime ); const finalName = + definitions && definitions[ /** @type {string} */ (webpackExportsProperty) diff --git a/lib/serialization/BinaryMiddleware.js b/lib/serialization/BinaryMiddleware.js index f094347f5..0d4bd3088 100644 --- a/lib/serialization/BinaryMiddleware.js +++ b/lib/serialization/BinaryMiddleware.js @@ -8,10 +8,14 @@ const memoize = require("../util/memoize"); const SerializerMiddleware = require("./SerializerMiddleware"); /** @typedef {import("./SerializerMiddleware").Context} Context */ -/** @typedef {import("./SerializerMiddleware").LazyFn} LazyFn */ /** @typedef {import("./types").BufferSerializableType} BufferSerializableType */ /** @typedef {import("./types").PrimitiveSerializableType} PrimitiveSerializableType */ +/** + * @template LAZY_RESULT + * @typedef {import("./SerializerMiddleware").LazyFunction} LazyFunction + */ + /* Format: @@ -146,16 +150,16 @@ class BinaryMiddleware extends SerializerMiddleware { /** * @param {DeserializedType} data data * @param {Context} context context object - * @returns {SerializedType | Promise} serialized data + * @returns {SerializedType | Promise | null} serialized data */ serialize(data, context) { return this._serialize(data, context); } /** - * @param {function(): Promise | any} fn lazy function + * @param {LazyFunction} fn lazy function * @param {Context} context serialize function - * @returns {function(): Promise | any} new lazy + * @returns {LazyFunction} new lazy */ _serializeLazy(fn, context) { return SerializerMiddleware.serializeLazy(fn, data => @@ -277,7 +281,7 @@ class BinaryMiddleware extends SerializerMiddleware { case "function": { if (!SerializerMiddleware.isLazy(thing)) throw new Error(`Unexpected function ${thing}`); - /** @type {SerializedType | (() => SerializedType)} */ + /** @type {SerializedType | LazyFunction} */ let serializedData = SerializerMiddleware.getLazySerializedValue(thing); if (serializedData === undefined) { @@ -285,16 +289,23 @@ class BinaryMiddleware extends SerializerMiddleware { flush(); allocationScope.leftOverBuffer = leftOverBuffer; const result = - /** @type {(Exclude>)[]} */ ( - thing() - ); + /** @type {PrimitiveSerializableType[]} */ + (thing()); const data = this._serialize(result, context, allocationScope); leftOverBuffer = allocationScope.leftOverBuffer; allocationScope.leftOverBuffer = null; - SerializerMiddleware.setLazySerializedValue(thing, data); + SerializerMiddleware.setLazySerializedValue( + /** @type {LazyFunction} */ + (thing), + data + ); serializedData = data; } else { - serializedData = this._serializeLazy(thing, context); + serializedData = this._serializeLazy( + /** @type {LazyFunction} */ + (thing), + context + ); flush(); buffers.push(serializedData); break; @@ -655,7 +666,7 @@ class BinaryMiddleware extends SerializerMiddleware { * @private * @param {SerializedType} content content * @param {Context} context context object - * @returns {LazyFn} lazy function + * @returns {LazyFunction} lazy function */ _createLazyDeserialized(content, context) { return SerializerMiddleware.createLazy( @@ -668,9 +679,9 @@ class BinaryMiddleware extends SerializerMiddleware { /** * @private - * @param {LazyFn} fn lazy function + * @param {LazyFunction} fn lazy function * @param {Context} context context object - * @returns {TODO} new lazy + * @returns {LazyFunction} new lazy */ _deserializeLazy(fn, context) { return SerializerMiddleware.deserializeLazy(fn, data => @@ -807,13 +818,17 @@ class BinaryMiddleware extends SerializerMiddleware { return () => { const count = readU32(); const lengths = Array.from({ length: count }).map(() => readU32()); + /** @type {(Buffer | LazyFunction)[]} */ const content = []; for (let l of lengths) { if (l === 0) { if (typeof currentBuffer !== "function") { throw new Error("Unexpected non-lazy element in stream"); } - content.push(currentBuffer); + content.push( + /** @type {LazyFunction} */ + (currentBuffer) + ); currentDataItem++; currentBuffer = currentDataItem < data.length ? data[currentDataItem] : null; @@ -1129,7 +1144,13 @@ class BinaryMiddleware extends SerializerMiddleware { let result = []; while (currentBuffer !== null) { if (typeof currentBuffer === "function") { - result.push(this._deserializeLazy(currentBuffer, context)); + result.push( + this._deserializeLazy( + /** @type {LazyFunction} */ + (currentBuffer), + context + ) + ); currentDataItem++; currentBuffer = currentDataItem < data.length ? data[currentDataItem] : null; diff --git a/lib/serialization/FileMiddleware.js b/lib/serialization/FileMiddleware.js index 71a3a00d0..671ea1234 100644 --- a/lib/serialization/FileMiddleware.js +++ b/lib/serialization/FileMiddleware.js @@ -22,9 +22,13 @@ const SerializerMiddleware = require("./SerializerMiddleware"); /** @typedef {import("../util/fs").IStats} IStats */ /** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */ /** @typedef {import("./SerializerMiddleware").Context} Context */ -/** @typedef {import("./SerializerMiddleware").LazyFn} LazyFn */ /** @typedef {import("./types").BufferSerializableType} BufferSerializableType */ +/** + * @template LAZY_RESULT + * @typedef {import("./SerializerMiddleware").LazyFunction} LazyFunction + */ + /* Format: @@ -81,11 +85,13 @@ const readUInt64LE = Buffer.prototype.readBigUInt64LE return high * 0x100000000 + low; }; +/** @typedef {Promise} BackgroundJob */ + /** * @typedef {object} SerializeResult * @property {string | false} name * @property {number} size - * @property {Promise=} backgroundJob + * @property {BackgroundJob=} backgroundJob */ /** @@ -103,9 +109,9 @@ const serialize = async ( writeFile, hashFunction = "md4" ) => { - /** @type {(Buffer[] | Buffer | SerializeResult | Promise)[]} */ + /** @type {(Buffer[] | Buffer | Promise)[]} */ const processedData = []; - /** @type {WeakMap} */ + /** @type {WeakMap>} */ const resultToLazy = new WeakMap(); /** @type {Buffer[] | undefined} */ let lastBuffers; @@ -131,7 +137,10 @@ const serialize = async ( } else { const content = item(); if (content) { - const options = SerializerMiddleware.getLazyOptions(item); + const options = SerializerMiddleware.getLazyOptions( + /** @type {LazyFunction} */ + (item) + ); processedData.push( serialize( middleware, @@ -140,8 +149,13 @@ const serialize = async ( writeFile, hashFunction ).then(result => { - /** @type {any} */ (item).options.size = result.size; - resultToLazy.set(result, item); + /** @type {LazyFunction} */ + (item).options.size = result.size; + resultToLazy.set( + result, + /** @type {LazyFunction} */ + (item) + ); return result; }) ); @@ -162,24 +176,24 @@ const serialize = async ( throw new Error("Unexpected falsy value in items array"); } } - /** @type {Promise[]} */ + /** @type {BackgroundJob[]} */ const backgroundJobs = []; - const resolvedData = ( - await Promise.all( - /** @type {Promise[]} */ - (processedData) - ) - ).map(item => { + const resolvedData = (await Promise.all(processedData)).map(item => { if (Array.isArray(item) || Buffer.isBuffer(item)) return item; - backgroundJobs.push(item.backgroundJob); + backgroundJobs.push( + /** @type {BackgroundJob} */ + (item.backgroundJob) + ); // create pointer buffer from size and name const name = /** @type {string} */ (item.name); const nameBuffer = Buffer.from(name); const buf = Buffer.allocUnsafe(8 + nameBuffer.length); writeUInt64LE(buf, item.size, 0); nameBuffer.copy(buf, 8, 0); - const lazy = resultToLazy.get(item); + const lazy = + /** @type {LazyFunction} */ + (resultToLazy.get(item)); SerializerMiddleware.setLazySerializedValue(lazy, buf); return buf; }); @@ -227,7 +241,7 @@ const serialize = async ( backgroundJob: backgroundJobs.length === 1 ? backgroundJobs[0] - : Promise.all(backgroundJobs) + : /** @type {BackgroundJob} */ (Promise.all(backgroundJobs)) }; }; @@ -336,6 +350,7 @@ const deserialize = async (middleware, name, readFile) => { lastLengthPositive = valuePositive; } } + /** @type {(Buffer | LazyFunction)[]} */ const result = []; for (let length of lengths) { if (length < 0) { @@ -343,17 +358,14 @@ const deserialize = async (middleware, name, readFile) => { const size = Number(readUInt64LE(slice, 0)); const nameBuffer = slice.slice(8); const name = nameBuffer.toString(); - result.push( - SerializerMiddleware.createLazy( - memoize(() => deserialize(middleware, name, readFile)), - middleware, - { - name, - size - }, - slice - ) + /** @type {LazyFunction} */ + const lazy = SerializerMiddleware.createLazy( + memoize(() => deserialize(middleware, name, readFile)), + middleware, + { name, size }, + slice ); + result.push(lazy); } else { if (contentPosition === contentItemLength) { nextContent(); @@ -431,7 +443,7 @@ class FileMiddleware extends SerializerMiddleware { /** * @param {DeserializedType} data data * @param {Context} context context object - * @returns {SerializedType | Promise} serialized data + * @returns {SerializedType | Promise | null} serialized data */ serialize(data, context) { const { filename, extension = "" } = context; @@ -616,7 +628,7 @@ class FileMiddleware extends SerializerMiddleware { let currentBuffer; /** @type {number | undefined} */ let currentBufferUsed; - /** @type {any[]} */ + /** @type {Buffer[]} */ const buf = []; /** @type {import("zlib").Zlib & import("stream").Transform | undefined} */ let decompression; @@ -630,7 +642,12 @@ class FileMiddleware extends SerializerMiddleware { }); } if (decompression) { + /** @typedef {(value: Buffer[] | PromiseLike) => void} NewResolve */ + /** @typedef {(reason?: Error) => void} NewReject */ + + /** @type {NewResolve | undefined} */ let newResolve; + /** @type {NewReject | undefined} */ let newReject; resolve( Promise.all([ @@ -638,15 +655,21 @@ class FileMiddleware extends SerializerMiddleware { newResolve = rs; newReject = rj; }), - new Promise((resolve, reject) => { - decompression.on("data", chunk => buf.push(chunk)); - decompression.on("end", () => resolve()); - decompression.on("error", err => reject(err)); - }) + new Promise( + /** + * @param {(value?: undefined) => void} resolve resolve + * @param {(reason?: Error) => void} reject reject + */ + (resolve, reject) => { + decompression.on("data", chunk => buf.push(chunk)); + decompression.on("end", () => resolve()); + decompression.on("error", err => reject(err)); + } + ) ]).then(() => buf) ); - resolve = newResolve; - reject = newReject; + resolve = /** @type {NewResolve} */ (newResolve); + reject = /** @type {NewReject} */ (newReject); } this.fs.open(file, "r", (err, _fd) => { if (err) { @@ -696,12 +719,16 @@ class FileMiddleware extends SerializerMiddleware { remaining -= bytesRead; if ( currentBufferUsed === - /** @type {Buffer} */ (currentBuffer).length + /** @type {Buffer} */ + (currentBuffer).length ) { if (decompression) { decompression.write(currentBuffer); } else { - buf.push(currentBuffer); + buf.push( + /** @type {Buffer} */ + (currentBuffer) + ); } currentBuffer = undefined; if (remaining === 0) { diff --git a/lib/serialization/ObjectMiddleware.js b/lib/serialization/ObjectMiddleware.js index a84f97176..5971e24b4 100644 --- a/lib/serialization/ObjectMiddleware.js +++ b/lib/serialization/ObjectMiddleware.js @@ -20,7 +20,12 @@ const SetObjectSerializer = require("./SetObjectSerializer"); /** @typedef {import("./types").ComplexSerializableType} ComplexSerializableType */ /** @typedef {import("./types").PrimitiveSerializableType} PrimitiveSerializableType */ -/** @typedef {new (...params: any[]) => any} Constructor */ +/** @typedef {new (...params: EXPECTED_ANY[]) => EXPECTED_ANY} Constructor */ + +/** + * @template LAZY_RESULT + * @typedef {import("./SerializerMiddleware").LazyFunction} LazyFunction + */ /* @@ -315,7 +320,7 @@ class ObjectMiddleware extends SerializerMiddleware { /** * @param {DeserializedType} data data * @param {Context} context context object - * @returns {SerializedType | Promise} serialized data + * @returns {SerializedType | Promise | null} serialized data */ serialize(data, context) { /** @type {Item[]} */ @@ -785,8 +790,11 @@ class ObjectMiddleware extends SerializerMiddleware { return item; } else if (typeof item === "function") { return SerializerMiddleware.deserializeLazy( - item, - data => this.deserialize(data, context)[0] + /** @type {LazyFunction} */ + (item), + data => + /** @type {[DeserializedType]} */ + (this.deserialize(data, context))[0] ); } else { return item; diff --git a/lib/serialization/Serializer.js b/lib/serialization/Serializer.js index 6c820166c..6265d939c 100644 --- a/lib/serialization/Serializer.js +++ b/lib/serialization/Serializer.js @@ -23,16 +23,18 @@ class Serializer { } /** - * @param {any} obj object + * @param {TODO | Promise} obj object * @param {Context} context context object - * @returns {Promise} result + * @returns {Promise} result */ serialize(obj, context) { const ctx = { ...context, ...this.context }; let current = obj; for (const middleware of this.serializeMiddlewares) { if (current && typeof current.then === "function") { - current = current.then(data => data && middleware.serialize(data, ctx)); + current = + /** @type {Promise} */ + (current).then(data => data && middleware.serialize(data, ctx)); } else if (current) { try { current = middleware.serialize(current, ctx); @@ -45,18 +47,19 @@ class Serializer { } /** - * @param {any} value value + * @param {TODO | Promise} value value * @param {Context} context object - * @returns {Promise} result + * @returns {Promise} result */ deserialize(value, context) { const ctx = { ...context, ...this.context }; - /** @type {any} */ let current = value; for (const middleware of this.deserializeMiddlewares) { current = current && typeof current.then === "function" - ? current.then(data => middleware.deserialize(data, ctx)) + ? /** @type {Promise} */ (current).then(data => + middleware.deserialize(data, ctx) + ) : middleware.deserialize(current, ctx); } return current; diff --git a/lib/serialization/SerializerMiddleware.js b/lib/serialization/SerializerMiddleware.js index 75e03c634..032a4a670 100644 --- a/lib/serialization/SerializerMiddleware.js +++ b/lib/serialization/SerializerMiddleware.js @@ -10,8 +10,18 @@ const LAZY_TARGET = Symbol("lazy serialization target"); const LAZY_SERIALIZED_VALUE = Symbol("lazy serialization data"); /** @typedef {TODO} Context */ -/** @typedef {function(): Promise | any} LazyFn */ -/** @typedef {Record} LazyOptions */ + +/** + * @template LazyResult + * @typedef {function(): LazyResult | Promise} InternalLazyFunction + */ + +/** @typedef {Record} LazyOptions */ + +/** + * @template LazyResult + * @typedef {InternalLazyFunction & { [LAZY_TARGET]: TODO, [LAZY_SERIALIZED_VALUE]?: TODO, options: LazyOptions }} LazyFunction + */ /** * @template DeserializedType @@ -23,7 +33,7 @@ class SerializerMiddleware { * @abstract * @param {DeserializedType} data data * @param {Context} context context object - * @returns {SerializedType | Promise} serialized data + * @returns {SerializedType | Promise | null} serialized data */ serialize(data, context) { const AbstractMethodError = require("../AbstractMethodError"); @@ -43,23 +53,26 @@ class SerializerMiddleware { } /** - * @param {any | LazyFn} value contained value or function to value + * @template LazyResult + * @param {LazyFunction | EXPECTED_ANY} value contained value or function to value * @param {SerializerMiddleware} target target middleware * @param {LazyOptions=} options lazy options * @param {any=} serializedValue serialized value - * @returns {LazyFn} lazy function + * @returns {LazyFunction} lazy function */ static createLazy(value, target, options = {}, serializedValue = undefined) { if (SerializerMiddleware.isLazy(value, target)) return value; - const fn = typeof value === "function" ? value : () => value; + const fn = + /** @type {LazyFunction} */ + (typeof value === "function" ? value : () => value); fn[LAZY_TARGET] = target; - /** @type {any} */ (fn).options = options; + fn.options = options; fn[LAZY_SERIALIZED_VALUE] = serializedValue; return fn; } /** - * @param {LazyFn} fn lazy function + * @param {EXPECTED_ANY} fn lazy function * @param {SerializerMiddleware=} target target middleware * @returns {boolean} true, when fn is a lazy function (optionally of that target) */ @@ -70,7 +83,8 @@ class SerializerMiddleware { } /** - * @param {LazyFn} fn lazy function + * @template LazyResult + * @param {LazyFunction} fn lazy function * @returns {LazyOptions | undefined} options */ static getLazyOptions(fn) { @@ -79,7 +93,8 @@ class SerializerMiddleware { } /** - * @param {LazyFn} fn lazy function + * @template LazyResult + * @param {LazyFunction | EXPECTED_ANY} fn lazy function * @returns {any | undefined} serialized value */ static getLazySerializedValue(fn) { @@ -88,8 +103,9 @@ class SerializerMiddleware { } /** - * @param {LazyFn} fn lazy function - * @param {any} value serialized value + * @template LazyResult + * @param {LazyFunction} fn lazy function + * @param {TODO} value serialized value * @returns {void} */ static setLazySerializedValue(fn, value) { @@ -97,50 +113,69 @@ class SerializerMiddleware { } /** - * @param {LazyFn} lazy lazy function - * @param {function(any): Promise | any} serialize serialize function - * @returns {LazyFn} new lazy + * @template LazyResult, R + * @param {LazyFunction} lazy lazy function + * @param {function(LazyResult): Promise | R} serialize serialize function + * @returns {LazyFunction} new lazy */ static serializeLazy(lazy, serialize) { - const fn = memoize(() => { - const r = lazy(); - if (r && typeof r.then === "function") { - return r.then(data => data && serialize(data)); - } - return serialize(r); - }); + const fn = /** @type {LazyFunction} */ ( + memoize(() => { + const r = lazy(); + if ( + r && + typeof (/** @type {Promise} */ (r).then) === "function" + ) { + return ( + /** @type {Promise} */ + (r).then(data => data && serialize(data)) + ); + } + return serialize(/** @type {LazyResult} */ (r)); + }) + ); fn[LAZY_TARGET] = lazy[LAZY_TARGET]; - /** @type {any} */ (fn).options = /** @type {any} */ (lazy).options; + fn.options = lazy.options; lazy[LAZY_SERIALIZED_VALUE] = fn; return fn; } /** - * @template T - * @param {LazyFn} lazy lazy function - * @param {function(T): Promise | T} deserialize deserialize function - * @returns {function(): Promise | T} new lazy + * @template LazyResult, R + * @param {LazyFunction} lazy lazy function + * @param {function(LazyResult): Promise | R} deserialize deserialize function + * @returns {LazyFunction} new lazy */ static deserializeLazy(lazy, deserialize) { - const fn = memoize(() => { - const r = lazy(); - if (r && typeof r.then === "function") { - return r.then(data => deserialize(data)); - } - return deserialize(r); - }); + const fn = /** @type {LazyFunction} */ ( + memoize(() => { + const r = lazy(); + if ( + r && + typeof (/** @type {Promise} */ (r).then) === "function" + ) { + return ( + /** @type {Promise} */ + (r).then(data => deserialize(data)) + ); + } + return deserialize(/** @type {LazyResult} */ (r)); + }) + ); fn[LAZY_TARGET] = lazy[LAZY_TARGET]; - /** @type {any} */ (fn).options = /** @type {any} */ (lazy).options; + fn.options = lazy.options; fn[LAZY_SERIALIZED_VALUE] = lazy; return fn; } /** - * @param {LazyFn} lazy lazy function - * @returns {LazyFn} new lazy + * @template LazyResult + * @param {LazyFunction | EXPECTED_ANY} lazy lazy function + * @returns {LazyFunction | EXPECTED_ANY} new lazy */ static unMemoizeLazy(lazy) { if (!SerializerMiddleware.isLazy(lazy)) return lazy; + /** @type {LazyFunction} */ const fn = () => { throw new Error( "A lazy value that has been unmemorized can't be called again" @@ -150,7 +185,7 @@ class SerializerMiddleware { lazy[LAZY_SERIALIZED_VALUE] ); fn[LAZY_TARGET] = lazy[LAZY_TARGET]; - fn.options = /** @type {any} */ (lazy).options; + fn.options = lazy.options; return fn; } } diff --git a/lib/serialization/SingleItemMiddleware.js b/lib/serialization/SingleItemMiddleware.js index 23e72f7d8..866510f6b 100644 --- a/lib/serialization/SingleItemMiddleware.js +++ b/lib/serialization/SingleItemMiddleware.js @@ -18,7 +18,7 @@ class SingleItemMiddleware extends SerializerMiddleware { /** * @param {DeserializedType} data data * @param {Context} context context object - * @returns {SerializedType | Promise} serialized data + * @returns {SerializedType | Promise | null} serialized data */ serialize(data, context) { return [data]; diff --git a/lib/util/fs.js b/lib/util/fs.js index 14a18c6dc..8e7e2032d 100644 --- a/lib/util/fs.js +++ b/lib/util/fs.js @@ -431,7 +431,7 @@ const path = require("path"); */ /** - * @template {NodeJS.ArrayBufferView} [TBuffer=Buffer] + * @template {NodeJS.ArrayBufferView} [TBuffer=NodeJS.ArrayBufferView] * @typedef {{ * (fd: number, buffer: TBuffer, offset: number, length: number, position: ReadPosition | null, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void; * (fd: number, options: ReadAsyncOptions, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void; diff --git a/lib/util/memoize.js b/lib/util/memoize.js index d3fc19634..74d5d6200 100644 --- a/lib/util/memoize.js +++ b/lib/util/memoize.js @@ -4,7 +4,10 @@ "use strict"; -/** @template T @typedef {function(): T} FunctionReturning */ +/** + * @template T + * @typedef {function(): T} FunctionReturning + */ /** * @template T diff --git a/test/configCases/context-replacement/f/folder/a.js b/test/configCases/context-replacement/f/folder/a.js new file mode 100644 index 000000000..6cd1d0075 --- /dev/null +++ b/test/configCases/context-replacement/f/folder/a.js @@ -0,0 +1 @@ +module.exports = "a"; diff --git a/test/configCases/context-replacement/f/folder/nested/error.js b/test/configCases/context-replacement/f/folder/nested/error.js new file mode 100644 index 000000000..a7450cb49 --- /dev/null +++ b/test/configCases/context-replacement/f/folder/nested/error.js @@ -0,0 +1,7 @@ +This +should +result +in +an +error +}]) \ No newline at end of file diff --git a/test/configCases/context-replacement/f/index.js b/test/configCases/context-replacement/f/index.js new file mode 100644 index 000000000..6051fcfb0 --- /dev/null +++ b/test/configCases/context-replacement/f/index.js @@ -0,0 +1,6 @@ +it("should replace a context with a new regExp", function() { + function rqInContext(x) { + return require('./folder/' + x); + } + expect(rqInContext("a")).toBe("a"); +}); diff --git a/test/configCases/context-replacement/f/webpack.config.js b/test/configCases/context-replacement/f/webpack.config.js new file mode 100644 index 000000000..d08bb1ac4 --- /dev/null +++ b/test/configCases/context-replacement/f/webpack.config.js @@ -0,0 +1,6 @@ +var webpack = require("../../../../"); + +/** @type {import("../../../../").Configuration} */ +module.exports = { + plugins: [new webpack.ContextReplacementPlugin(/folder$/, false, /(a|b)/)] +}; diff --git a/types.d.ts b/types.d.ts index 6ba78a978..67ca066c0 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1704,6 +1704,12 @@ declare interface CodeGenerationContext { */ sourceTypes?: ReadonlySet; } +declare interface CodeGenerationJob { + module: Module; + hash: string; + runtime: RuntimeSpec; + runtimes: RuntimeSpec[]; +} declare interface CodeGenerationResult { /** * the resulting sources for all source types @@ -2168,12 +2174,7 @@ declare class Compilation { sortItemsWithChunkIds(): void; summarizeDependencies(): void; createModuleHashes(): void; - createHash(): { - module: Module; - hash: string; - runtime: RuntimeSpec; - runtimes: RuntimeSpec[]; - }[]; + createHash(): CodeGenerationJob[]; fullHash?: string; hash?: string; emitAsset(file: string, source: Source, assetInfo?: AssetInfo): void; @@ -3060,15 +3061,21 @@ declare interface ContextModuleOptions { declare class ContextReplacementPlugin { constructor( resourceRegExp: RegExp, - newContentResource?: any, - newContentRecursive?: any, + newContentResource?: string | boolean | RegExp | ((context?: any) => void), + newContentRecursive?: boolean | RegExp | NewContentCreateContextMap, newContentRegExp?: RegExp ); resourceRegExp: RegExp; - newContentCallback: any; - newContentResource: any; - newContentCreateContextMap: any; - newContentRecursive: any; + newContentCallback?: (context?: any) => void; + newContentResource?: string; + newContentCreateContextMap?: ( + fs: InputFileSystem, + callback: ( + err: null | Error, + newContentRecursive: NewContentCreateContextMap + ) => void + ) => void; + newContentRecursive?: boolean; newContentRegExp?: RegExp; /** @@ -4791,7 +4798,7 @@ declare class ExternalModule extends Module { * restore unsafe cache data */ restoreFromUnsafeCache( - unsafeCacheData: object, + unsafeCacheData: UnsafeCacheData, normalModuleFactory: NormalModuleFactory ): void; } @@ -5832,7 +5839,7 @@ declare interface IntermediateFileSystemExtras { | WriteStreamOptions ) => NodeJS.WritableStream; open: Open; - read: Read; + read: Read; close: ( arg0: number, arg1: (arg0: null | NodeJS.ErrnoException) => void @@ -7830,6 +7837,19 @@ declare interface KnownStatsProfile { factory: number; dependencies: number; } +declare interface KnownUnsafeCacheData { + /** + * factory meta + */ + factoryMeta?: FactoryMeta; + + /** + * resolve options + */ + resolveOptions?: ResolveOptions; + parserOptions?: ParserOptions; + generatorOptions?: GeneratorOptions; +} declare interface LStatFs { ( path: PathLikeFs, @@ -9195,9 +9215,10 @@ declare interface ModuleMemCachesItem { memCache: WeakTupleMap; } declare interface ModuleObject { - id: string; + id?: string; exports: any; loaded: boolean; + error?: Error; } /** @@ -9616,6 +9637,9 @@ declare interface NeedBuildContext { fileSystemInfo: FileSystemInfo; valueCacheVersions: Map>; } +declare interface NewContentCreateContextMap { + [index: string]: string; +} declare class NoEmitOnErrorsPlugin { constructor(); @@ -9714,7 +9738,7 @@ declare class NormalModule extends Module { * restore unsafe cache data */ restoreFromUnsafeCache( - unsafeCacheData: NormalModuleUnsafeCacheData, + unsafeCacheData: UnsafeCacheData, normalModuleFactory: NormalModuleFactory ): void; createSourceForAsset( @@ -9984,12 +10008,6 @@ declare class NormalModuleReplacementPlugin { */ apply(compiler: Compiler): void; } -type NormalModuleUnsafeCacheData = UnsafeCacheData & { - parser?: Parser; - parserOptions?: ParserOptions; - generator?: Generator; - generatorOptions?: GeneratorOptions; -}; type NormalizedStatsOptions = KnownNormalizedStatsOptions & Omit< StatsOptions, @@ -11335,32 +11353,32 @@ declare interface PlatformTargetProperties { /** * web platform, importing of http(s) and std: is available */ - web: null | boolean; + web?: null | boolean; /** * browser platform, running in a normal web browser */ - browser: null | boolean; + browser?: null | boolean; /** * (Web)Worker platform, running in a web/shared/service worker */ - webworker: null | boolean; + webworker?: null | boolean; /** * node platform, require of node built-in modules is available */ - node: null | boolean; + node?: null | boolean; /** * nwjs platform, require of legacy nw.gui is available */ - nwjs: null | boolean; + nwjs?: null | boolean; /** * electron platform, require of some electron built-in modules is available */ - electron: null | boolean; + electron?: null | boolean; } type Plugin = | undefined @@ -11422,7 +11440,7 @@ declare class Profiler { inspector: any; hasSession(): boolean; startProfiling(): Promise | Promise<[any, any, any]>; - sendCommand(method: string, params?: object): Promise; + sendCommand(method: string, params?: Record): Promise; destroy(): Promise; stopProfiling(): Promise<{ profile: any }>; } @@ -11625,7 +11643,7 @@ declare interface RawSourceMap { mappings: string; file: string; } -declare interface Read { +declare interface Read { ( fd: number, buffer: TBuffer, @@ -12988,10 +13006,10 @@ declare interface ResourceDataWithData { data: Record; } declare abstract class RestoreProvidedData { - exports: any; - otherProvided: any; - otherCanMangleProvide: any; - otherTerminalBinding: any; + exports: any[]; + otherProvided?: null | boolean; + otherCanMangleProvide?: boolean; + otherTerminalBinding: boolean; serialize(__0: ObjectSerializerContext): void; } declare interface RmDirOptions { @@ -13981,7 +13999,7 @@ declare abstract class SerializerMiddleware { serialize( data: DeserializedType, context?: any - ): SerializedType | Promise; + ): null | SerializedType | Promise; deserialize( data: SerializedType, context?: any @@ -15271,10 +15289,7 @@ declare const UNDEFINED_MARKER: unique symbol; * https://nodejs.org/api/url.html#the-whatwg-url-api */ declare interface URL_url extends URL {} -declare interface UnsafeCacheData { - factoryMeta?: FactoryMeta; - resolveOptions?: ResolveOptions; -} +type UnsafeCacheData = KnownUnsafeCacheData & Record; declare interface UpdateHashContextDependency { chunkGraph: ChunkGraph; runtime: RuntimeSpec;