fix(types): context module types

This commit is contained in:
alexander.akait 2024-03-25 19:05:56 +03:00
parent e660ad8b75
commit 4b62748f37
5 changed files with 153 additions and 71 deletions

View File

@ -231,6 +231,7 @@
"sourcemapped",
"splitted",
"stylesheet",
"slsh",
"subdir",
"subfolder",
"submodule",

View File

@ -187,6 +187,7 @@ const isAvailableChunk = (a, b) => {
/** @typedef {Set<Chunk>} EntryInChunks */
/** @typedef {Set<Chunk>} RuntimeInChunks */
/** @typedef {string | number} ModuleId */
class ChunkGraphModule {
constructor() {
@ -1309,7 +1310,7 @@ class ChunkGraph {
/**
* @param {Module} module the module
* @returns {string | number} the id of the module
* @returns {ModuleId} the id of the module
*/
getModuleId(module) {
const cgm = this._getChunkGraphModule(module);
@ -1318,7 +1319,7 @@ class ChunkGraph {
/**
* @param {Module} module the module
* @param {string | number} id the id of the module
* @param {ModuleId} id the id of the module
* @returns {void}
*/
setModuleId(module, id) {

View File

@ -29,10 +29,14 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
/** @typedef {import("./ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").BuildInfo} BuildInfo */
/** @typedef {import("./Module").BuildMeta} BuildMeta */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
@ -93,6 +97,10 @@ const makeSerializable = require("./util/makeSerializable");
* @param {ResolveDependenciesCallback} callback
*/
/** @typedef {1 | 3 | 7 | 9} FakeMapType */
/** @typedef {Map<string, string | number> | FakeMapType} FakeMap */
const SNAPSHOT_OPTIONS = { timestamp: true };
const TYPES = new Set(["javascript"]);
@ -133,6 +141,7 @@ class ContextModule extends Module {
}
// Info from Factory
/** @type {ResolveDependencies | undefined} */
this.resolveDependencies = resolveDependencies;
if (options && options.resolveOptions !== undefined) {
this.resolveOptions = options.resolveOptions;
@ -174,6 +183,12 @@ class ContextModule extends Module {
this.resolveDependencies = undefined;
}
/**
* @private
* @param {RegExp} regexString RegExp as a string
* @param {boolean=} stripSlash do we need to strip a slsh
* @returns {string} pretty RegExp
*/
_prettyRegExp(regexString, stripSlash = true) {
const str = (regexString + "").replace(/!/g, "%21").replace(/\|/g, "%7C");
return stripSlash ? str.substring(1, str.length - 1) : str;
@ -298,7 +313,9 @@ class ContextModule extends Module {
if (this.options.groupOptions) {
const groupOptions = this.options.groupOptions;
for (const key of Object.keys(groupOptions)) {
identifier += ` ${key}: ${groupOptions[key]}`;
identifier += ` ${key}: ${
groupOptions[/** @type {keyof RawChunkGroupOptions} */ (key)]
}`;
}
}
if (this.options.namespaceObject === "strict") {
@ -387,11 +404,13 @@ class ContextModule extends Module {
// build if enforced
if (this._forceBuild) return callback(null, true);
const buildInfo = /** @type {BuildInfo} */ (this.buildInfo);
// always build when we have no snapshot and context
if (!this.buildInfo.snapshot)
if (!buildInfo.snapshot)
return callback(null, Boolean(this.context || this.options.resource));
fileSystemInfo.checkSnapshotValid(this.buildInfo.snapshot, (err, valid) => {
fileSystemInfo.checkSnapshotValid(buildInfo.snapshot, (err, valid) => {
callback(err, !valid);
});
}
@ -417,7 +436,8 @@ class ContextModule extends Module {
this.dependencies.length = 0;
this.blocks.length = 0;
const startTime = Date.now();
this.resolveDependencies(fs, this.options, (err, dependencies) => {
/** @type {ResolveDependencies} */
(this.resolveDependencies)(fs, this.options, (err, dependencies) => {
if (err) {
return callback(
makeWebpackError(err, "ContextModule.resolveDependencies")
@ -518,7 +538,8 @@ class ContextModule extends Module {
SNAPSHOT_OPTIONS,
(err, snapshot) => {
if (err) return callback(err);
this.buildInfo.snapshot = snapshot;
/** @type {BuildInfo} */
(this.buildInfo).snapshot = snapshot;
callback();
}
);
@ -549,35 +570,37 @@ class ContextModule extends Module {
}
/**
* @param {ContextElementDependency[]} dependencies all dependencies
* @param {Dependency[]} dependencies all dependencies
* @param {ChunkGraph} chunkGraph chunk graph
* @returns {TODO} TODO
* @returns {Map<string, string | number>} map with user requests
*/
getUserRequestMap(dependencies, chunkGraph) {
const moduleGraph = chunkGraph.moduleGraph;
// if we filter first we get a new array
// therefore we don't need to create a clone of dependencies explicitly
// therefore the order of this is !important!
const sortedDependencies = dependencies
.filter(dependency => moduleGraph.getModule(dependency))
.sort((a, b) => {
if (a.userRequest === b.userRequest) {
return 0;
}
return a.userRequest < b.userRequest ? -1 : 1;
});
const sortedDependencies =
/** @type {ContextElementDependency[]} */
(dependencies)
.filter(dependency => moduleGraph.getModule(dependency))
.sort((a, b) => {
if (a.userRequest === b.userRequest) {
return 0;
}
return a.userRequest < b.userRequest ? -1 : 1;
});
const map = Object.create(null);
for (const dep of sortedDependencies) {
const module = moduleGraph.getModule(dep);
const module = /** @type {Module} */ (moduleGraph.getModule(dep));
map[dep.userRequest] = chunkGraph.getModuleId(module);
}
return map;
}
/**
* @param {ContextElementDependency[]} dependencies all dependencies
* @param {Dependency[]} dependencies all dependencies
* @param {ChunkGraph} chunkGraph chunk graph
* @returns {TODO} TODO
* @returns {FakeMap} fake map
*/
getFakeMap(dependencies, chunkGraph) {
if (!this.options.namespaceObject) {
@ -591,7 +614,9 @@ class ContextModule extends Module {
// therefore we don't need to create a clone of dependencies explicitly
// therefore the order of this is !important!
const sortedModules = dependencies
.map(dependency => moduleGraph.getModule(dependency))
.map(
dependency => /** @type {Module} */ (moduleGraph.getModule(dependency))
)
.filter(Boolean)
.sort(comparator);
const fakeMap = Object.create(null);
@ -640,12 +665,21 @@ class ContextModule extends Module {
return fakeMap;
}
/**
* @param {FakeMap} fakeMap fake map
* @returns {string} fake map init statement
*/
getFakeMapInitStatement(fakeMap) {
return typeof fakeMap === "object"
? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};`
: "";
}
/**
* @param {FakeMapType} type type
* @param {boolean=} asyncModule is async module
* @returns {string} return result
*/
getReturn(type, asyncModule) {
if (type === 9) {
return `${RuntimeGlobals.require}(id)`;
@ -655,6 +689,12 @@ class ContextModule extends Module {
})`;
}
/**
* @param {FakeMap} fakeMap fake map
* @param {boolean=} asyncModule us async module
* @param {string=} fakeMapDataExpression fake map data expression
* @returns {string} module object source
*/
getReturnModuleObjectSource(
fakeMap,
asyncModule,
@ -669,8 +709,8 @@ class ContextModule extends Module {
}
/**
* @param {TODO} dependencies TODO
* @param {TODO} id TODO
* @param {Dependency[]} dependencies dependencies
* @param {ModuleId} id module id
* @param {ChunkGraph} chunkGraph the chunk graph
* @returns {string} source code
*/
@ -703,8 +743,8 @@ webpackContext.id = ${JSON.stringify(id)};`;
}
/**
* @param {TODO} dependencies TODO
* @param {TODO} id TODO
* @param {Dependency[]} dependencies dependencies
* @param {ModuleId} id module id
* @param {ChunkGraph} chunkGraph the chunk graph
* @returns {string} source code
*/
@ -742,8 +782,8 @@ module.exports = webpackContext;`;
}
/**
* @param {TODO} dependencies TODO
* @param {TODO} id TODO
* @param {Dependency[]} dependencies dependencies
* @param {ModuleId} id module id
* @param {Object} context context
* @param {ChunkGraph} context.chunkGraph the chunk graph
* @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
@ -791,8 +831,8 @@ module.exports = webpackAsyncContext;`;
}
/**
* @param {TODO} dependencies TODO
* @param {TODO} id TODO
* @param {Dependency[]} dependencies dependencies
* @param {ModuleId} id module id
* @param {Object} context context
* @param {ChunkGraph} context.chunkGraph the chunk graph
* @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
@ -835,9 +875,9 @@ module.exports = webpackAsyncContext;`;
}
/**
* @param {TODO} block TODO
* @param {TODO} dependencies TODO
* @param {TODO} id TODO
* @param {AsyncDependenciesBlock} block block
* @param {Dependency[]} dependencies dependencies
* @param {ModuleId} id module id
* @param {Object} options options object
* @param {RuntimeTemplate} options.runtimeTemplate the runtime template
* @param {ChunkGraph} options.chunkGraph the chunk graph
@ -885,8 +925,8 @@ module.exports = webpackAsyncContext;`;
}
/**
* @param {TODO} blocks TODO
* @param {TODO} id TODO
* @param {AsyncDependenciesBlock[]} blocks blocks
* @param {ModuleId} id module id
* @param {Object} context context
* @param {ChunkGraph} context.chunkGraph the chunk graph
* @param {RuntimeTemplate} context.runtimeTemplate the chunk graph
@ -904,10 +944,12 @@ module.exports = webpackAsyncContext;`;
const hasFakeMap = typeof fakeMap === "object";
const items = blocks
.map(block => {
const dependency = block.dependencies[0];
const dependency =
/** @type {ContextElementDependency} */
(block.dependencies[0]);
return {
dependency: dependency,
module: moduleGraph.getModule(dependency),
module: /** @type {Module} */ (moduleGraph.getModule(dependency)),
block: block,
userRequest: dependency.userRequest,
chunks: undefined
@ -997,6 +1039,11 @@ webpackAsyncContext.id = ${JSON.stringify(id)};
module.exports = webpackAsyncContext;`;
}
/**
* @param {ModuleId} id module id
* @param {RuntimeTemplate} runtimeTemplate runtime template
* @returns {string} source for empty async context
*/
getSourceForEmptyContext(id, runtimeTemplate) {
return `function webpackEmptyContext(req) {
var e = new Error("Cannot find module '" + req + "'");
@ -1009,6 +1056,11 @@ webpackEmptyContext.id = ${JSON.stringify(id)};
module.exports = webpackEmptyContext;`;
}
/**
* @param {ModuleId} id module id
* @param {RuntimeTemplate} runtimeTemplate runtime template
* @returns {string} source for empty async context
*/
getSourceForEmptyAsyncContext(id, runtimeTemplate) {
const arrow = runtimeTemplate.supportsArrowFunction();
return `function webpackEmptyAsyncContext(req) {

View File

@ -133,7 +133,13 @@ class SnapshotIterator {
}
}
/** @typedef {(snapshot: Snapshot) => (Map<string, any> | Set<string>)[]} GetMapsFunction */
class SnapshotIterable {
/**
* @param {Snapshot} snapshot snapshot
* @param {GetMapsFunction} getMaps get maps function
*/
constructor(snapshot, getMaps) {
this.snapshot = snapshot;
this.getMaps = getMaps;
@ -213,6 +219,13 @@ class SnapshotIterable {
}
}
/** @typedef {Map<string, FileSystemInfoEntry | null>} FileTimestamps */
/** @typedef {Map<string, string | null>} FileHashes */
/** @typedef {Map<string, TimestampAndHash | string | null>} FileTshs */
/** @typedef {Map<string, ResolvedContextFileSystemInfoEntry | null>} ContextTimestamps */
/** @typedef {Map<string, string | null>} ContextHashes */
/** @typedef {Map<string, ResolvedContextTimestampAndHash | null>} ContextTshs */
class Snapshot {
constructor() {
this._flags = 0;
@ -224,17 +237,17 @@ class Snapshot {
this._cachedMissingIterable = undefined;
/** @type {number | undefined} */
this.startTime = undefined;
/** @type {Map<string, FileSystemInfoEntry | null> | undefined} */
/** @type {FileTimestamps | undefined} */
this.fileTimestamps = undefined;
/** @type {Map<string, string | null> | undefined} */
/** @type {FileHashes | undefined} */
this.fileHashes = undefined;
/** @type {Map<string, TimestampAndHash | string | null> | undefined} */
/** @type {FileTshs | undefined} */
this.fileTshs = undefined;
/** @type {Map<string, ResolvedContextFileSystemInfoEntry | null> | undefined} */
/** @type {ContextTimestamps | undefined} */
this.contextTimestamps = undefined;
/** @type {Map<string, string | null> | undefined} */
/** @type {ContextHashes | undefined} */
this.contextHashes = undefined;
/** @type {Map<string, ResolvedContextTimestampAndHash | null> | undefined} */
/** @type {ContextTshs | undefined} */
this.contextTshs = undefined;
/** @type {Map<string, boolean> | undefined} */
this.missingExistence = undefined;
@ -254,6 +267,9 @@ class Snapshot {
return (this._flags & 1) !== 0;
}
/**
* @param {number} value start value
*/
setStartTime(value) {
this._flags = this._flags | 1;
this.startTime = value;
@ -427,7 +443,7 @@ class Snapshot {
}
/**
* @param {function(Snapshot): (ReadonlyMap<string, any> | ReadonlySet<string>)[]} getMaps first
* @param {GetMapsFunction} getMaps first
* @returns {Iterable<string>} iterable
*/
_createIterable(getMaps) {
@ -728,6 +744,10 @@ class SnapshotOptimization {
}
}
/**
* @param {string} str input
* @returns {TODO} result
*/
const parseString = str => {
if (str[0] === "'" || str[0] === "`")
str = `"${str.slice(1, -1).replace(/"/g, '\\"')}"`;
@ -989,7 +1009,7 @@ class FileSystemInfo {
);
/** @type {StackedCacheMap<string, FileSystemInfoEntry | "ignore" | null>} */
this._fileTimestamps = new StackedCacheMap();
/** @type {Map<string, string>} */
/** @type {Map<string, string | null>} */
this._fileHashes = new Map();
/** @type {Map<string, TimestampAndHash | string>} */
this._fileTshs = new Map();
@ -1081,13 +1101,18 @@ class FileSystemInfo {
}
logStatistics() {
const logger = /** @type {Logger} */ (this.logger);
/**
* @param {string} header header
* @param {string | undefined} message message
*/
const logWhenMessage = (header, message) => {
if (message) {
this.logger.log(`${header}: ${message}`);
logger.log(`${header}: ${message}`);
}
};
this.logger.log(`${this._statCreatedSnapshots} new snapshots created`);
this.logger.log(
logger.log(`${this._statCreatedSnapshots} new snapshots created`);
logger.log(
`${
this._statTestedSnapshotsNotCached &&
Math.round(
@ -1099,7 +1124,7 @@ class FileSystemInfo {
this._statTestedSnapshotsCached + this._statTestedSnapshotsNotCached
})`
);
this.logger.log(
logger.log(
`${
this._statTestedChildrenNotCached &&
Math.round(
@ -1110,8 +1135,8 @@ class FileSystemInfo {
this._statTestedChildrenCached + this._statTestedChildrenNotCached
})`
);
this.logger.log(`${this._statTestedEntries} entries tested`);
this.logger.log(
logger.log(`${this._statTestedEntries} entries tested`);
logger.log(
`File info in cache: ${this._fileTimestamps.size} timestamps ${this._fileHashes.size} hashes ${this._fileTshs.size} timestamp hash combinations`
);
logWhenMessage(
@ -1126,7 +1151,7 @@ class FileSystemInfo {
`File timestamp hash combination snapshot optimization`,
this._fileTshsOptimization.getStatisticMessage()
);
this.logger.log(
logger.log(
`Directory info in cache: ${this._contextTimestamps.size} timestamps ${this._contextHashes.size} hashes ${this._contextTshs.size} timestamp hash combinations`
);
logWhenMessage(
@ -1145,9 +1170,7 @@ class FileSystemInfo {
`Missing items snapshot optimization`,
this._missingExistenceOptimization.getStatisticMessage()
);
this.logger.log(
`Managed items info in cache: ${this._managedItems.size} items`
);
logger.log(`Managed items info in cache: ${this._managedItems.size} items`);
logWhenMessage(
`Managed items snapshot optimization`,
this._managedItemInfoOptimization.getStatisticMessage()
@ -1302,13 +1325,15 @@ class FileSystemInfo {
const cache = this._contextHashes.get(path);
if (cache !== undefined) {
const resolved = getResolvedHash(cache);
if (resolved !== undefined) return callback(null, resolved);
if (resolved !== undefined)
return callback(null, /** @type {string} */ (resolved));
return this._resolveContextHash(cache, callback);
}
this.contextHashQueue.add(path, (err, entry) => {
if (err) return callback(err);
const resolved = getResolvedHash(entry);
if (resolved !== undefined) return callback(null, resolved);
if (resolved !== undefined)
return callback(null, /** @type {string} */ (resolved));
this._resolveContextHash(entry, callback);
});
}
@ -1513,7 +1538,8 @@ class FileSystemInfo {
resolveResults.set(key, result.path);
} else {
invalidResolveResults.add(key);
this.logger.warn(
/** @type {Logger} */
(this.logger).warn(
`Resolving '${path}' in ${context} for build dependencies doesn't lead to expected result '${expected}', but to '${
err || (result && result.path)
}' instead. Resolving dependencies are ignored for this path.\n${pathToString(
@ -1941,9 +1967,9 @@ class FileSystemInfo {
/**
*
* @param {number | null | undefined} startTime when processing the files has started
* @param {Iterable<string>} files all files
* @param {Iterable<string>} directories all directories
* @param {Iterable<string>} missing all missing files or directories
* @param {Iterable<string> | null} files all files
* @param {Iterable<string> | null} directories all directories
* @param {Iterable<string> | null} missing all missing files or directories
* @param {SnapshotOptions | null | undefined} options options object (for future extensions)
* @param {function((WebpackError | null)=, (Snapshot | null)=): void} callback callback function
* @returns {void}
@ -3318,7 +3344,7 @@ class FileSystemInfo {
/**
* @param {ContextHash} entry context hash
* @param {function((Error | null)=, string=): void} callback callback
* @param {function((WebpackError | null)=, string=): void} callback callback
* @returns {void}
*/
_resolveContextHash(entry, callback) {
@ -3340,7 +3366,7 @@ class FileSystemInfo {
});
},
err => {
if (err) return callback(err);
if (err) return callback(/** @type {WebpackError} */ (err));
const hash = createHash(this._hashFunction);
hash.update(entry.hash);
hashes.sort();
@ -3583,7 +3609,7 @@ class FileSystemInfo {
elements.length === 1 &&
elements[0] === "node_modules"
) {
// This is only a grouping folder e. g. used by yarn
// This is only a grouping folder e.g. used by yarn
// we are only interested in existence of this special directory
this._managedItems.set(path, "*nested");
return callback(null, "*nested");
@ -3604,7 +3630,8 @@ class FileSystemInfo {
return callback(e);
}
if (!data.name) {
this.logger.warn(
/** @type {Logger} */
(this.logger).warn(
`${packageJsonPath} doesn't contain a "name" property (see snapshot.managedPaths option)`
);
return callback();

15
types.d.ts vendored
View File

@ -1210,8 +1210,8 @@ declare class ChunkGraph {
chunkGroup: ChunkGroup
): void;
disconnectChunkGroup(chunkGroup: ChunkGroup): void;
getModuleId(module: Module): string | number;
setModuleId(module: Module, id: string | number): void;
getModuleId(module: Module): ModuleId;
setModuleId(module: Module, id: ModuleId): void;
getRuntimeId(runtime: string): string | number;
setRuntimeId(runtime: string, id: string | number): void;
hasModuleHashes(module: Module, runtime: RuntimeSpec): boolean;
@ -4858,9 +4858,9 @@ declare abstract class FileSystemInfo {
): void;
createSnapshot(
startTime: undefined | null | number,
files: Iterable<string>,
directories: Iterable<string>,
missing: Iterable<string>,
files: null | Iterable<string>,
directories: null | Iterable<string>,
missing: null | Iterable<string>,
options: undefined | null | SnapshotOptionsFileSystemInfo,
callback: (arg0?: null | WebpackError, arg1?: null | Snapshot) => void
): void;
@ -7990,7 +7990,7 @@ declare class Module extends DependenciesBlock {
buildInfo?: BuildInfo;
presentationalDependencies?: Dependency[];
codeGenerationDependencies?: Dependency[];
id: string | number;
id: ModuleId;
get hash(): string;
get renderedHash(): string;
profile?: ModuleProfile;
@ -8393,6 +8393,7 @@ declare class ModuleGraphConnection {
static TRANSITIVE_ONLY: typeof TRANSITIVE_ONLY;
static CIRCULAR_CONNECTION: typeof CIRCULAR_CONNECTION;
}
type ModuleId = string | number;
type ModuleInfo = ConcatenatedModuleInfo | ExternalModuleInfo;
/**
@ -13064,7 +13065,7 @@ declare abstract class Snapshot {
managedMissing?: Set<string>;
children?: Set<Snapshot>;
hasStartTime(): boolean;
setStartTime(value?: any): void;
setStartTime(value: number): void;
setMergedStartTime(value?: any, snapshot?: any): void;
hasFileTimestamps(): boolean;
setFileTimestamps(value?: any): void;