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

View File

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

View File

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

View File

@ -14,11 +14,20 @@ const ExternalModuleInitFragment = require("./ExternalModuleInitFragment");
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */ /** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */ /** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */ /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */ /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../util/Hash")} Hash */ /** @typedef {import("../util/Hash")} Hash */
class ExternalModuleDependency extends CachedConstDependency { 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( constructor(
module, module,
importSpecifiers, importSpecifiers,

View File

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

View File

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

View File

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