fix: a lot of types (#19486)

This commit is contained in:
Alexander Akait 2025-05-01 17:36:51 +03:00 committed by GitHub
parent ea3ba3dfcc
commit bc258291f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
152 changed files with 1704 additions and 521 deletions

View File

@ -6,6 +6,8 @@ test/**/*.*
!test/*.cjs
!test/*.mjs
!test/**/webpack.config.js
!test/**/webpack.config.cjs
!test/**/webpack.config.mjs
!test/**/test.config.js
!test/**/test.filter.js
!test/**/errors.js
@ -15,7 +17,6 @@ test/**/*.*
!test/*.md
!test/helpers/*.*
!test/benchmarkCases/**/*.mjs
!test/_helpers/**/*.mjs
test/js/**/*.*
# Ignore some folders

View File

@ -1,5 +1,8 @@
declare module "*.json";
type Env = Record<string, any>;
type TestOptions = { testPath: string, srcPath: string };
declare namespace jest {
interface Matchers<R> {
toBeTypeOf: (

View File

@ -245,9 +245,9 @@ type AdditionalData = {
};
type WebpackLoaderContextCallback = (
err: Error | undefined | null,
err: undefined | null | Error,
content?: string | Buffer,
sourceMap?: string | SourceMap,
sourceMap?: null | string | SourceMap,
additionalData?: AdditionalData
) => void;

View File

@ -187,13 +187,26 @@ export type ExternalItem =
| RegExp
| string
| (ExternalItemObjectKnown & ExternalItemObjectUnknown)
| (
| ((
| ExternalItemFunction;
/**
* The function is called on each dependency.
*/
export type ExternalItemFunction =
| ExternalItemFunctionCallback
| ExternalItemFunctionPromise;
/**
* The function is called on each dependency (`function(context, request, callback(err, result))`).
*/
export type ExternalItemFunctionCallback = (
data: ExternalItemFunctionData,
callback: (err?: Error | null, result?: ExternalItemValue) => void
) => void)
| ((data: ExternalItemFunctionData) => Promise<ExternalItemValue>)
);
) => void;
/**
* The function is called on each dependency (`function(context, request)`).
*/
export type ExternalItemFunctionPromise = (
data: ExternalItemFunctionData
) => Promise<ExternalItemValue>;
/**
* Specifies the default type of externals ('amd*', 'umd*', 'system' and 'jsonp' depend on output.libraryTarget set to the same value).
*/
@ -349,13 +362,7 @@ export type ResolvePluginInstance =
*/
export type RuleSetUse =
| (Falsy | RuleSetUseItem)[]
| ((data: {
resource: string;
realResource: string;
resourceQuery: string;
issuer: string;
compiler: string;
}) => (Falsy | RuleSetUseItem)[])
| RuleSetUseFunction
| RuleSetUseItem;
/**
* A description of an applied loader.
@ -375,8 +382,14 @@ export type RuleSetUseItem =
*/
options?: RuleSetLoaderOptions;
}
| ((data: object) => RuleSetUseItem | (Falsy | RuleSetUseItem)[])
| RuleSetUseFunction
| RuleSetLoader;
/**
* The function is called on each data and return rule set item.
*/
export type RuleSetUseFunction = (
data: import("../lib/rules/RuleSetCompiler").EffectData
) => RuleSetUseItem | (Falsy | RuleSetUseItem)[];
/**
* A list of rules.
*/
@ -390,10 +403,10 @@ export type GeneratorOptionsByModuleType = GeneratorOptionsByModuleTypeKnown &
* Don't parse files matching. It's matched against the full resolved request.
*/
export type NoParse =
| (RegExp | string | Function)[]
| (RegExp | string | ((content: string) => boolean))[]
| RegExp
| string
| Function;
| ((content: string) => boolean);
/**
* Specify options for each parser.
*/
@ -424,8 +437,19 @@ export type OptimizationRuntimeChunk =
/**
* The name or name factory for the runtime chunks.
*/
name?: string | Function;
name?:
| string
| import("../lib/optimize/RuntimeChunkPlugin").RuntimeChunkFunction;
};
/**
* A function returning cache groups.
*/
export type OptimizationSplitChunksGetCacheGroups = (
module: import("../lib/Module")
) =>
| OptimizationSplitChunksCacheGroup
| OptimizationSplitChunksCacheGroup[]
| void;
/**
* Size description for limits.
*/
@ -794,6 +818,33 @@ export type EntryNormalized = EntryDynamicNormalized | EntryStaticNormalized;
*/
export type ExperimentsNormalized = ExperimentsCommon &
ExperimentsNormalizedExtra;
/**
* Get a resolve function with the current resolver options.
*/
export type ExternalItemFunctionDataGetResolve = (
options?: ResolveOptions
) =>
| ExternalItemFunctionDataGetResolveCallbackResult
| ExternalItemFunctionDataGetResolveResult;
/**
* Result of get a resolve function with the current resolver options.
*/
export type ExternalItemFunctionDataGetResolveCallbackResult = (
context: string,
request: string,
callback: (
err?: Error | null,
result?: string | false,
resolveRequest?: import("enhanced-resolve").ResolveRequest
) => void
) => void;
/**
* Callback result of get a resolve function with the current resolver options.
*/
export type ExternalItemFunctionDataGetResolveResult = (
context: string,
request: string
) => Promise<string>;
/**
* The dependency used for the external.
*/
@ -832,17 +883,8 @@ export type OptimizationRuntimeChunkNormalized =
/**
* The name factory for the runtime chunks.
*/
name?: Function;
name?: import("../lib/optimize/RuntimeChunkPlugin").RuntimeChunkFunction;
};
/**
* A function returning cache groups.
*/
export type OptimizationSplitChunksGetCacheGroups = (
module: import("../lib/Module")
) =>
| OptimizationSplitChunksCacheGroup
| OptimizationSplitChunksCacheGroup[]
| void;
/**
* Options object as provided by the user.
@ -1368,7 +1410,7 @@ export interface ModuleOptions {
/**
* Cache the resolving of module requests.
*/
unsafeCache?: boolean | Function;
unsafeCache?: boolean | ((module: import("../lib/Module")) => boolean);
/**
* Enable warnings for partial dynamic dependencies. Deprecated: This option has moved to 'module.parser.javascript.wrappedContextCritical'.
*/
@ -1835,7 +1877,7 @@ export interface OptimizationSplitChunksOptions {
| false
| RegExp
| string
| Function
| OptimizationSplitChunksGetCacheGroups
| OptimizationSplitChunksCacheGroup;
};
/**
@ -2387,7 +2429,11 @@ export interface PerformanceOptions {
/**
* Filter function to select assets that are checked.
*/
assetFilter?: Function;
assetFilter?: (
name: import("../lib/Compilation").Asset["name"],
source: import("../lib/Compilation").Asset["source"],
assetInfo: import("../lib/Compilation").Asset["info"]
) => boolean;
/**
* Sets the format of the hints: warnings, errors or nothing at all.
*/
@ -3178,19 +3224,7 @@ export interface ExternalItemFunctionData {
/**
* Get a resolve function with the current resolver options.
*/
getResolve?: (
options?: ResolveOptions
) =>
| ((
context: string,
request: string,
callback: (
err?: Error | null,
result?: string | false,
resolveRequest?: import("enhanced-resolve").ResolveRequest
) => void
) => void)
| ((context: string, request: string) => Promise<string>);
getResolve?: ExternalItemFunctionDataGetResolve;
/**
* The request as written by the user in the require/import expression/statement.
*/
@ -3392,6 +3426,21 @@ export interface JsonGeneratorOptions {
*/
JSONParse?: boolean;
}
/**
* Parser options for JSON modules.
*/
export interface JsonParserOptions {
/**
* The depth of json dependency flagged as `exportInfo`.
*/
exportsDepth?: number;
/**
* Function to parser content and return JSON.
*/
parse?: (
input: string
) => Buffer | import("../lib/json/JsonParser").JsonValue;
}
/**
* Options for the default backend.
*/
@ -3482,7 +3531,114 @@ export interface ModuleOptionsNormalized {
/**
* Cache the resolving of module requests.
*/
unsafeCache?: boolean | Function;
unsafeCache?: boolean | ((module: import("../lib/Module")) => boolean);
}
/**
* Enables/Disables integrated optimizations.
*/
export interface OptimizationNormalized {
/**
* Avoid wrapping the entry module in an IIFE.
*/
avoidEntryIife?: boolean;
/**
* Check for incompatible wasm types when importing/exporting from/to ESM.
*/
checkWasmTypes?: boolean;
/**
* Define the algorithm to choose chunk ids (named: readable ids for better debugging, deterministic: numeric hash ids for better long term caching, size: numeric ids focused on minimal initial download size, total-size: numeric ids focused on minimal total download size, false: no algorithm used, as custom one can be provided via plugin).
*/
chunkIds?:
| "natural"
| "named"
| "deterministic"
| "size"
| "total-size"
| false;
/**
* Concatenate modules when possible to generate less modules, more efficient code and enable more optimizations by the minimizer.
*/
concatenateModules?: boolean;
/**
* Emit assets even when errors occur. Critical errors are emitted into the generated code and will cause errors at runtime.
*/
emitOnErrors?: boolean;
/**
* Also flag chunks as loaded which contain a subset of the modules.
*/
flagIncludedChunks?: boolean;
/**
* Creates a module-internal dependency graph for top level symbols, exports and imports, to improve unused exports detection.
*/
innerGraph?: boolean;
/**
* Rename exports when possible to generate shorter code (depends on optimization.usedExports and optimization.providedExports, true/"deterministic": generate short deterministic names optimized for caching, "size": generate the shortest possible names).
*/
mangleExports?: ("size" | "deterministic") | boolean;
/**
* Reduce size of WASM by changing imports to shorter strings.
*/
mangleWasmImports?: boolean;
/**
* Merge chunks which contain the same modules.
*/
mergeDuplicateChunks?: boolean;
/**
* Enable minimizing the output. Uses optimization.minimizer.
*/
minimize?: boolean;
/**
* Minimizer(s) to use for minimizing the output.
*/
minimizer?: ("..." | Falsy | WebpackPluginInstance | WebpackPluginFunction)[];
/**
* Define the algorithm to choose module ids (natural: numeric ids in order of usage, named: readable ids for better debugging, hashed: (deprecated) short hashes as ids for better long term caching, deterministic: numeric hash ids for better long term caching, size: numeric ids focused on minimal initial download size, false: no algorithm used, as custom one can be provided via plugin).
*/
moduleIds?: "natural" | "named" | "hashed" | "deterministic" | "size" | false;
/**
* Avoid emitting assets when errors occur (deprecated: use 'emitOnErrors' instead).
*/
noEmitOnErrors?: boolean;
/**
* Set process.env.NODE_ENV to a specific value.
*/
nodeEnv?: false | string;
/**
* Generate records with relative paths to be able to move the context folder.
*/
portableRecords?: boolean;
/**
* Figure out which exports are provided by modules to generate more efficient code.
*/
providedExports?: boolean;
/**
* Use real [contenthash] based on final content of the assets.
*/
realContentHash?: boolean;
/**
* Removes modules from chunks when these modules are already included in all parents.
*/
removeAvailableModules?: boolean;
/**
* Remove chunks which are empty.
*/
removeEmptyChunks?: boolean;
/**
* Create an additional chunk which contains only the webpack runtime and chunk hash maps.
*/
runtimeChunk?: OptimizationRuntimeChunkNormalized;
/**
* Skip over modules which contain no side effects when exports are not used (false: disabled, 'flag': only use manually placed side effects flag, true: also analyse source code for side effects).
*/
sideEffects?: "flag" | boolean;
/**
* Optimize duplication and caching by splitting chunks by shared modules and cache group.
*/
splitChunks?: false | OptimizationSplitChunksOptions;
/**
* Figure out which exports are used by modules to mangle export names, omit unused exports and generate more efficient code (true: analyse used exports for each runtime, "global": analyse exports globally for all runtimes combined).
*/
usedExports?: "global" | boolean;
}
/**
* Normalized options affecting the output of the compilation. `output` options tell webpack how to write the compiled files to disk.
@ -3772,7 +3928,7 @@ export interface WebpackOptionsNormalized {
/**
* Enables/Disables integrated optimizations.
*/
optimization: Optimization;
optimization: OptimizationNormalized;
/**
* Normalized options affecting the output of the compilation. `output` options tell webpack how to write the compiled files to disk.
*/
@ -3999,6 +4155,10 @@ export interface ParserOptionsByModuleTypeKnown {
* Parser options for javascript modules.
*/
"javascript/esm"?: JavascriptParserOptions;
/**
* Parser options for JSON modules.
*/
json?: JsonParserOptions;
}
/**
* Specify options for each parser.

View File

@ -57,6 +57,7 @@ const memoize = require("./util/memoize");
/** @typedef {import("../declarations/WebpackOptions").Mode} Mode */
/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
/** @typedef {import("../declarations/WebpackOptions").NoParse} NoParse */
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
@ -1079,7 +1080,7 @@ class NormalModule extends Module {
}
/**
* @param {TODO} rule rule
* @param {Exclude<NoParse, EXPECTED_ANY[]>} rule rule
* @param {string} content content
* @returns {boolean} result
*/
@ -1097,7 +1098,7 @@ class NormalModule extends Module {
}
/**
* @param {TODO} noParseRule no parse rule
* @param {undefined | NoParse} noParseRule no parse rule
* @param {string} request request
* @returns {boolean} check if module should not be parsed, returns "true" if the module should !not! be parsed, returns "false" if the module !must! be parsed
*/

View File

@ -504,10 +504,7 @@ class WebpackOptionsApply extends OptionsApply {
}
if (options.optimization.runtimeChunk) {
const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
new RuntimeChunkPlugin(
/** @type {{ name?: (entrypoint: { name: string }) => string }} */
(options.optimization.runtimeChunk)
).apply(compiler);
new RuntimeChunkPlugin(options.optimization.runtimeChunk).apply(compiler);
}
if (!options.optimization.emitOnErrors) {
const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");

View File

@ -648,11 +648,14 @@ const applyModuleDefaults = (
"unsafeCache",
/**
* @param {Module} module module
* @returns {boolean | null | string} true, if we want to cache the module
* @returns {boolean} true, if we want to cache the module
*/
module => {
const name = module.nameForCondition();
return name && NODE_MODULES_REGEXP.test(name);
if (!name) {
return false;
}
return NODE_MODULES_REGEXP.test(name);
}
);
} else {
@ -683,7 +686,8 @@ const applyModuleDefaults = (
F(module.parser, "javascript", () => ({}));
F(module.parser, JSON_MODULE_TYPE, () => ({}));
D(
module.parser[JSON_MODULE_TYPE],
/** @type {NonNullable<ParserOptionsByModuleTypeKnown[JSON_MODULE_TYPE]>} */
(module.parser[JSON_MODULE_TYPE]),
"exportsDepth",
mode === "development" ? 1 : Infinity
);

View File

@ -549,16 +549,16 @@ const getNormalizedOptimizationRuntimeChunk = runtimeChunk => {
}
if (runtimeChunk === true || runtimeChunk === "multiple") {
return {
/**
* @param {Entrypoint} entrypoint entrypoint
* @returns {string} runtime chunk name
*/
name: entrypoint => `runtime~${entrypoint.name}`
};
}
const { name } = runtimeChunk;
return {
name: typeof name === "function" ? name : () => name
name:
typeof name === "function"
? /** @type {Exclude<OptimizationRuntimeChunkNormalized, false>["name"]} */
(name)
: () => /** @type {string} */ (name)
};
};

View File

@ -11,20 +11,30 @@ const memoize = require("./util/memoize");
/** @typedef {import("../declarations/WebpackOptions").Entry} Entry */
/** @typedef {import("../declarations/WebpackOptions").EntryNormalized} EntryNormalized */
/** @typedef {import("../declarations/WebpackOptions").EntryObject} EntryObject */
/** @typedef {import("../declarations/WebpackOptions").ExternalItem} ExternalItem */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunction} ExternalItemFunction */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionCallback} ExternalItemFunctionCallback */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionData} ExternalItemFunctionData */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionDataGetResolve} ExternalItemFunctionDataGetResolve */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionDataGetResolveCallbackResult} ExternalItemFunctionDataGetResolveCallbackResult */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionDataGetResolveResult} ExternalItemFunctionDataGetResolveResult */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionPromise} ExternalItemFunctionPromise */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemObjectKnown} ExternalItemObjectKnown */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemObjectUnknown} ExternalItemObjectUnknown */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemValue} ExternalItemValue */
/** @typedef {import("../declarations/WebpackOptions").Externals} Externals */
/** @typedef {import("../declarations/WebpackOptions").FileCacheOptions} FileCacheOptions */
/** @typedef {import("../declarations/WebpackOptions").GeneratorOptionsByModuleTypeKnown} GeneratorOptionsByModuleTypeKnown */
/** @typedef {import("../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
/** @typedef {import("../declarations/WebpackOptions").MemoryCacheOptions} MemoryCacheOptions */
/** @typedef {import("../declarations/WebpackOptions").ModuleOptions} ModuleOptions */
/** @typedef {import("../declarations/WebpackOptions").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */
/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
/** @typedef {import("../declarations/WebpackOptions").RuleSetCondition} RuleSetCondition */
/** @typedef {import("../declarations/WebpackOptions").RuleSetConditionAbsolute} RuleSetConditionAbsolute */
/** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
/** @typedef {import("../declarations/WebpackOptions").RuleSetUse} RuleSetUse */
/** @typedef {import("../declarations/WebpackOptions").RuleSetUseFunction} RuleSetUseFunction */
/** @typedef {import("../declarations/WebpackOptions").RuleSetUseItem} RuleSetUseItem */
/** @typedef {import("../declarations/WebpackOptions").StatsOptions} StatsOptions */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} Configuration */
@ -37,6 +47,7 @@ const memoize = require("./util/memoize");
/** @typedef {import("./Compilation").EntryOptions} EntryOptions */
/** @typedef {import("./Compilation").PathData} PathData */
/** @typedef {import("./Compiler").AssetEmittedInfo} AssetEmittedInfo */
/** @typedef {import("./Entrypoint")} Entrypoint */
/** @typedef {import("./MultiCompiler").MultiCompilerOptions} MultiCompilerOptions */
/** @typedef {import("./MultiStats")} MultiStats */
/** @typedef {import("./NormalModuleFactory").ResolveData} ResolveData */

View File

@ -16,8 +16,8 @@ const JsonParser = require("./JsonParser");
/** @typedef {import("../util/fs").JsonValue} JsonValue */
const validate = createSchemaValidation(
require("../../schemas/plugins/JsonModulesPluginParser.check.js"),
() => require("../../schemas/plugins/JsonModulesPluginParser.json"),
require("../../schemas/plugins/json/JsonModulesPluginParser.check.js"),
() => require("../../schemas/plugins/json/JsonModulesPluginParser.json"),
{
name: "Json Modules Plugin",
baseDataPath: "parser"
@ -25,8 +25,8 @@ const validate = createSchemaValidation(
);
const validateGenerator = createSchemaValidation(
require("../../schemas/plugins/JsonModulesPluginGenerator.check.js"),
() => require("../../schemas/plugins/JsonModulesPluginGenerator.json"),
require("../../schemas/plugins/json/JsonModulesPluginGenerator.check.js"),
() => require("../../schemas/plugins/json/JsonModulesPluginGenerator.json"),
{
name: "Json Modules Plugin",
baseDataPath: "generator"

View File

@ -11,16 +11,15 @@
const PLUGIN_NAME = "RuntimeChunkPlugin";
/** @typedef {(entrypoint: { name: string }) => string} RuntimeChunkFunction */
class RuntimeChunkPlugin {
/**
* @param {{ name?: (entrypoint: { name: string }) => string }} options options
* @param {{ name?: RuntimeChunkFunction }=} options options
*/
constructor(options) {
this.options = {
/**
* @param {Entrypoint} entrypoint entrypoint name
* @returns {string} runtime chunk name
*/
/** @type {RuntimeChunkFunction} */
name: entrypoint => `runtime~${entrypoint.name}`,
...options
};
@ -41,7 +40,7 @@ class RuntimeChunkPlugin {
if (data.options.runtime === undefined && !data.options.dependOn) {
// Determine runtime chunk name
let name =
/** @type {string | ((entrypoint: { name: string }) => string)} */
/** @type {string | RuntimeChunkFunction} */
(this.options.name);
if (typeof name === "function") {
name = name({ name: entryName });

View File

@ -37,8 +37,7 @@ class BasicEffectRulePlugin {
if (unhandledProperties.has(this.ruleProperty)) {
unhandledProperties.delete(this.ruleProperty);
const value =
rule[/** @type {keyof RuleSetRule} */ (this.ruleProperty)];
const value = rule[this.ruleProperty];
result.effects.push({
type: this.effectType,

View File

@ -8,6 +8,7 @@
/** @typedef {import("../../declarations/WebpackOptions").RuleSetConditionOrConditions} RuleSetConditionOrConditions */
/** @typedef {import("../../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
/** @typedef {import("./RuleSetCompiler")} RuleSetCompiler */
/** @typedef {import("./RuleSetCompiler").EffectData} EffectData */
/** @typedef {import("./RuleSetCompiler").RuleCondition} RuleCondition */
/** @typedef {import("./RuleSetCompiler").RuleConditionFunction} RuleConditionFunction */
@ -22,7 +23,7 @@
class ObjectMatcherRulePlugin {
/**
* @param {ObjectMatcherRuleKeys} ruleProperty the rule property
* @param {string=} dataProperty the data property
* @param {keyof EffectData=} dataProperty the data property
* @param {RuleConditionFunction=} additionalConditionFunction need to check
*/
constructor(ruleProperty, dataProperty, additionalConditionFunction) {

View File

@ -13,7 +13,9 @@ const { SyncHook } = require("tapable");
/** @typedef {(Falsy | RuleSetRule)[]} RuleSetRules */
/** @typedef {(value: string | EffectData) => boolean} RuleConditionFunction */
/**
* @typedef {(value: EffectData[keyof EffectData]) => boolean} RuleConditionFunction
*/
/**
* @typedef {object} RuleCondition
@ -29,7 +31,19 @@ const { SyncHook } = require("tapable");
*/
/**
* @typedef {Record<string, TODO>} EffectData
* @typedef {object} EffectData
* @property {string=} resource
* @property {string=} realResource
* @property {string=} resourceQuery
* @property {string=} resourceFragment
* @property {string=} scheme
* @property {ImportAttributes=} assertions
* @property {string=} mimetype
* @property {string} dependency
* @property {Record<string, EXPECTED_ANY>} descriptionData
* @property {string=} compiler
* @property {string} issuer
* @property {string} issuerLayer
*/
/**
@ -102,7 +116,7 @@ class RuleSetCompiler {
for (const condition of rule.conditions) {
const p = condition.property;
if (Array.isArray(p)) {
/** @type {EffectData | string | undefined} */
/** @type {EffectData | EffectData[keyof EffectData] | undefined} */
let current = data;
for (const subProperty of p) {
if (
@ -110,7 +124,7 @@ class RuleSetCompiler {
typeof current === "object" &&
Object.prototype.hasOwnProperty.call(current, subProperty)
) {
current = current[subProperty];
current = current[/** @type {keyof EffectData} */ (subProperty)];
} else {
current = undefined;
break;
@ -121,7 +135,7 @@ class RuleSetCompiler {
continue;
}
} else if (p in data) {
const value = data[p];
const value = data[/** @type {keyof EffectData} */ (p)];
if (value !== undefined) {
if (!condition.fn(value)) return false;
continue;

View File

@ -15,6 +15,7 @@ const util = require("util");
/** @typedef {import("../../declarations/WebpackOptions").RuleSetUseItem} RuleSetUseItem */
/** @typedef {import("./RuleSetCompiler")} RuleSetCompiler */
/** @typedef {import("./RuleSetCompiler").Effect} Effect */
/** @typedef {import("./RuleSetCompiler").EffectData} EffectData */
class UseEffectRulePlugin {
/**
@ -55,7 +56,7 @@ class UseEffectRulePlugin {
* @param {string} path options path
* @param {string} defaultIdent default ident when none is provided
* @param {RuleSetUseItem} item user provided use value
* @returns {Effect | ((value: TODO) => Effect[])} effect
* @returns {(Effect | ((effectData: EffectData) => Effect[]))} effect
*/
const useToEffect = (path, defaultIdent, item) => {
if (typeof item === "function") {
@ -139,7 +140,7 @@ class UseEffectRulePlugin {
/**
* @param {string} path current path
* @param {RuleSetUse} items user provided use value
* @returns {(Effect | ((value: TODO) => Effect[]))[]} effects
* @returns {(Effect | ((effectData: EffectData) => Effect[]))[]} effects
*/
const useToEffects = (path, items) => {
if (Array.isArray(items)) {
@ -160,10 +161,7 @@ class UseEffectRulePlugin {
if (typeof use === "function") {
result.effects.push(data =>
useToEffectsWithoutIdent(
`${path}.use`,
use(/** @type {TODO} */ (data))
)
useToEffectsWithoutIdent(`${path}.use`, use(data))
);
} else {
for (const effect of useToEffects(`${path}.use`, use)) {

View File

@ -45,6 +45,7 @@
"@types/jest": "^29.5.11",
"@types/mime-types": "^2.1.4",
"@types/node": "^22.13.10",
"@types/xxhashjs": "^0.2.4",
"assemblyscript": "^0.27.34",
"babel-loader": "^10.0.0",
"benchmark": "^2.1.4",

File diff suppressed because one or more lines are too long

View File

@ -1179,12 +1179,26 @@
}
},
{
"description": "The function is called on each dependency (`function(context, request, callback(err, result))`).",
"instanceof": "Function",
"tsType": "(((data: ExternalItemFunctionData, callback: (err?: (Error | null), result?: ExternalItemValue) => void) => void) | ((data: ExternalItemFunctionData) => Promise<ExternalItemValue>))"
"$ref": "#/definitions/ExternalItemFunction"
}
]
},
"ExternalItemFunction": {
"description": "The function is called on each dependency.",
"anyOf": [
{
"$ref": "#/definitions/ExternalItemFunctionCallback"
},
{
"$ref": "#/definitions/ExternalItemFunctionPromise"
}
]
},
"ExternalItemFunctionCallback": {
"description": "The function is called on each dependency (`function(context, request, callback(err, result))`).",
"instanceof": "Function",
"tsType": "((data: ExternalItemFunctionData, callback: (err?: (Error | null), result?: ExternalItemValue) => void) => void)"
},
"ExternalItemFunctionData": {
"description": "Data object passed as argument when a function is set for 'externals'.",
"type": "object",
@ -1204,9 +1218,7 @@
"type": "string"
},
"getResolve": {
"description": "Get a resolve function with the current resolver options.",
"instanceof": "Function",
"tsType": "((options?: ResolveOptions) => ((context: string, request: string, callback: (err?: Error | null, result?: string | false, resolveRequest?: import('enhanced-resolve').ResolveRequest) => void) => void) | ((context: string, request: string) => Promise<string>))"
"$ref": "#/definitions/ExternalItemFunctionDataGetResolve"
},
"request": {
"description": "The request as written by the user in the require/import expression/statement.",
@ -1214,6 +1226,26 @@
}
}
},
"ExternalItemFunctionDataGetResolve": {
"description": "Get a resolve function with the current resolver options.",
"instanceof": "Function",
"tsType": "((options?: ResolveOptions) => ExternalItemFunctionDataGetResolveCallbackResult | ExternalItemFunctionDataGetResolveResult)"
},
"ExternalItemFunctionDataGetResolveCallbackResult": {
"description": "Result of get a resolve function with the current resolver options.",
"instanceof": "Function",
"tsType": "((context: string, request: string, callback: (err?: Error | null, result?: string | false, resolveRequest?: import('enhanced-resolve').ResolveRequest) => void) => void)"
},
"ExternalItemFunctionDataGetResolveResult": {
"description": "Callback result of get a resolve function with the current resolver options.",
"instanceof": "Function",
"tsType": "((context: string, request: string) => Promise<string>)"
},
"ExternalItemFunctionPromise": {
"description": "The function is called on each dependency (`function(context, request)`).",
"instanceof": "Function",
"tsType": "((data: ExternalItemFunctionData) => Promise<ExternalItemValue>)"
},
"ExternalItemValue": {
"description": "The dependency used for the external.",
"anyOf": [
@ -2023,6 +2055,22 @@
}
}
},
"JsonParserOptions": {
"description": "Parser options for JSON modules.",
"type": "object",
"additionalProperties": false,
"properties": {
"exportsDepth": {
"description": "The depth of json dependency flagged as `exportInfo`.",
"type": "number"
},
"parse": {
"description": "Function to parser content and return JSON.",
"instanceof": "Function",
"tsType": "((input: string) => Buffer | import('../lib/json/JsonParser').JsonValue)"
}
}
},
"Layer": {
"description": "Specifies the layer in which modules of this entrypoint are placed.",
"anyOf": [
@ -2474,7 +2522,7 @@
},
{
"instanceof": "Function",
"tsType": "Function"
"tsType": "((module: import('../lib/Module')) => boolean)"
}
]
},
@ -2534,7 +2582,7 @@
},
{
"instanceof": "Function",
"tsType": "Function"
"tsType": "((module: import('../lib/Module')) => boolean)"
}
]
}
@ -2565,7 +2613,7 @@
},
{
"instanceof": "Function",
"tsType": "Function"
"tsType": "((content: string) => boolean)"
}
]
},
@ -2583,7 +2631,7 @@
},
{
"instanceof": "Function",
"tsType": "Function"
"tsType": "((content: string) => boolean)"
}
]
},
@ -2784,6 +2832,173 @@
}
}
},
"OptimizationNormalized": {
"description": "Enables/Disables integrated optimizations.",
"type": "object",
"additionalProperties": false,
"properties": {
"avoidEntryIife": {
"description": "Avoid wrapping the entry module in an IIFE.",
"type": "boolean"
},
"checkWasmTypes": {
"description": "Check for incompatible wasm types when importing/exporting from/to ESM.",
"type": "boolean"
},
"chunkIds": {
"description": "Define the algorithm to choose chunk ids (named: readable ids for better debugging, deterministic: numeric hash ids for better long term caching, size: numeric ids focused on minimal initial download size, total-size: numeric ids focused on minimal total download size, false: no algorithm used, as custom one can be provided via plugin).",
"enum": [
"natural",
"named",
"deterministic",
"size",
"total-size",
false
]
},
"concatenateModules": {
"description": "Concatenate modules when possible to generate less modules, more efficient code and enable more optimizations by the minimizer.",
"type": "boolean"
},
"emitOnErrors": {
"description": "Emit assets even when errors occur. Critical errors are emitted into the generated code and will cause errors at runtime.",
"type": "boolean"
},
"flagIncludedChunks": {
"description": "Also flag chunks as loaded which contain a subset of the modules.",
"type": "boolean"
},
"innerGraph": {
"description": "Creates a module-internal dependency graph for top level symbols, exports and imports, to improve unused exports detection.",
"type": "boolean"
},
"mangleExports": {
"description": "Rename exports when possible to generate shorter code (depends on optimization.usedExports and optimization.providedExports, true/\"deterministic\": generate short deterministic names optimized for caching, \"size\": generate the shortest possible names).",
"anyOf": [
{
"enum": ["size", "deterministic"]
},
{
"type": "boolean"
}
]
},
"mangleWasmImports": {
"description": "Reduce size of WASM by changing imports to shorter strings.",
"type": "boolean"
},
"mergeDuplicateChunks": {
"description": "Merge chunks which contain the same modules.",
"type": "boolean"
},
"minimize": {
"description": "Enable minimizing the output. Uses optimization.minimizer.",
"type": "boolean"
},
"minimizer": {
"description": "Minimizer(s) to use for minimizing the output.",
"type": "array",
"cli": {
"exclude": true
},
"items": {
"description": "Plugin of type object or instanceof Function.",
"anyOf": [
{
"enum": ["..."]
},
{
"$ref": "#/definitions/Falsy"
},
{
"$ref": "#/definitions/WebpackPluginInstance"
},
{
"$ref": "#/definitions/WebpackPluginFunction"
}
]
}
},
"moduleIds": {
"description": "Define the algorithm to choose module ids (natural: numeric ids in order of usage, named: readable ids for better debugging, hashed: (deprecated) short hashes as ids for better long term caching, deterministic: numeric hash ids for better long term caching, size: numeric ids focused on minimal initial download size, false: no algorithm used, as custom one can be provided via plugin).",
"enum": ["natural", "named", "hashed", "deterministic", "size", false]
},
"noEmitOnErrors": {
"description": "Avoid emitting assets when errors occur (deprecated: use 'emitOnErrors' instead).",
"type": "boolean",
"cli": {
"exclude": true
}
},
"nodeEnv": {
"description": "Set process.env.NODE_ENV to a specific value.",
"anyOf": [
{
"enum": [false]
},
{
"type": "string"
}
]
},
"portableRecords": {
"description": "Generate records with relative paths to be able to move the context folder.",
"type": "boolean"
},
"providedExports": {
"description": "Figure out which exports are provided by modules to generate more efficient code.",
"type": "boolean"
},
"realContentHash": {
"description": "Use real [contenthash] based on final content of the assets.",
"type": "boolean"
},
"removeAvailableModules": {
"description": "Removes modules from chunks when these modules are already included in all parents.",
"type": "boolean"
},
"removeEmptyChunks": {
"description": "Remove chunks which are empty.",
"type": "boolean"
},
"runtimeChunk": {
"$ref": "#/definitions/OptimizationRuntimeChunkNormalized"
},
"sideEffects": {
"description": "Skip over modules which contain no side effects when exports are not used (false: disabled, 'flag': only use manually placed side effects flag, true: also analyse source code for side effects).",
"anyOf": [
{
"enum": ["flag"]
},
{
"type": "boolean"
}
]
},
"splitChunks": {
"description": "Optimize duplication and caching by splitting chunks by shared modules and cache group.",
"anyOf": [
{
"enum": [false]
},
{
"$ref": "#/definitions/OptimizationSplitChunksOptions"
}
]
},
"usedExports": {
"description": "Figure out which exports are used by modules to mangle export names, omit unused exports and generate more efficient code (true: analyse used exports for each runtime, \"global\": analyse exports globally for all runtimes combined).",
"anyOf": [
{
"enum": ["global"]
},
{
"type": "boolean"
}
]
}
}
},
"OptimizationRuntimeChunk": {
"description": "Create an additional chunk which contains only the webpack runtime and chunk hash maps.",
"anyOf": [
@ -2805,7 +3020,7 @@
},
{
"instanceof": "Function",
"tsType": "Function"
"tsType": "import('../lib/optimize/RuntimeChunkPlugin').RuntimeChunkFunction"
}
]
}
@ -2826,7 +3041,7 @@
"name": {
"description": "The name factory for the runtime chunks.",
"instanceof": "Function",
"tsType": "Function"
"tsType": "import('../lib/optimize/RuntimeChunkPlugin').RuntimeChunkFunction"
}
}
}
@ -3060,8 +3275,7 @@
"type": "string"
},
{
"instanceof": "Function",
"tsType": "Function"
"$ref": "#/definitions/OptimizationSplitChunksGetCacheGroups"
},
{
"$ref": "#/definitions/OptimizationSplitChunksCacheGroup"
@ -3084,8 +3298,7 @@
"type": "string"
},
{
"instanceof": "Function",
"tsType": "Function"
"$ref": "#/definitions/OptimizationSplitChunksGetCacheGroups"
}
]
}
@ -3754,6 +3967,9 @@
},
"javascript/esm": {
"$ref": "#/definitions/JavascriptParserOptions"
},
"json": {
"$ref": "#/definitions/JsonParserOptions"
}
}
},
@ -3792,7 +4008,7 @@
"assetFilter": {
"description": "Filter function to select assets that are checked.",
"instanceof": "Function",
"tsType": "Function"
"tsType": "((name: import('../lib/Compilation').Asset['name'], source: import('../lib/Compilation').Asset['source'], assetInfo: import('../lib/Compilation').Asset['info']) => boolean)"
},
"hints": {
"description": "Sets the format of the hints: warnings, errors or nothing at all.",
@ -4700,14 +4916,18 @@
}
},
{
"instanceof": "Function",
"tsType": "((data: { resource: string, realResource: string, resourceQuery: string, issuer: string, compiler: string }) => (Falsy | RuleSetUseItem)[])"
"$ref": "#/definitions/RuleSetUseFunction"
},
{
"$ref": "#/definitions/RuleSetUseItem"
}
]
},
"RuleSetUseFunction": {
"description": "The function is called on each data and return rule set item.",
"instanceof": "Function",
"tsType": "((data: import('../lib/rules/RuleSetCompiler').EffectData) => (RuleSetUseItem | (Falsy | RuleSetUseItem)[]))"
},
"RuleSetUseItem": {
"description": "A description of an applied loader.",
"anyOf": [
@ -4738,8 +4958,7 @@
}
},
{
"instanceof": "Function",
"tsType": "((data: object) => RuleSetUseItem | (Falsy | RuleSetUseItem)[])"
"$ref": "#/definitions/RuleSetUseFunction"
},
{
"$ref": "#/definitions/RuleSetLoader"
@ -5613,7 +5832,7 @@
"$ref": "#/definitions/Node"
},
"optimization": {
"$ref": "#/definitions/Optimization"
"$ref": "#/definitions/OptimizationNormalized"
},
"output": {
"$ref": "#/definitions/OutputNormalized"

View File

@ -1,7 +0,0 @@
/*
* This file was automatically generated.
* DO NOT MODIFY BY HAND.
* Run `yarn special-lint-fix` to update
*/
declare const check: (options: import("../../declarations/plugins/JsonModulesPluginGenerator").JsonModulesPluginGeneratorOptions) => boolean;
export = check;

View File

@ -1,11 +0,0 @@
{
"title": "JsonModulesPluginGeneratorOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"JSONParse": {
"description": "Use `JSON.parse` when the JSON string is longer than 20 characters.",
"type": "boolean"
}
}
}

View File

@ -1,7 +0,0 @@
/*
* This file was automatically generated.
* DO NOT MODIFY BY HAND.
* Run `yarn special-lint-fix` to update
*/
declare const check: (options: import("../../declarations/plugins/JsonModulesPluginParser").JsonModulesPluginParserOptions) => boolean;
export = check;

View File

@ -1,16 +0,0 @@
{
"title": "JsonModulesPluginParserOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"exportsDepth": {
"description": "The depth of json dependency flagged as `exportInfo`.",
"type": "number"
},
"parse": {
"description": "Function that executes for a module source string and should return json-compatible data.",
"instanceof": "Function",
"tsType": "((input: string) => any)"
}
}
}

View File

@ -0,0 +1,7 @@
/*
* This file was automatically generated.
* DO NOT MODIFY BY HAND.
* Run `yarn special-lint-fix` to update
*/
declare const check: (options: any) => boolean;
export = check;

View File

@ -0,0 +1,3 @@
{
"$ref": "../../WebpackOptions.json#/definitions/JsonGeneratorOptions"
}

View File

@ -0,0 +1,7 @@
/*
* This file was automatically generated.
* DO NOT MODIFY BY HAND.
* Run `yarn special-lint-fix` to update
*/
declare const check: (options: any) => boolean;
export = check;

View File

@ -0,0 +1,3 @@
{
"$ref": "../../WebpackOptions.json#/definitions/JsonParserOptions"
}

View File

@ -4494,6 +4494,19 @@ Object {
"multiple": false,
"simpleType": "string",
},
"module-parser-json-exports-depth": Object {
"configs": Array [
Object {
"description": "The depth of json dependency flagged as \`exportInfo\`.",
"multiple": false,
"path": "module.parser.json.exportsDepth",
"type": "number",
},
],
"description": "The depth of json dependency flagged as \`exportInfo\`.",
"multiple": false,
"simpleType": "number",
},
"module-rules-compiler": Object {
"configs": Array [
Object {

View File

@ -1,4 +1,4 @@
/** @type {import("../../../../").LoaderDefinitionFunction} */
/** @type {import("../../../../").LoaderDefinition} */
exports.default = function (source) {
const ref = JSON.parse(source);
const callback = this.async();

View File

@ -1,4 +1,4 @@
/** @type {import("../../../../").LoaderDefinitionFunction} */
/** @type {import("../../../../").LoaderDefinition} */
exports.default = function (source) {
const ref = JSON.parse(source);
const callback = this.async();
@ -6,7 +6,7 @@ exports.default = function (source) {
if (err) {
callback(null, JSON.stringify(`err: ${err && err.message}`));
} else {
callback(null, JSON.stringify(`source: ${JSON.parse(source)}`));
callback(null, JSON.stringify(`source: ${JSON.parse(/** @type {string} */ (source))}`));
}
});
};

View File

@ -1,4 +1,4 @@
/** @type {import("../../../../").LoaderDefinitionFunction} */
/** @type {import("../../../../").LoaderDefinition} */
exports.default = function (source) {
const callback = this.async();
const ref = JSON.parse(source);
@ -6,7 +6,7 @@ exports.default = function (source) {
if (err) {
callback(err);
} else {
callback(null, JSON.stringify(`source: ${JSON.parse(source)}`));
callback(null, JSON.stringify(`source: ${JSON.parse(/** @type {string} */ (source))}`));
}
});
};

View File

@ -5,6 +5,7 @@ const acornParser = acorn.Parser;
/** @type {import("../../../../").LoaderDefinition} */
module.exports = function (source) {
/** @type {TODO} */
const comments = [];
const semicolons = new Set();

View File

@ -5,6 +5,7 @@ const Source = require("webpack-sources").Source;
module.exports = {
plugins: [
compiler => {
/** @type {Record<string, boolean>} */
const files = {};
compiler.hooks.assetEmitted.tap(
"Test",

View File

@ -2,7 +2,8 @@
module.exports = {
mode: "development",
output: {
assetModuleFilename: ({ filename }) => {
assetModuleFilename: ({ filename: _filename }) => {
const filename = /** @type {string} */ (_filename);
if (/.png$/.test(filename)) {
return "images/[\\ext\\]/success-png[ext]";
}

View File

@ -1,6 +1,8 @@
const path = require("path");
const NormalModule = require("../../../../").NormalModule;
/** @typedef {import("../../../../").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "development",
@ -9,6 +11,7 @@ module.exports = {
{
test: /\.png$/,
type: "asset",
/** @type {ParserOptionsByModuleTypeKnown['asset']} */
parser: {
dataUrlCondition: (source, { filename, module }) => {
expect(source).toBeInstanceOf(Buffer);
@ -23,6 +26,7 @@ module.exports = {
{
test: /\.jpg$/,
type: "asset",
/** @type {ParserOptionsByModuleTypeKnown['asset']} */
parser: {
dataUrlCondition: (source, { filename, module }) => {
expect(source).toBeInstanceOf(Buffer);

View File

@ -2,6 +2,7 @@ const path = require("path");
const fs = require("fs");
const webpack = require("../../../../");
/** @type {import("../../../../").Configuration} */
const common = {
module: {
rules: [
@ -46,6 +47,10 @@ const common = {
}
};
/**
* @param {number} i index
* @returns {import("../../../../").Configuration | undefined} configuration
*/
const entry = i => {
switch (i % 4) {
case 0:
@ -80,6 +85,10 @@ const entry = i => {
}
};
/**
* @param {number} i index
* @returns {import("../../../../").Configuration} configuration
*/
const esm = i => ({
...common,
...entry(i),
@ -97,6 +106,10 @@ const esm = i => ({
}
});
/**
* @param {number} i index
* @returns {import("../../../../").Configuration} configuration
*/
const node = i => ({
...common,
...entry(i),
@ -110,6 +123,10 @@ const node = i => ({
target: "node"
});
/**
* @param {number} i index
* @returns {import("../../../../").Configuration} configuration
*/
const web = i => ({
...common,
...entry(i),

View File

@ -13,7 +13,10 @@ module.exports = {
generator: {
asset: {
dataUrl: (source, { module }) => {
const mimeType = mimeTypes.lookup(module.nameForCondition());
const mimeType = mimeTypes.lookup(
/** @type {string} */
(module.nameForCondition())
);
if (mimeType === "image/svg+xml") {
if (typeof source !== "string") {
source = source.toString();

View File

@ -1 +1,2 @@
/** @type {import("../../../../../").LoaderDefinition} */
module.exports = content => `export default ${JSON.stringify(content + ".webpack{}")}`;

View File

@ -1 +1,2 @@
/** @type {import("../../../../../").LoaderDefinition} */
module.exports = content => `export default ${JSON.stringify(content)}`;

View File

@ -2,14 +2,16 @@ const http = require("http");
const fs = require("fs");
const path = require("path");
/** @typedef {import("../../../../../").Compiler} Compiler */
/**
* @returns {import("http").Server} server instance
*/
function createServer() {
const server = http.createServer((req, res) => {
let file;
const pathname = "." + req.url.replace(/\?.*$/, "");
if (req.url.endsWith("?no-cache")) {
const pathname = "." + /** @type {string} */ (req.url).replace(/\?.*$/, "");
if (/** @type {string} */ (req.url).endsWith("?no-cache")) {
res.setHeader("Cache-Control", "no-cache, max-age=60");
} else {
res.setHeader("Cache-Control", "public, immutable, max-age=600");
@ -52,23 +54,28 @@ class ServerPlugin {
}
/**
* @param {import("../../../../../").Compiler} compiler
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.beforeRun.tapPromise(
"ServerPlugin",
async (compiler, callback) => {
async () => {
this.refs++;
if (!this.server) {
this.server = createServer();
await new Promise((resolve, reject) => {
this.server.listen(this.port, err => {
if (err) {
reject(err);
} else {
await new Promise(
/**
* @param {(value: void) => void} resolve resolve
* @param {(reason?: Error) => void} _reject reject
*/
(resolve, _reject) => {
/** @type {import("http").Server} */
(this.server).listen(
this.port,
() => {
resolve();
}
});
);
});
}
}

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").GeneratorOptionsByModuleTypeKnown} GeneratorOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration} */
module.exports = {
node: {
@ -18,9 +20,12 @@ module.exports = {
{
test: /\.scss$/i,
type: "asset/resource",
/** @type {GeneratorOptionsByModuleTypeKnown['asset/resource']} */
generator: {
binary: false,
filename: pathInfo => pathInfo.filename.replace(/\.scss/gi, ".css")
filename: pathInfo =>
/** @type {string} */
(pathInfo.filename).replace(/\.scss/gi, ".css")
},
use: ["./loader.js"]
}

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "development",
@ -6,6 +8,7 @@ module.exports = {
{
test: /\.(png|svg|jpg)$/,
type: "asset",
/** @type {ParserOptionsByModuleTypeKnown['asset']} */
parser: {
dataUrlCondition: (source, { filename, module }) =>
filename.includes("?foo=bar")

View File

@ -1,6 +1,8 @@
const svgToMiniDataURI = require("mini-svg-data-uri");
const mimeTypes = require("mime-types");
/** @typedef {import("../../../../").GeneratorOptionsByModuleTypeKnown} GeneratorOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "development",
@ -9,6 +11,7 @@ module.exports = {
{
test: /\.(png|svg|jpg)$/,
type: "asset/inline",
/** @type {GeneratorOptionsByModuleTypeKnown["asset/inline"]} */
generator: {
dataUrl: (source, { filename, module }) => {
if (filename.endsWith("?foo=bar")) {
@ -19,7 +22,10 @@ module.exports = {
return svgToMiniDataURI(source);
}
const mimeType = mimeTypes.lookup(module.nameForCondition());
const mimeType = mimeTypes.lookup(
/** @type {string} */
(module.nameForCondition())
);
const encodedContent = source.toString("base64");
return `data:${mimeType};base64,${encodedContent}`;

View File

@ -1,8 +1,5 @@
const path = require("path");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../types").Configuration} */
module.exports = (env, { testPath }) => ({
target: "node14",

View File

@ -1,5 +1,8 @@
"use strict";
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").FileCacheOptions} FileCacheOptions */
// with explicit cache names
/** @type {import("../../../../").Configuration} */
@ -13,13 +16,18 @@ module.exports = [
},
plugins: [
{
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.environment.tap("FixTestCachePlugin", () => {
compiler.options.cache.cacheLocation =
compiler.options.cache.cacheLocation.replace(
/filesystem$/,
"filesystem-extra-1"
);
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation =
/** @type {string} */
(
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation
).replace(/filesystem$/, "filesystem-extra-1");
});
}
}
@ -34,13 +42,18 @@ module.exports = [
},
plugins: [
{
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.environment.tap("FixTestCachePlugin", () => {
compiler.options.cache.cacheLocation =
compiler.options.cache.cacheLocation.replace(
/filesystem$/,
"filesystem-extra-2"
);
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation =
/** @type {string} */
(
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation
).replace(/filesystem$/, "filesystem-extra-2");
});
}
}

View File

@ -2,7 +2,11 @@
// with explicit cache names
/** @type {import("../../../../").Configuration} */
/** @typedef {import("../../../../").Configuration} Configuration */
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").FileCacheOptions} FileCacheOptions */
/** @type {Configuration} */
module.exports = [
{
mode: "production",
@ -13,13 +17,18 @@ module.exports = [
},
plugins: [
{
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.environment.tap("FixTestCachePlugin", () => {
compiler.options.cache.cacheLocation =
compiler.options.cache.cacheLocation.replace(
/default$/,
"default-extra"
);
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation =
/** @type {string} */
(
/** @type {FileCacheOptions} */
(compiler.options.cache).cacheLocation
).replace(/default$/, "default-extra");
});
}
}

View File

@ -20,6 +20,7 @@ module.exports = {
*/
const handler = compilation => {
compilation.hooks.afterSeal.tap("testcase", () => {
/** @type {Record<string, string>} */
const data = {};
for (const [name, group] of compilation.namedChunkGroups) {
/** @type {Map<Module, number>} */

View File

@ -22,6 +22,7 @@ module.exports = {
const handler = compilation => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.afterSeal.tap("testcase", () => {
/** @type {Record<string, string>} */
const data = {};
for (const [name, group] of compilation.namedChunkGroups) {
/** @type {Map<Module, number>} */

View File

@ -16,6 +16,7 @@ module.exports = {
*/
const handler = compilation => {
compilation.hooks.afterSeal.tap("testcase", () => {
/** @type {Record<string, string>} */
const data = {};
for (const [name, group] of compilation.namedChunkGroups) {
/** @type {Map<Module, number>} */

View File

@ -1,12 +1,22 @@
const fs = require('fs');
const path = require('path');
/**
* @param {string} path path
* @returns {string} path
*/
function handlePath(path) {
return path.replace(/\\/g, "/");
}
/**
* @param {string} from from
* @returns {{ files: string[], directories: string[] }}
*/
module.exports = function readDir(from) {
/** @type {string[]} */
const collectedFiles = [];
/** @type {string[]} */
const collectedDirectories = [];
const stack = [from];
let cursor;

View File

@ -1,12 +1,22 @@
const fs = require('fs');
const path = require('path');
/**
* @param {string} path path
* @returns {string} path
*/
function handlePath(path) {
return path.replace(/\\/g, "/");
}
/**
* @param {string} from from
* @returns {{ files: string[], directories: string[] }}
*/
module.exports = function readDir(from) {
/** @type {string[]} */
const collectedFiles = [];
/** @type {string[]} */
const collectedDirectories = [];
const stack = [from];
let cursor;

View File

@ -12,7 +12,9 @@ module.exports = {
let once = true;
compiler.hooks.environment.tap("Test", () => {
if (once) {
const outputPath = compiler.options.output.path;
const outputPath =
/** @type {string} */
(compiler.options.output.path);
const originalPath = path.join(outputPath, "file.ext");
fs.writeFileSync(originalPath, "");
const customDir = path.join(outputPath, "this/dir/should/be/removed");

View File

@ -1,4 +1,4 @@
/** @type {import("../../../../").LoaderDefinitionFunction} */
/** @type {import("../../../../").LoaderDefinition} */
module.exports = function () {
const callback = this.async();
this.importModule("./module1", { baseUri: "webpack://" }, (err, exports) => {

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
const common = {
target: "web",
optimization: {
@ -8,6 +9,8 @@ const common = {
}
};
/** @typedef {import("../../../../").GeneratorOptionsByModuleTypeKnown} GeneratorOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration[]} */
module.exports = [
{
@ -76,6 +79,7 @@ module.exports = [
{
test: /\.css$/,
type: "css/module",
/** @type {GeneratorOptionsByModuleTypeKnown["css/module"]} */
generator: {
exportsConvention: name => name.toUpperCase()
}

View File

@ -1,9 +1,6 @@
const webpack = require("../../../../");
const path = require("path");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration} */
module.exports = (env, { testPath }) => ({
target: "web",

View File

@ -1,9 +1,6 @@
const path = require("path");
const webpack = require("../../../../");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{

View File

@ -1,6 +1,3 @@
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration} */
module.exports = (env, { testPath }) => ({
target: "web",

View File

@ -1,9 +1,6 @@
const webpack = require("../../../../");
const path = require("path");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{

View File

@ -1,5 +1,7 @@
const webpack = require("../../../../");
/** @typedef {import("../../../../").GeneratorOptionsByModuleTypeKnown} GeneratorOptionsByModuleTypeKnown */
const common = {
optimization: {
chunkIds: "named"
@ -42,6 +44,7 @@ const common = {
},
{
resourceQuery: /\?upper$/,
/** @type {GeneratorOptionsByModuleTypeKnown["css/module"]} */
generator: {
exportsConvention: name => name.toUpperCase()
}

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").LoaderDefinition} */
module.exports = function loader(content) {
return content + `.using-loader { color: red; }`;
};

View File

@ -2,6 +2,10 @@ const path = require("path");
const fs = require("fs");
const webpack = require("../../../../");
/**
* @param {0 | 1 | 2} i index
* @returns {{ main: string[] }} entry
*/
const entry = i => {
switch (i) {
case 0:
@ -20,7 +24,7 @@ const entry = i => {
};
/**
* @param {number} i param
* @param {0 | 1 | 2} i param
* @returns {import("../../../../").Configuration} return
*/
const common = i => ({
@ -66,4 +70,4 @@ const common = i => ({
});
/** @type {import("../../../../").Configuration[]} */
module.exports = [...[0, 1].map(i => common(i))];
module.exports = [.../** @type {(0 | 1 | 2)[]} */ ([0, 1]).map(i => common(i))];

View File

@ -1,5 +1,7 @@
const toml = require("toml");
/** @typedef {import("../../../../").ParserOptionsByModuleTypeKnown} ParserOptionsByModuleTypeKnown */
/** @type {import("../../../../").Configuration[]} */
module.exports = [
{
@ -9,6 +11,7 @@ module.exports = [
{
test: /\.toml$/,
type: "json",
/** @type {ParserOptionsByModuleTypeKnown['json']} */
parser: {
parse(input) {
expect(arguments.length).toBe(1);

View File

@ -8,6 +8,7 @@ const webpack = require("../../../../");
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").ParserState} ParserState */
/** @typedef {import("../../../../lib/Parser").PreparsedAst} PreparsedAst */
/** @typedef {import("../../../../").Module} Module */
class LocalizationParser extends Parser {
/**
@ -18,22 +19,28 @@ class LocalizationParser extends Parser {
parse(source, state) {
if (typeof source !== "string") throw new Error("Unexpected input");
const { module } = state;
module.buildInfo.content = JSON.parse(source);
/** @type {NonNullable<Module["buildInfo"]>} */
(module.buildInfo).content = JSON.parse(source);
return state;
}
}
const TYPES = new Set(["localization"]);
/**
* @extends {Generator}
*/
class LocalizationGenerator extends Generator {
getTypes() {
return TYPES;
}
/** @type {Generator["getSize"]} */
getSize(module, type) {
return 42;
}
/** @type {Generator["generate"]} */
generate(module, { type }) {
return null;
}
@ -62,6 +69,9 @@ ${RuntimeGlobals.ensureChunkHandlers}.localization = (chunkId, promises) => {
}
}
/**
* @type {{ TARGET: string, CONTENT2: boolean, NORMAL1: boolean, NORMAL2: boolean }[]}
*/
const definitions = ["node", "async-node", "web"].reduce(
(arr, target) =>
arr.concat([
@ -102,7 +112,8 @@ const definitions = ["node", "async-node", "web"].reduce(
NORMAL2: false
}
]),
[]
/** @type {{ TARGET: string, CONTENT2: boolean, NORMAL1: boolean, NORMAL2: boolean }[]} */
([])
);
module.exports = definitions.map((defs, i) => ({
@ -136,6 +147,7 @@ module.exports = definitions.map((defs, i) => ({
compilation.chunkTemplate.hooks.renderManifest.tap(
"LocalizationPlugin",
(result, { chunk, chunkGraph }) => {
/** @type {Module[]} */
const localizationModules = [];
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
if (module.getSourceTypes().has("localization"))
@ -144,10 +156,15 @@ module.exports = definitions.map((defs, i) => ({
result.push({
render: () => {
/** @type {Record<number | string, string>} */
const data = {};
for (const module of localizationModules) {
data[chunkGraph.getModuleId(module)] =
module.buildInfo.content;
data[
/** @type {number | string} */
(chunkGraph.getModuleId(module))
] =
/** @type {NonNullable<Module["buildInfo"]>} */
(module.buildInfo).content;
}
return new RawSource(
`module.exports = ${JSON.stringify(data)}`

View File

@ -1,4 +1,5 @@
/** @typedef {import("../../../../").Compilation} Compilation */
/** @typedef {import("../../../../").Module} Module */
/** @type {import("../../../../").Configuration} */
module.exports = {
@ -19,7 +20,9 @@ module.exports = {
compilation.hooks.dependencyReferencedExports.tap(
"Test",
(referencedExports, dep) => {
const module = compilation.moduleGraph.getParentModule(dep);
const module =
/** @type {Module} */
(compilation.moduleGraph.getParentModule(dep));
if (!module.identifier().endsWith("module.js"))
return referencedExports;
const refModule = compilation.moduleGraph.getModule(dep);
@ -36,7 +39,8 @@ module.exports = {
return referencedExports.filter(
names =>
(Array.isArray(names) && names.length !== 1) ||
names[0] !== "unused"
/** @type {string[]} */
(names)[0] !== "unused"
);
}
return referencedExports;

View File

@ -1,4 +1,5 @@
/** @typedef {import("../../../../").Compilation} Compilation */
/** @typedef {import("../../../../").Module} Module */
/** @type {import("../../../../").Configuration} */
module.exports = {
@ -13,7 +14,9 @@ module.exports = {
compilation.hooks.dependencyReferencedExports.tap(
"Test",
(referencedExports, dep) => {
const module = compilation.moduleGraph.getParentModule(dep);
const module =
/** @type {Module} */
(compilation.moduleGraph.getParentModule(dep));
if (!module.identifier().endsWith("module.js"))
return referencedExports;
const refModule = compilation.moduleGraph.getModule(dep);
@ -30,7 +33,8 @@ module.exports = {
return referencedExports.filter(
names =>
(Array.isArray(names) && names.length !== 1) ||
names[0] !== "unused"
/** @type {string[]} */
(names)[0] !== "unused"
);
}
return referencedExports;

View File

@ -1,4 +1,7 @@
const { ChunkGraph, ExternalModule } = require("../../../../");
/** @typedef {import("../../../../").Module} Module */
/** @type {import("../../../../").Configuration} */
module.exports = {
plugins: [
@ -57,7 +60,9 @@ module.exports = {
m.issuer = module;
expect(m.issuer).toBe(module);
expect(
typeof m.usedExports === "boolean" ? [] : [...m.usedExports]
typeof m.usedExports === "boolean"
? []
: [.../** @type {Set<string>} */ (m.usedExports)]
).toEqual(["testExport"]);
expect(Array.isArray(m.optimizationBailout)).toBe(true);
expect(m.optional).toBe(false);

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Chunk} Chunk */
/** @type {import("../../../../").Configuration} */
module.exports = {
entry: {
@ -19,7 +21,8 @@ module.exports = {
const hashes = [];
expect(() => {
for (const module of compilation.chunkGraph.getChunkModulesIterable(
compilation.namedChunks.get("a")
/** @type {Chunk} */
(compilation.namedChunks.get("a"))
)) {
hashes.push(module.hash);
}

View File

@ -1,6 +1,7 @@
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").Compilation} Compilation */
/** @typedef {import("../../../../").Configuration} Configuration */
/** @typedef {import("../../../../").Chunk} Chunk */
/** @type {Configuration} */
/** @type {import("../../../../").Configuration} */
@ -34,12 +35,19 @@ module.exports = {
const handler = compilation => {
compilation.hooks.afterSeal.tap("testcase", () => {
const { chunkGraph } = compilation;
/** @type {Record<string, Set<string>>} */
const chunkModules = {};
for (const chunk of compilation.chunks) {
chunkModules[chunk.name] = new Set();
chunkModules[
/** @type {NonNullable<Chunk["name"]>} */
(chunk.name)
] = new Set();
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
chunkModules[chunk.name].add(module.identifier());
chunkModules[
/** @type {NonNullable<Chunk["name"]>} */
(chunk.name)
].add(module.identifier());
}
}

View File

@ -1,5 +1,7 @@
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").Compilation} Compilation */
/** @typedef {import("../../../../").Chunk} Chunk */
/** @typedef {import("../../../../").Module} Module */
/** @type {import("../../../../").Configuration} */
module.exports = {
@ -23,12 +25,19 @@ module.exports = {
const handler = compilation => {
compilation.hooks.afterSeal.tap("testcase", () => {
const { chunkGraph } = compilation;
/** @type {Record<string, Set<Module>>} */
const chunkModules = {};
for (const chunk of compilation.chunks) {
chunkModules[chunk.name] = new Set();
chunkModules[
/** @type {NonNullable<Chunk["name"]>} */
(chunk.name)
] = new Set();
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
chunkModules[chunk.name].add(module);
chunkModules[
/** @type {NonNullable<Chunk["name"]>} */
(chunk.name)
].add(module);
}
}

View File

@ -1,4 +1,9 @@
/** @typedef {import("../../../../").Compiler} Compiler */
class ThrowsExceptionInRender {
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap("ThrowsException", compilation => {
compilation.mainTemplate.hooks.requireExtensions.tap(

View File

@ -1,26 +1,37 @@
/** @typedef {import("enhanced-resolve").ResolveRequest} ResolveRequest */
/** @typedef {import("../../../../").ExternalItemFunctionData} ExternalItemFunctionData */
/** @type {import("../../../../").Configuration} */
module.exports = {
optimization: {
concatenateModules: true
},
externals: [
({ context, request, getResolve }, callback) => {
({ context: _context, request, getResolve }, callback) => {
if (request !== "external" && request !== "external-false") {
return callback(null, false);
}
const resolve = getResolve({
const context = /** @type {string} */ (_context);
const resolve =
/** @type {ReturnType<NonNullable<ExternalItemFunctionData["getResolve"]>>} */ (
/** @type {NonNullable<ExternalItemFunctionData["getResolve"]>} */
(getResolve)({
alias: {
"external-false": false
}
});
})
);
if (request === "external-false") {
resolve(context, request, callback);
} else {
resolve(context, request, (err, resolved, resolveRequest) => {
if (err) callback(err);
else if (resolved !== resolveRequest.path)
else if (
resolved !== /** @type {ResolveRequest} */ (resolveRequest).path
)
callback(new Error("Error"));
else callback(null, `var ${JSON.stringify(resolved)}`);
});

View File

@ -1,16 +1,27 @@
/** @typedef {import("../../../../").ExternalItemFunctionData} ExternalItemFunctionData */
/** @typedef {import("../../../../").ExternalItemFunctionPromise} ExternalItemFunctionPromise */
/** @typedef {import("../../../../").ExternalItemFunctionDataGetResolve} ExternalItemFunctionDataGetResolve */
/** @typedef {import("../../../../").ExternalItemFunctionDataGetResolveResult} ExternalItemFunctionDataGetResolveResult */
/** @type {import("../../../../").Configuration} */
module.exports = {
optimization: {
concatenateModules: true
},
externals: [
/** @type {ExternalItemFunctionPromise} */
async ({ context, request, getResolve }) => {
if (request !== "external" && request !== "external-promise") {
return false;
}
const resolve = getResolve();
const resolved = await resolve(context, request);
const resolve =
/** @type {ExternalItemFunctionDataGetResolveResult} */
(
/** @type {ExternalItemFunctionDataGetResolve} */
(getResolve)()
);
const resolved = await resolve(/** @type {string} */ (context), request);
return `var ${JSON.stringify(resolved)}`;
}
]

View File

@ -1,3 +1,6 @@
/** @typedef {import("../../../../").Chunk & { name: string }} Chunk */
/** @typedef {import("../../../../").PathData & { chunk: Chunk }} PathData */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "development",
@ -5,12 +8,24 @@ module.exports = {
a: "./a",
b: {
import: "./b",
/**
* @param {PathData} data data
* @returns {string} filename
*/
filename: data =>
`${data.chunk.name + data.chunk.name + data.chunk.name}.js`
}
},
output: {
/**
* @param {PathData} data data
* @returns {string} filename
*/
filename: data => `${data.chunk.name + data.chunk.name}.js`,
/**
* @param {PathData} data data
* @returns {string} filename
*/
chunkFilename: data => `${data.chunk.name + data.chunk.name}.js`
}
};

View File

@ -1,18 +1,17 @@
/**
* Escapes regular expression metacharacters
* @param {string} str String to quote
* @returns {string} Escaped string
*/
const quotemeta = str => {
return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
};
/** @typedef {import("../../../../").Configuration} Configuration */
/**
* @param {Record<string, { name?: string, usedExports: string[], expect: Record<string, string[]> }>} testCases
* @returns {Configuration[]} configurations
*/
module.exports = testCases => {
/** @type {Configuration[]} */
const configs = [];
for (const name of Object.keys(testCases)) {
const testCase = testCases[name];
testCase.name = name;
const entry = `../_helpers/entryLoader.js?${JSON.stringify(testCase)}!`;
/** @type {{ alias: Record<string, string> }} */
const resolve = {
alias: {}
};

View File

@ -1,12 +1,4 @@
const matchAll = (str, regexp) => {
const matches = [];
let match;
while ((match = regexp.exec(str)) !== null) {
matches.push(match);
}
return matches;
};
/** @type {import("../../../../").LoaderDefinition} */
module.exports = source => {
return [
source,

View File

@ -1,4 +1,5 @@
const createTestCases = require("../_helpers/createTestCases");
module.exports = createTestCases({
nothing: {
usedExports: [],

View File

@ -0,0 +1,7 @@
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z

View File

@ -0,0 +1,13 @@
import toml from "./data.toml";
it("should transform toml to json", () => {
expect(toml).toMatchObject({
title: "TOML Example",
owner: {
name: 'Tom Preston-Werner',
organization: 'GitHub',
bio: 'GitHub Cofounder & CEO\nLikes tater tots and beer.',
dob: '1979-05-27T07:32:00.000Z'
}
});
});

View File

@ -0,0 +1,24 @@
const toml = require("toml");
/** @type {import("../../../../").Configuration[]} */
module.exports = [
{
mode: "development",
module: {
parser: {
json: {
parse(input) {
expect(arguments.length).toBe(1);
return toml.parse(input);
}
}
},
rules: [
{
test: /\.toml$/,
type: "json"
}
]
}
}
];

View File

@ -2,9 +2,6 @@ const path = require("path");
const webpack = require("../../../../");
const supportsAsync = require("../../../helpers/supportsAsync");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{

View File

@ -5,9 +5,6 @@ const webpack = require("../../../../");
const path = require("path");
const supportsAsync = require("../../../helpers/supportsAsync");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{

View File

@ -1,11 +1,15 @@
/** @type {import("../../../../").LoaderDefinitionFunction} */
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").Compilation} Compilation */
/** @type {import("../../../../").LoaderDefinition} */
module.exports = async function loader() {
const callback = this.async();
const loader = this;
const compilerName = `extract:${loader.resourcePath}`;
const compiler = loader._compiler;
const compiler = /** @type {Compiler} */ (loader._compiler);
const compilation = /** @type {Compilation} */ (loader._compilation);
const filename = "*";
const childCompiler = loader._compilation.createChildCompiler(
const childCompiler = compilation.createChildCompiler(
compilerName,
{
filename,
@ -24,7 +28,7 @@ module.exports = async function loader() {
library: {
EnableLibraryPlugin
}
} = loader._compiler.webpack;
} = compiler.webpack;
new EnableLibraryPlugin('commonjs2').apply(childCompiler);
@ -59,12 +63,19 @@ module.exports = async function loader() {
});
try {
await new Promise((resolve, reject) => {
childCompiler.runAsChild((err, _entries, compilation) => {
await new Promise(
/**
* @param {(value?: void) => void} resolve resolve
* @param {(reason?: Error) => void} reject
*/
(resolve, reject) => {
childCompiler.runAsChild((err, _entries, _compilation) => {
if (err) {
return reject(err);
}
const compilation = /** @type {Compilation} */ (_compilation);
if (compilation.errors.length > 0) {
return reject(compilation.errors[0]);
}
@ -73,7 +84,7 @@ module.exports = async function loader() {
});
})
} catch (e) {
callback(e);
callback(/** @type {Error} */ (e));
return;
}

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Compilation} Compilation */
/** @type {import("../../../../types").Configuration} */
module.exports = {
mode: "none",
@ -23,6 +25,9 @@ module.exports = {
},
plugins: [
function () {
/**
* @param {Compilation} compilation compilation
*/
const handler = compilation => {
compilation.hooks.afterProcessAssets.tap("testcase", assets => {
const source = assets["test.js"].source();

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Compilation} Compilation */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "none",
@ -44,6 +46,9 @@ module.exports = {
},
plugins: [
function () {
/**
* @param {Compilation} compilation compilation
*/
const handler = compilation => {
compilation.hooks.afterProcessAssets.tap("testcase", assets => {
const source = assets["bundle0.mjs"].source();

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Chunk} Chunk */
/** @type {import("../../../../").Configuration} */
module.exports = {
output: {
@ -56,7 +58,9 @@ module.exports = {
"info",
expect.objectContaining({ sourceFilename: "file.jpg" })
);
const { auxiliaryFiles } = stats.compilation.namedChunks.get("main");
const { auxiliaryFiles } =
/** @type {Chunk} */
(stats.compilation.namedChunks.get("main"));
expect(auxiliaryFiles).toContain("assets/file.png");
expect(auxiliaryFiles).toContain("assets/file.png?1");
expect(auxiliaryFiles).toContain("assets/file.jpg");

View File

@ -13,11 +13,18 @@ class FailPlugin {
}
class TestChildCompilationPlugin {
constructor(output) {}
constructor() {}
/**
* @param {TODO} compiler compiler
*/
apply(compiler) {
compiler.hooks.make.tapAsync(
"TestChildCompilationFailurePlugin",
/**
* @param {TODO} compilation compilation
* @param {TODO} cb cb
*/
(compilation, cb) => {
const child = compilation.createChildCompiler(
"name",

View File

@ -3,7 +3,12 @@ const { NormalModule } = require("webpack");
const PLUGIN_NAME = "PluginWithLoader";
const loaderPath = require.resolve("./loader.js");
/** @typedef {import("../../../../").Compiler} Compiler */
class PluginWithLoader {
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
NormalModule.getCompilationHooks(compilation).beforeLoaders.tap(

View File

@ -1,4 +1,4 @@
// const { getRuntimeKey } = require("../../../../lib/util/runtime");
/** @typedef {import("webpack-sources").Source} Source */
/** @type {import("../../../../").Configuration} */
module.exports = {
@ -30,7 +30,9 @@ module.exports = {
module,
"main"
);
const source = sources.get("javascript");
const source =
/** @type {Source} */
(sources.get("javascript"));
const file = compilation.getAssetPath("[name].js", {
filename: `${module
.readableIdentifier(compilation.requestShortener)

View File

@ -1,9 +1,6 @@
const path = require("path");
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {import("../../../../").Configuration[]} */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration[]} */
module.exports = (env, { testPath }) => [
{
devtool: false,

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Chunk} Chunk */
/** @type {import("../../../../").Configuration} */
module.exports = {
entry() {
@ -8,6 +10,9 @@ module.exports = {
},
output: {
filename: data =>
data.chunk.name === "a" ? `${data.chunk.name}.js` : "[name].js"
/** @type {Chunk} */
(data.chunk).name === "a"
? `${/** @type {Chunk} */ (data.chunk).name}.js`
: "[name].js"
}
};

View File

@ -1,3 +1,5 @@
/** @typedef {import("../../../../").Chunk} Chunk */
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "none",
@ -18,7 +20,14 @@ module.exports = {
},
output: {
filename: data =>
/^[ac]$/.test(data.chunk.name) ? "inner1/inner2/[name].js" : "[name].js",
/^[ac]$/.test(
/** @type {string} */ (
/** @type {Chunk} */
(data.chunk).name
)
)
? "inner1/inner2/[name].js"
: "[name].js",
assetModuleFilename: "[name][ext]"
},
module: {

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").LoaderDefinition} */
module.exports = function loader(content) {
return `module.exports = ${JSON.stringify(content)}`;
};

View File

@ -1,5 +1,9 @@
const webpack = require("../../../../");
/**
* @param {boolean | undefined} system system
* @returns {import("../../../../").Configuration} configuration
*/
function createConfig(system) {
const systemString = "" + system;
return {

View File

@ -20,6 +20,10 @@ module.exports = {
NEGATIVE_ZER0: -0,
NEGATIVE_NUMBER: -100.25,
POSITIVE_NUMBER: +100.25,
/**
* @param {number} a a
* @returns {number} result
*/
// eslint-disable-next-line object-shorthand
FUNCTION: /* istanbul ignore next */ function (a) {
return a + 1;
@ -29,6 +33,10 @@ module.exports = {
OBJECT: {
SUB: {
UNDEFINED: undefined,
/**
* @param {number} a a
* @returns {number} result
*/
// eslint-disable-next-line object-shorthand
FUNCTION: /* istanbul ignore next */ function (a) {
return a + 1;

View File

@ -1,9 +1,6 @@
const path = require("path");
const LibManifestPlugin = require("../../../../").LibManifestPlugin;
/** @typedef {import("../../../WatchTestCases.template").Env} Env */
/** @typedef {import("../../../WatchTestCases.template").TestOptions} TestOptions */
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration} */
module.exports = (env, { testPath }) => ({
entry: {

View File

@ -1,5 +1,7 @@
const MCEP = require("mini-css-extract-plugin");
/** @typedef {import("../../../../").StatsCompilation} StatsCompilation */
/** @type {(i: number, options?: import("mini-css-extract-plugin").PluginOptions) => import("../../../../").Configuration} */
const config = (i, options) => ({
entry: {
@ -37,9 +39,10 @@ const config = (i, options) => ({
new MCEP(options),
compiler => {
compiler.hooks.done.tap("Test", stats => {
const chunkIds = stats
.toJson({ all: false, chunks: true, ids: true })
.chunks.map(c => c.id)
const chunkIds =
/** @type {NonNullable<StatsCompilation["chunks"]>} */
(stats.toJson({ all: false, chunks: true, ids: true }).chunks)
.map(c => c.id)
.sort();
expect(chunkIds).toEqual([
"a",

View File

@ -2,6 +2,7 @@ const rootPath = "../../../../";
const webpack = require(rootPath);
const path = require("path");
/** @type {(env: Env, options: TestOptions) => import("../../../../").Configuration} */
module.exports = (env, { testPath }) => ({
plugins: [
new webpack.debug.ProfilingPlugin({

View File

@ -1,6 +1,9 @@
const path = require("path");
const webpack = require("../../../../");
const data = require("./data");
/** @typedef {import("../../../../").ProgressPlugin} ProgressPlugin */
/** @type {import("../../../../").Configuration} */
module.exports = {
externals: {
@ -14,7 +17,9 @@ module.exports = {
apply: compiler => {
compiler.hooks.compilation.tap("CustomPlugin", compilation => {
compilation.hooks.optimize.tap("CustomPlugin", () => {
const reportProgress = webpack.ProgressPlugin.getReporter(compiler);
const reportProgress =
/** @type {NonNullable<ReturnType<typeof webpack.ProgressPlugin['getReporter']>>} */
(webpack.ProgressPlugin.getReporter(compiler));
reportProgress(0, "custom category", "custom message");
});
});

View File

@ -5,11 +5,22 @@ const {
optimize: { RealContentHashPlugin }
} = require("../../../../");
/** @typedef {import("../../../../").Compiler} Compiler */
/** @typedef {import("../../../../").Asset} Asset */
/** @typedef {import("../../../../").AssetInfo} AssetInfo */
/** @typedef {import("../../../../").ChunkGroup} Entrypoint */
class VerifyAdditionalAssetsPlugin {
/**
* @param {number} stage stage
*/
constructor(stage) {
this.stage = stage;
}
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap(
"VerifyAdditionalAssetsPlugin",
@ -34,10 +45,16 @@ class VerifyAdditionalAssetsPlugin {
}
class HtmlPlugin {
/**
* @param {string[]} entrypoints entrypoints
*/
constructor(entrypoints) {
this.entrypoints = entrypoints;
}
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap("html-plugin", compilation => {
compilation.hooks.processAssets.tap(
@ -49,17 +66,27 @@ class HtmlPlugin {
const publicPath = compilation.outputOptions.publicPath;
const files = [];
for (const name of this.entrypoints) {
for (const file of compilation.entrypoints.get(name).getFiles())
for (const file of /** @type {Entrypoint} */ (
compilation.entrypoints.get(name)
).getFiles())
files.push(file);
}
const toScriptTag = (file, extra) => {
const asset = compilation.getAsset(file);
/**
* @param {string} file file
* @returns {string} content of script tag
*/
const toScriptTag = file => {
const asset = /** @type {Asset} */ (compilation.getAsset(file));
const hash = createHash("sha512");
hash.update(asset.source.source());
const integrity = `sha512-${hash.digest("base64")}`;
compilation.updateAsset(
file,
x => x,
/**
* @param {AssetInfo} assetInfo asset info
* @returns {AssetInfo} new asset info
*/
assetInfo => ({
...assetInfo,
contenthash: Array.isArray(assetInfo.contenthash)
@ -91,10 +118,16 @@ ${files.map(file => ` ${toScriptTag(file)}`).join("\n")}
}
class HtmlInlinePlugin {
/**
* @param {RegExp} inline inline
*/
constructor(inline) {
this.inline = inline;
}
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap("html-inline-plugin", compilation => {
compilation.hooks.processAssets.tap(
@ -104,11 +137,14 @@ class HtmlInlinePlugin {
additionalAssets: true
},
assets => {
const publicPath = compilation.outputOptions.publicPath;
const publicPath =
/** @type {string} */
(compilation.outputOptions.publicPath);
for (const name of Object.keys(assets)) {
if (/\.html$/.test(name)) {
const asset = compilation.getAsset(name);
const content = asset.source.source();
const asset = /** @type {Asset} */ (compilation.getAsset(name));
const content = /** @type {string} */ (asset.source.source());
/** @type {{ start: number, length: number, asset: Asset }[]} */
const matches = [];
const regExp =
/<script\s+src\s*=\s*"([^"]+)"(?:\s+[^"=\s]+(?:\s*=\s*(?:"[^"]*"|[^\s]+))?)*\s*><\/script>/g;
@ -118,7 +154,9 @@ class HtmlInlinePlugin {
if (url.startsWith(publicPath))
url = url.slice(publicPath.length);
if (this.inline.test(url)) {
const asset = compilation.getAsset(url);
const asset = /** @type {Asset} */ (
compilation.getAsset(url)
);
matches.push({
start: match.index,
length: match[0].length,
@ -147,6 +185,9 @@ class HtmlInlinePlugin {
}
class SriHashSupportPlugin {
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap("sri-hash-support-plugin", compilation => {
RealContentHashPlugin.getCompilationHooks(compilation).updateHash.tap(
@ -164,6 +205,9 @@ class SriHashSupportPlugin {
}
class HtmlMinimizePlugin {
/**
* @param {Compiler} compiler compiler
*/
apply(compiler) {
compiler.hooks.compilation.tap("html-minimize-plugin", compilation => {
compilation.hooks.processAssets.tap(
@ -177,7 +221,11 @@ class HtmlMinimizePlugin {
if (/\.html$/.test(name)) {
compilation.updateAsset(
name,
source => new RawSource(source.source().replace(/\s+/g, " ")),
source =>
new RawSource(
/** @type {string} */
(source.source()).replace(/\s+/g, " ")
),
assetInfo => ({
...assetInfo,
minimized: true

Some files were not shown because too many files have changed in this diff Show More