chore(types): more

This commit is contained in:
alexander.akait 2024-01-26 17:47:14 +03:00
parent 89bea025a7
commit 1c4bcfa36c
7 changed files with 213 additions and 67 deletions

View File

@ -25,9 +25,11 @@ const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule");
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
/** @typedef {import("./javascript/JavascriptParser").Range} Range */
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
/**
* @param {boolean} module true if ES module
* @param {boolean | undefined} module true if ES module
* @param {string} importMetaName `import.meta` name
* @returns {Record<string, {expr: string, req: string[] | null, type?: string, assign: boolean}>} replacements
*/
@ -150,7 +152,9 @@ class APIPlugin {
compiler.hooks.compilation.tap(
PLUGIN_NAME,
(compilation, { normalModuleFactory }) => {
const { importMetaName } = compilation.outputOptions;
const importMetaName = /** @type {string} */ (
compilation.outputOptions.importMetaName
);
const REPLACEMENTS = getReplacements(
this.options.module,
importMetaName
@ -166,7 +170,7 @@ class APIPlugin {
.tap(PLUGIN_NAME, chunk => {
compilation.addRuntimeModule(
chunk,
new ChunkNameRuntimeModule(chunk.name)
new ChunkNameRuntimeModule(/** @type {string} */ (chunk.name))
);
return true;
});
@ -218,7 +222,7 @@ class APIPlugin {
if (info.assign === false) {
parser.hooks.assign.for(key).tap(PLUGIN_NAME, expr => {
const err = new WebpackError(`${key} must not be assigned`);
err.loc = expr.loc;
err.loc = /** @type {DependencyLocation} */ (expr.loc);
throw err;
});
}
@ -234,9 +238,9 @@ class APIPlugin {
.tap(PLUGIN_NAME, expr => {
const dep = new ConstDependency(
JSON.stringify(parser.state.module.layer),
expr.range
/** @type {Range} */ (expr.range)
);
dep.loc = expr.loc;
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(dep);
return true;
});
@ -248,7 +252,7 @@ class APIPlugin {
: new BasicEvaluatedExpression().setString(
parser.state.module.layer
)
).setRange(expr.range)
).setRange(/** @type {Range} */ (expr.range))
);
parser.hooks.evaluateTypeof
.for("__webpack_layer__")
@ -257,7 +261,7 @@ class APIPlugin {
.setString(
parser.state.module.layer === null ? "object" : "string"
)
.setRange(expr.range)
.setRange(/** @type {Range} */ (expr.range))
);
parser.hooks.expression
@ -267,10 +271,10 @@ class APIPlugin {
"__webpack_module__.id";
const dep = new ConstDependency(
parser.state.module.moduleArgument + ".id",
expr.range,
/** @type {Range} */ (expr.range),
[RuntimeGlobals.moduleId]
);
dep.loc = expr.loc;
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(dep);
return true;
});
@ -282,10 +286,10 @@ class APIPlugin {
"__webpack_module__";
const dep = new ConstDependency(
parser.state.module.moduleArgument,
expr.range,
/** @type {Range} */ (expr.range),
[RuntimeGlobals.module]
);
dep.loc = expr.loc;
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(dep);
return true;
});

View File

@ -40,7 +40,7 @@ const sortFragmentWithIndex = ([a, i], [b, j]) => {
*/
class InitFragment {
/**
* @param {string|Source} content the source code that will be included as initialization code
* @param {string | Source | undefined} content the source code that will be included as initialization code
* @param {number} stage category of initialization code (contribute to order)
* @param {number} position position in the category (contribute to order)
* @param {string=} key unique key to avoid emitting the same initialization code twice
@ -56,7 +56,7 @@ class InitFragment {
/**
* @param {Context} context context
* @returns {string|Source} the source code that will be included as initialization code
* @returns {string | Source | undefined} the source code that will be included as initialization code
*/
getContent(context) {
return this.content;
@ -91,7 +91,7 @@ class InitFragment {
for (const [fragment] of sortedFragments) {
if (
typeof (
/** @type {InitFragment<T> & { mergeAll?: (fragments: InitFragment[]) => InitFragment[] }} */
/** @type {InitFragment<T> & { mergeAll?: (fragments: InitFragment<Context>[]) => InitFragment<Context>[] }} */
(fragment).mergeAll
) === "function"
) {

View File

@ -136,7 +136,7 @@ class NodeStuffPlugin {
/**
* @param {string} expressionName expression name
* @param {(value: string) => void} fn function
* @param {(value: string) => string} fn function
* @returns {void}
*/
const setUrlModuleConstant = (expressionName, fn) => {
@ -153,10 +153,10 @@ class NodeStuffPlugin {
],
undefined,
fn("__webpack_fileURLToPath__"),
expr.range,
/** @type {Range} */ (expr.range),
expressionName
);
dep.loc = expr.loc;
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(dep);
return true;

View File

@ -14,11 +14,20 @@ const ExternalModuleInitFragment = require("./ExternalModuleInitFragment");
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../util/Hash")} Hash */
class ExternalModuleDependency extends CachedConstDependency {
/**
* @param {string} module module
* @param {{ name: string, value: string }[]} importSpecifiers import specifiers
* @param {string | undefined} defaultImport default import
* @param {string} expression expression
* @param {Range} range range
* @param {string} identifier identifier
*/
constructor(
module,
importSpecifiers,

View File

@ -9,11 +9,14 @@ const InitFragment = require("../InitFragment");
const makeSerializable = require("../util/makeSerializable");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Generator").GenerateContext} Context */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {Map<string, Set<string>>} ImportSpecifiers */
/**
* @extends {InitFragment<GenerateContext>}
*/
class ExternalModuleInitFragment extends InitFragment {
/**
* @param {string} importedModule imported module
@ -45,6 +48,10 @@ class ExternalModuleInitFragment extends InitFragment {
this.defaultImport = defaultImport;
}
/**
* @param {ExternalModuleInitFragment} other other
* @returns {ExternalModuleInitFragment} ExternalModuleInitFragment
*/
merge(other) {
const newSpecifiersMap = new Map(this.specifiers);
for (const [name, specifiers] of other.specifiers) {
@ -63,7 +70,7 @@ class ExternalModuleInitFragment extends InitFragment {
}
/**
* @param {Context} context context
* @param {GenerateContext} context context
* @returns {string|Source} the source code that will be included as initialization code
*/
getContent({ runtimeRequirements }) {

View File

@ -93,6 +93,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
/** @typedef {{declaredScope: ScopeInfo, freeName: string | true, tagInfo: TagInfo | undefined}} VariableInfoInterface */
/** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[] }} GetInfoResult */
/** @typedef {Statement | ModuleDeclaration | Expression} StatementPathItem */
/** @type {string[]} */
const EMPTY_ARRAY = [];
@ -423,9 +424,11 @@ class JavascriptParser extends Parser {
this.scope = undefined;
/** @type {ParserState} */
this.state = undefined;
/** @type {Comment[] | undefined} */
this.comments = undefined;
/** @type {Set<number> | undefined} */
this.semicolons = undefined;
/** @type {(Statement | ModuleDeclaration | Expression)[]} */
/** @type {StatementPathItem[]} */
this.statementPath = undefined;
/** @type {Statement | ModuleDeclaration | Expression | undefined} */
this.prevStatement = undefined;
@ -683,7 +686,18 @@ class JavascriptParser extends Parser {
const isAlwaysDifferent = (a, b) =>
(a === true && b === false) || (a === false && b === true);
/**
* @param {BasicEvaluatedExpression} left left
* @param {BasicEvaluatedExpression} right right
* @param {BasicEvaluatedExpression} res res
* @param {boolean} eql true for "===" and false for "!=="
* @returns {BasicEvaluatedExpression | undefined} result
*/
const handleTemplateStringCompare = (left, right, res, eql) => {
/**
* @param {BasicEvaluatedExpression[]} parts parts
* @returns {string} value
*/
const getPrefix = parts => {
let value = "";
for (const p of parts) {
@ -693,6 +707,10 @@ class JavascriptParser extends Parser {
}
return value;
};
/**
* @param {BasicEvaluatedExpression[]} parts parts
* @returns {string} value
*/
const getSuffix = parts => {
let value = "";
for (let i = parts.length - 1; i >= 0; i--) {
@ -702,10 +720,18 @@ class JavascriptParser extends Parser {
}
return value;
};
const leftPrefix = getPrefix(left.parts);
const rightPrefix = getPrefix(right.parts);
const leftSuffix = getSuffix(left.parts);
const rightSuffix = getSuffix(right.parts);
const leftPrefix = getPrefix(
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
);
const rightPrefix = getPrefix(
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
);
const leftSuffix = getSuffix(
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
);
const rightSuffix = getSuffix(
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
);
const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
const prefixMismatch =
@ -831,9 +857,12 @@ class JavascriptParser extends Parser {
const res = new BasicEvaluatedExpression();
if (left.isString()) {
if (right.isString()) {
res.setString(left.string + right.string);
res.setString(
/** @type {string} */ (left.string) +
/** @type {string} */ (right.string)
);
} else if (right.isNumber()) {
res.setString(left.string + right.number);
res.setString(/** @type {string} */ (left.string) + right.number);
} else if (
right.isWrapped() &&
right.prefix &&
@ -843,7 +872,10 @@ class JavascriptParser extends Parser {
// => ("leftPrefix" + inner + "postfix")
res.setWrapped(
new BasicEvaluatedExpression()
.setString(left.string + right.prefix.string)
.setString(
/** @type {string} */ (left.string) +
/** @type {string} */ (right.prefix.string)
)
.setRange(joinRanges(left.range, right.prefix.range)),
right.postfix,
right.wrappedInnerExpressions
@ -863,7 +895,7 @@ class JavascriptParser extends Parser {
}
} else if (left.isNumber()) {
if (right.isString()) {
res.setString(left.number + right.string);
res.setString(left.number + /** @type {string} */ (right.string));
} else if (right.isNumber()) {
res.setNumber(left.number + right.number);
} else {
@ -871,7 +903,10 @@ class JavascriptParser extends Parser {
}
} else if (left.isBigInt()) {
if (right.isBigInt()) {
res.setBigInt(left.bigint + right.bigint);
res.setBigInt(
/** @type {bigint} */ (left.bigint) +
/** @type {bigint} */ (right.bigint)
);
}
} else if (left.isWrapped()) {
if (left.postfix && left.postfix.isString() && right.isString()) {
@ -880,8 +915,16 @@ class JavascriptParser extends Parser {
res.setWrapped(
left.prefix,
new BasicEvaluatedExpression()
.setString(left.postfix.string + right.string)
.setRange(joinRanges(left.postfix.range, right.range)),
.setString(
/** @type {string} */ (left.postfix.string) +
/** @type {string} */ (right.string)
)
.setRange(
joinRanges(
/** @type {Range} */ (left.postfix.range),
/** @type {Range} */ (right.range)
)
),
left.wrappedInnerExpressions
);
} else if (
@ -894,8 +937,16 @@ class JavascriptParser extends Parser {
res.setWrapped(
left.prefix,
new BasicEvaluatedExpression()
.setString(left.postfix.string + right.number)
.setRange(joinRanges(left.postfix.range, right.range)),
.setString(
/** @type {string} */ (left.postfix.string) +
/** @type {number} */ (right.number)
)
.setRange(
joinRanges(
/** @type {Range} */ (left.postfix.range),
/** @type {Range} */ (right.range)
)
),
left.wrappedInnerExpressions
);
} else if (right.isString()) {
@ -909,7 +960,7 @@ class JavascriptParser extends Parser {
left.prefix,
new BasicEvaluatedExpression()
.setString(right.number + "")
.setRange(right.range),
.setRange(/** @type {Range} */ (right.range)),
left.wrappedInnerExpressions
);
} else if (right.isWrapped()) {
@ -1280,9 +1331,12 @@ class JavascriptParser extends Parser {
if (arg2.type === "SpreadElement") return;
const arg2Eval = this.evaluateExpression(arg2);
if (!arg2Eval.isNumber()) return;
result = param.string.indexOf(arg1Value, arg2Eval.number);
result = /** @type {string} */ (param.string).indexOf(
arg1Value,
arg2Eval.number
);
} else {
result = param.string.indexOf(arg1Value);
result = /** @type {string} */ (param.string).indexOf(arg1Value);
}
return new BasicEvaluatedExpression()
.setNumber(result)
@ -1303,7 +1357,9 @@ class JavascriptParser extends Parser {
if (!arg2.isString()) return;
const arg2Value = arg2.string;
return new BasicEvaluatedExpression()
.setString(param.string.replace(arg1Value, arg2Value))
.setString(
/** @type {string} */ (param.string).replace(arg1Value, arg2Value)
)
.setSideEffects(param.couldHaveSideEffects())
.setRange(/** @type {Range} */ (expr.range));
});
@ -1314,7 +1370,7 @@ class JavascriptParser extends Parser {
if (!param.isString()) return;
let arg1;
let result,
str = param.string;
str = /** @type {string} */ (param.string);
switch (expr.arguments.length) {
case 1:
if (expr.arguments[0].type === "SpreadElement") return;
@ -1371,7 +1427,10 @@ class JavascriptParser extends Parser {
// is a const string
prevExpr.setString(prevExpr.string + exprAsString + quasi);
prevExpr.setRange([prevExpr.range[0], quasiExpr.range[1]]);
prevExpr.setRange([
/** @type {Range} */ (prevExpr.range)[0],
/** @type {Range} */ (quasiExpr.range)[1]
]);
// We unset the expression as it doesn't match to a single expression
prevExpr.setExpression(undefined);
continue;
@ -1443,14 +1502,16 @@ class JavascriptParser extends Parser {
continue;
}
/** @type {string} */
const value = argExpr.isString()
? argExpr.string
: "" + argExpr.number;
? /** @type {string} */ (argExpr.string)
: "" + /** @type {number} */ (argExpr.number);
/** @type {string} */
const newString = value + (stringSuffix ? stringSuffix.string : "");
const newRange = /** @type {Range} */ ([
argExpr.range[0],
(stringSuffix || argExpr).range[1]
/** @type {Range} */ (argExpr.range)[0],
/** @type {Range} */ ((stringSuffix || argExpr).range)[1]
]);
stringSuffix = new BasicEvaluatedExpression()
.setString(newString)
@ -1480,7 +1541,8 @@ class JavascriptParser extends Parser {
.setRange(/** @type {Range} */ (expr.range));
} else {
const newString =
param.string + (stringSuffix ? stringSuffix.string : "");
/** @type {string} */ (param.string) +
(stringSuffix ? stringSuffix.string : "");
return new BasicEvaluatedExpression()
.setString(newString)
.setSideEffects(
@ -1499,9 +1561,11 @@ class JavascriptParser extends Parser {
let result;
const arg = this.evaluateExpression(expr.arguments[0]);
if (arg.isString()) {
result = param.string.split(arg.string);
result =
/** @type {string} */
(param.string).split(/** @type {string} */ (arg.string));
} else if (arg.isRegExp()) {
result = param.string.split(arg.regExp);
result = /** @type {string} */ (param.string).split(arg.regExp);
} else {
return;
}
@ -2290,6 +2354,10 @@ class JavascriptParser extends Parser {
}
}
/**
* @param {Declaration} declaration
* @param {TODO} onIdent
*/
enterDeclaration(declaration, onIdent) {
switch (declaration.type) {
case "VariableDeclaration":
@ -2546,10 +2614,16 @@ class JavascriptParser extends Parser {
declarator.init && this.getRenameIdentifier(declarator.init);
if (renameIdentifier && declarator.id.type === "Identifier") {
const hook = this.hooks.canRename.get(renameIdentifier);
if (hook !== undefined && hook.call(declarator.init)) {
if (
hook !== undefined &&
hook.call(/** @type {Expression} */ (declarator.init))
) {
// renaming with "var a = b;"
const hook = this.hooks.rename.get(renameIdentifier);
if (hook === undefined || !hook.call(declarator.init)) {
if (
hook === undefined ||
!hook.call(/** @type {Expression} */ (declarator.init))
) {
this.setVariable(declarator.id.name, renameIdentifier);
}
break;
@ -2934,7 +3008,7 @@ class JavascriptParser extends Parser {
(currentStatement.type === "ExpressionStatement" &&
currentStatement.expression === expression)
) {
const old = this.statementPath.pop();
const old = /** @type {StatementPathItem} */ (this.statementPath.pop());
for (const expr of expression.expressions) {
this.statementPath.push(expr);
this.walkExpression(expr);
@ -3389,6 +3463,13 @@ class JavascriptParser extends Parser {
if (expression.computed === true) this.walkExpression(expression.property);
}
/**
* @param {TODO} expression member expression
* @param {string} name name
* @param {string | VariableInfo} rootInfo root info
* @param {string[]} members members
* @param {TODO} onUnhandled on unhandled callback
*/
walkMemberExpressionWithExpressionName(
expression,
name,
@ -3442,7 +3523,14 @@ class JavascriptParser extends Parser {
walkMetaProperty(metaProperty) {
this.hooks.expression.for(getRootName(metaProperty)).call(metaProperty);
}
/**
* @template T
* @template R
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called
* @param {TODO} expr expression
* @param {AsArray<T>} args args for the hook
* @returns {R | undefined} result of hook
*/
callHooksForExpression(hookMap, expr, ...args) {
return this.callHooksForExpressionWithFallback(
hookMap,
@ -3731,6 +3819,10 @@ class JavascriptParser extends Parser {
}
}
/**
* @param {(Pattern | Property)[]} patterns patterns
* @param {TODO} onIdent on ident callback
*/
enterPatterns(patterns, onIdent) {
for (const pattern of patterns) {
if (typeof pattern !== "string") {
@ -3741,6 +3833,10 @@ class JavascriptParser extends Parser {
}
}
/**
* @param {Pattern | Property} pattern pattern
* @param {TODO} onIdent on ident callback
*/
enterPattern(pattern, onIdent) {
if (!pattern) return;
switch (pattern.type) {
@ -3765,7 +3861,7 @@ class JavascriptParser extends Parser {
this.enterIdentifier(pattern.value, onIdent);
this.scope.inShorthand = false;
} else {
this.enterPattern(pattern.value, onIdent);
this.enterPattern(/** @type {Identifier} */ (pattern.value), onIdent);
}
break;
}
@ -3807,10 +3903,12 @@ class JavascriptParser extends Parser {
elementIndex++
) {
const element = pattern.elements[elementIndex];
// TODO check on `null`?
if (element) {
this.enterPattern(element, onIdent);
}
}
}
/**
* @param {RestElement} pattern object pattern
@ -4160,15 +4258,26 @@ class JavascriptParser extends Parser {
/**
* @param {Range} range range
* @returns {TODO[]} comments in the range
* @returns {Comment[]} comments in the range
*/
getComments(range) {
const [rangeStart, rangeEnd] = range;
const compare = (comment, needle) => comment.range[0] - needle;
let idx = binarySearchBounds.ge(this.comments, rangeStart, compare);
/**
* @param {Comment} comment comment
* @param {number} needle needle
* @returns {number} compared
*/
const compare = (comment, needle) =>
/** @type {Range} */ (comment.range)[0] - needle;
const comments = /** @type {Comment[]} */ (this.comments);
let idx = binarySearchBounds.ge(comments, rangeStart, compare);
/** @type {Comment[]} */
let commentsInRange = [];
while (this.comments[idx] && this.comments[idx].range[1] <= rangeEnd) {
commentsInRange.push(this.comments[idx]);
while (
comments[idx] &&
/** @type {Range} */ (comments[idx].range)[1] <= rangeEnd
) {
commentsInRange.push(comments[idx]);
idx++;
}
@ -4184,14 +4293,17 @@ class JavascriptParser extends Parser {
if (currentStatement === undefined) throw new Error("Not in statement");
return (
// Either asking directly for the end position of the current statement
(currentStatement.range[1] === pos && this.semicolons.has(pos)) ||
(currentStatement.range[1] === pos &&
/** @type {Set<number>} */ (this.semicolons).has(pos)) ||
// Or asking for the start position of the current statement,
// here we have to check multiple things
(currentStatement.range[0] === pos &&
// is there a previous statement which might be relevant?
this.prevStatement !== undefined &&
// is the end position of the previous statement an ASI position?
this.semicolons.has(this.prevStatement.range[1]))
/** @type {Set<number>} */ (this.semicolons).has(
this.prevStatement.range[1]
))
);
}
@ -4200,7 +4312,7 @@ class JavascriptParser extends Parser {
* @returns {void}
*/
unsetAsiPosition(pos) {
this.semicolons.delete(pos);
/** @type {Set<number>} */ (this.semicolons).delete(pos);
}
/**
@ -4216,6 +4328,11 @@ class JavascriptParser extends Parser {
);
}
/**
* @param {string} name name
* @param {TODO} tag tag info
* @returns {TODO} tag data
*/
getTagData(name, tag) {
const info = this.scope.definitions.get(name);
if (info instanceof VariableInfo) {
@ -4227,6 +4344,11 @@ class JavascriptParser extends Parser {
}
}
/**
* @param {string} name name
* @param {TODO} tag tag info
* @param {TODO} data data
*/
tagVariable(name, tag, data) {
const oldInfo = this.scope.definitions.get(name);
/** @type {VariableInfo} */
@ -4376,11 +4498,11 @@ class JavascriptParser extends Parser {
if (expr.computed) {
if (expr.property.type !== "Literal") break;
members.push(`${expr.property.value}`); // the literal
memberRanges.push(expr.object.range); // the range of the expression fragment before the literal
memberRanges.push(/** @type {Range} */ (expr.object.range)); // the range of the expression fragment before the literal
} else {
if (expr.property.type !== "Identifier") break;
members.push(expr.property.name); // the identifier
memberRanges.push(expr.object.range); // the range of the expression fragment before the identifier
memberRanges.push(/** @type {Range} */ (expr.object.range)); // the range of the expression fragment before the identifier
}
membersOptionals.push(expr.optional);
expr = expr.object;

View File

@ -88,7 +88,11 @@ const mangleExportsInfo = (deterministic, exportsInfo, isNamespace) => {
used === UsageState.OnlyPropertiesUsed ||
used === UsageState.Unused
) {
mangleExportsInfo(deterministic, exportInfo.exportsInfo, false);
mangleExportsInfo(
deterministic,
/** @type {ExportsInfo} */ (exportInfo.exportsInfo),
false
);
}
}
}