1
0
Fork 0
mirror of https://github.com/webpack/webpack.git synced 2024-07-13 05:26:47 +02:00

add guards support in JavascriptParser

This commit is contained in:
Ivan Kopeykin 2022-03-08 13:53:20 +03:00
parent 86a8bd9618
commit 9925ea24e5
11 changed files with 517 additions and 76 deletions

View file

@ -0,0 +1,36 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
const makeSerializable = require("../util/makeSerializable");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
const NullDependency = require("./NullDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/**
* Dependency just for export presence import specifier.
*/
class HarmonyExportPresenceImportSpecifierDependency extends HarmonyImportSpecifierDependency {
get type() {
return "export presence harmony import specifier";
}
}
makeSerializable(
HarmonyExportPresenceImportSpecifierDependency,
"webpack/lib/dependencies/HarmonyExportPresenceImportSpecifierDependency"
);
HarmonyExportPresenceImportSpecifierDependency.Template =
/** @type {any} can't cast to HarmonyImportSpecifierDependency.Template */ (
NullDependency.Template
);
module.exports = HarmonyExportPresenceImportSpecifierDependency;

View file

@ -11,6 +11,7 @@ const ConstDependency = require("./ConstDependency");
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
const HarmonyEvaluatedImportSpecifierDependency = require("./HarmonyEvaluatedImportSpecifierDependency");
const HarmonyExportPresenceImportSpecifierDependency = require("./HarmonyExportPresenceImportSpecifierDependency");
const HarmonyExports = require("./HarmonyExports");
const { ExportPresenceModes } = require("./HarmonyImportDependency");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
@ -96,6 +97,34 @@ module.exports = class HarmonyImportDependencyParserPlugin {
return node;
}
/**
* @param {string[]} ids ids
* @returns {string} guard name
*/
const createGuard = ids => ids.join(".");
/**
* @param {string} guard guard
* @param {number} idsLength ids length
* @returns {number} mode
*/
const detectExportPresenceMode = (guard, idsLength) => {
if (
exportPresenceMode === ExportPresenceModes.NONE ||
// namespace objects are safe to use
idsLength === 0 ||
parser.scope.guards.has(guard) ||
// if possible guard is in guard position,
// it is guarded by member chain minus one element. e.g.
// if (a && a.b) {} or if (a && "c" in a.b) {}
// a.b is guarded by a
(parser.scope.inGuardPosition &&
(idsLength === 1 ||
parser.scope.guards.has(guard.slice(0, guard.lastIndexOf(".")))))
)
return ExportPresenceModes.NONE;
return exportPresenceMode;
};
parser.hooks.isPure
.for("Identifier")
.tap("HarmonyImportDependencyParserPlugin", expression => {
@ -147,53 +176,137 @@ module.exports = class HarmonyImportDependencyParserPlugin {
parser.hooks.binaryExpression.tap(
"HarmonyImportDependencyParserPlugin",
expression => {
if (expression.operator !== "in") return;
if (expression.operator === "in") {
const leftPartEvaluated = parser.evaluateExpression(expression.left);
if (!leftPartEvaluated || leftPartEvaluated.couldHaveSideEffects())
return;
const leftPart = leftPartEvaluated.asString();
if (!leftPart) return;
const leftPartEvaluated = parser.evaluateExpression(expression.left);
if (leftPartEvaluated.couldHaveSideEffects()) return;
const leftPart = leftPartEvaluated.asString();
if (!leftPart) return;
const rightPart = parser.evaluateExpression(expression.right);
if (!rightPart || !rightPart.isIdentifier()) return;
const rightPart = parser.evaluateExpression(expression.right);
if (!rightPart.isIdentifier()) return;
const rootInfo = rightPart.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
const settings = rootInfo.tagInfo.data;
const members = rightPart.getMembers();
const baseIds = settings.ids.concat(members);
const ids = baseIds.concat([leftPart]);
const dep = new HarmonyEvaluatedImportSpecifierDependency(
settings.source,
settings.sourceOrder,
ids,
settings.name,
expression.range,
settings.assertions,
"in"
);
dep.directImport = members.length === 0;
dep.asiSafe = !parser.isAsiPosition(expression.range[0]);
dep.loc = expression.loc;
parser.state.module.addDependency(dep);
InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
const rootInfo = rightPart.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
const settings = rootInfo.tagInfo.data;
const members = rightPart.getMembers();
const dep = new HarmonyEvaluatedImportSpecifierDependency(
settings.source,
settings.sourceOrder,
settings.ids.concat(members).concat([leftPart]),
settings.name,
expression.range,
settings.assertions,
"in"
);
dep.directImport = members.length === 0;
dep.asiSafe = !parser.isAsiPosition(expression.range[0]);
dep.loc = expression.loc;
parser.state.module.addDependency(dep);
InnerGraph.onUsage(parser.state, e => (dep.usedByExports = e));
return true;
if (parser.scope.inGuardPosition) {
parser.scope.guards.add(createGuard(ids));
// namespace objects and identifiers are safe to use
if (baseIds.length > 1) {
// check for export presence for right side expression
const mode = detectExportPresenceMode(
createGuard(baseIds),
baseIds.length
);
// e.g if ("a" in b.c) {}
// here "b.c" is not guarded by "b"
if (mode !== ExportPresenceModes.NONE) {
const dep = new HarmonyExportPresenceImportSpecifierDependency(
settings.source,
settings.sourceOrder,
baseIds,
settings.name,
rightPart.expression.range,
mode,
settings.assertions
);
dep.loc = rightPart.expression.loc;
parser.state.module.addDependency(dep);
}
}
}
return true;
} else if (expression.operator === "!=") {
if (!parser.scope.inGuardPosition) return;
let identifierEvaluated;
const leftPartEvaluated = parser.evaluateExpression(expression.left);
if (!leftPartEvaluated) {
return;
} else if (leftPartEvaluated.isIdentifier()) {
const rootInfo = leftPartEvaluated.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
identifierEvaluated = leftPartEvaluated;
} else if (leftPartEvaluated.isFalsy() !== true) {
return;
}
const rightPartEvaluated = parser.evaluateExpression(
expression.right
);
if (!rightPartEvaluated) {
return;
} else if (
!identifierEvaluated &&
rightPartEvaluated.isIdentifier()
) {
const rootInfo = rightPartEvaluated.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
identifierEvaluated = rightPartEvaluated;
} else if (rightPartEvaluated.isFalsy() !== true) {
return;
}
// other hooks will add guards and dependencies
parser.walkExpression(identifierEvaluated.expression);
return true;
}
}
);
parser.hooks.expression
.for(harmonySpecifierTag)
.tap("HarmonyImportDependencyParserPlugin", expr => {
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
let exportPresenceModeComputed;
// namespace object is safe to use
if (settings.ids.length) {
const guard = createGuard(settings.ids);
exportPresenceModeComputed = detectExportPresenceMode(
guard,
settings.ids.length
);
if (parser.scope.inGuardPosition) parser.scope.guards.add(guard);
}
const dep = new HarmonyImportSpecifierDependency(
settings.source,
settings.sourceOrder,
settings.ids,
settings.name,
expr.range,
exportPresenceMode,
exportPresenceModeComputed || ExportPresenceModes.NONE,
settings.assertions
);
dep.shorthand = parser.scope.inShorthand;
@ -224,6 +337,12 @@ module.exports = class HarmonyImportDependencyParserPlugin {
)
: expression;
const ids = settings.ids.concat(nonOptionalMembers);
const guard = createGuard(ids);
const exportPresenceMode = detectExportPresenceMode(
guard,
ids.length
);
if (parser.scope.inGuardPosition) parser.scope.guards.add(guard);
const dep = new HarmonyImportSpecifierDependency(
settings.source,
settings.sourceOrder,
@ -267,7 +386,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
ids,
settings.name,
expr.range,
exportPresenceMode,
detectExportPresenceMode(createGuard(ids), ids.length),
settings.assertions
);
dep.directImport = members.length === 0;

View file

@ -12,6 +12,7 @@ const HarmonyEvaluatedImportSpecifierDependency = require("./HarmonyEvaluatedImp
const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency");
const HarmonyExportPresenceImportSpecifierDependency = require("./HarmonyExportPresenceImportSpecifierDependency");
const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
@ -69,6 +70,15 @@ class HarmonyModulesPlugin {
new HarmonyEvaluatedImportSpecifierDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyExportPresenceImportSpecifierDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyExportPresenceImportSpecifierDependency,
new HarmonyExportPresenceImportSpecifierDependency.Template()
);
compilation.dependencyTemplates.set(
HarmonyExportHeaderDependency,
new HarmonyExportHeaderDependency.Template()

View file

@ -301,18 +301,22 @@ class BasicEvaluatedExpression {
this.type = TypeString;
this.string = string;
this.sideEffects = false;
if (string === "") this.falsy = true;
else this.truthy = true;
return this;
}
setUndefined() {
this.type = TypeUndefined;
this.sideEffects = false;
this.falsy = true;
return this;
}
setNull() {
this.type = TypeNull;
this.sideEffects = false;
this.falsy = true;
return this;
}
@ -320,6 +324,8 @@ class BasicEvaluatedExpression {
this.type = TypeNumber;
this.number = number;
this.sideEffects = false;
if (number === 0) this.falsy = true;
else this.truthy = true;
return this;
}
@ -327,6 +333,8 @@ class BasicEvaluatedExpression {
this.type = TypeBigInt;
this.bigint = bigint;
this.sideEffects = false;
if (bigint === BigInt(0)) this.falsy = true;
else this.truthy = true;
return this;
}
@ -334,6 +342,8 @@ class BasicEvaluatedExpression {
this.type = TypeBoolean;
this.bool = bool;
this.sideEffects = false;
if (bool === false) this.falsy = true;
else this.truthy = true;
return this;
}
@ -341,6 +351,7 @@ class BasicEvaluatedExpression {
this.type = TypeRegExp;
this.regExp = regExp;
this.sideEffects = false;
this.truthy = true;
return this;
}

View file

@ -11,6 +11,7 @@ const { SyncBailHook, HookMap } = require("tapable");
const vm = require("vm");
const Parser = require("../Parser");
const StackedMap = require("../util/StackedMap");
const WriteOnlyStackedSet = require("../util/WriteOnlyStackedSet");
const binarySearchBounds = require("../util/binarySearchBounds");
const memoize = require("../util/memoize");
const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
@ -95,11 +96,13 @@ class VariableInfo {
/**
* @typedef {Object} ScopeInfo
* @property {StackedMap<string, VariableInfo | ScopeInfo>} definitions
* @property {WriteOnlyStackedSet<string>} guards
* @property {boolean | "arrow"} topLevelScope
* @property {boolean} inShorthand
* @property {boolean} isStrict
* @property {boolean} isAsmJs
* @property {boolean} inTry
* @property {boolean} inGuardPosition
*/
const joinRanges = (startRange, endRange) => {
@ -1648,8 +1651,11 @@ class JavascriptParser extends Parser {
walkIfStatement(statement) {
const result = this.hooks.statementIf.call(statement);
if (result === undefined) {
this.walkExpression(statement.test);
const oldGuard = this.scope.guards;
this.scope.guards = oldGuard.createChild();
this.inGuardPosition(() => this.walkExpression(statement.test), true);
this.walkNestedStatement(statement.consequent);
this.scope.guards = oldGuard;
if (statement.alternate) {
this.walkNestedStatement(statement.alternate);
}
@ -2318,12 +2324,15 @@ class JavascriptParser extends Parser {
walkAwaitExpression(expression) {
if (this.scope.topLevelScope === true)
this.hooks.topLevelAwait.call(expression);
this.walkExpression(expression.argument);
this.inGuardPosition(() => this.walkExpression(expression.argument), false);
}
walkArrayExpression(expression) {
if (expression.elements) {
this.walkExpressions(expression.elements);
this.inGuardPosition(
() => this.walkExpressions(expression.elements),
false
);
}
}
@ -2340,7 +2349,7 @@ class JavascriptParser extends Parser {
propIndex++
) {
const prop = expression.properties[propIndex];
this.walkProperty(prop);
this.inGuardPosition(() => this.walkProperty(prop), false);
}
}
@ -2424,17 +2433,20 @@ class JavascriptParser extends Parser {
const old = this.statementPath.pop();
for (const expr of expression.expressions) {
this.statementPath.push(expr);
this.walkExpression(expr);
this.inGuardPosition(() => this.walkExpression(expr), false);
this.statementPath.pop();
}
this.statementPath.push(old);
} else {
this.walkExpressions(expression.expressions);
this.inGuardPosition(
() => this.walkExpressions(expression.expressions),
false
);
}
}
walkUpdateExpression(expression) {
this.walkExpression(expression.argument);
this.inGuardPosition(() => this.walkExpression(expression.argument), false);
}
walkUnaryExpression(expression) {
@ -2454,7 +2466,7 @@ class JavascriptParser extends Parser {
if (result === true) return;
}
}
this.walkExpression(expression.argument);
this.inGuardPosition(() => this.walkExpression(expression.argument), false);
}
walkLeftRightExpression(expression) {
@ -2464,14 +2476,27 @@ class JavascriptParser extends Parser {
walkBinaryExpression(expression) {
if (this.hooks.binaryExpression.call(expression) === undefined) {
this.walkLeftRightExpression(expression);
this.inGuardPosition(
() => this.walkLeftRightExpression(expression),
false
);
}
}
/**
* @param {LogicalExpressionNode} expression expression
*/
walkLogicalExpression(expression) {
const result = this.hooks.expressionLogicalOperator.call(expression);
if (result === undefined) {
this.walkLeftRightExpression(expression);
if (expression.operator === "&&") {
this.walkLeftRightExpression(expression);
} else {
this.inGuardPosition(
() => this.walkLeftRightExpression(expression),
false
);
}
} else {
if (result) {
this.walkExpression(expression.right);
@ -2552,8 +2577,11 @@ class JavascriptParser extends Parser {
walkConditionalExpression(expression) {
const result = this.hooks.expressionConditionalOperator.call(expression);
if (result === undefined) {
this.walkExpression(expression.test);
const oldGuard = this.scope.guards;
this.scope.guards = oldGuard.createChild();
this.inGuardPosition(() => this.walkExpression(expression.test), true);
this.walkExpression(expression.consequent);
this.scope.guards = oldGuard;
if (expression.alternate) {
this.walkExpression(expression.alternate);
}
@ -2573,31 +2601,41 @@ class JavascriptParser extends Parser {
expression
);
if (result === true) return;
this.walkExpression(expression.callee);
if (expression.arguments) {
this.walkExpressions(expression.arguments);
}
this.inGuardPosition(() => {
this.walkExpression(expression.callee);
if (expression.arguments) {
this.walkExpressions(expression.arguments);
}
}, false);
}
walkYieldExpression(expression) {
if (expression.argument) {
this.walkExpression(expression.argument);
this.inGuardPosition(
() => this.walkExpression(expression.argument),
false
);
}
}
walkTemplateLiteral(expression) {
if (expression.expressions) {
this.walkExpressions(expression.expressions);
this.inGuardPosition(
() => this.walkExpressions(expression.expressions),
false
);
}
}
walkTaggedTemplateExpression(expression) {
if (expression.tag) {
this.walkExpression(expression.tag);
}
if (expression.quasi && expression.quasi.expressions) {
this.walkExpressions(expression.quasi.expressions);
}
this.inGuardPosition(() => {
if (expression.tag) {
this.walkExpression(expression.tag);
}
if (expression.quasi && expression.quasi.expressions) {
this.walkExpressions(expression.quasi.expressions);
}
}, false);
}
walkClassExpression(expression) {
@ -2687,7 +2725,7 @@ class JavascriptParser extends Parser {
let result = this.hooks.importCall.call(expression);
if (result === true) return;
this.walkExpression(expression.source);
this.inGuardPosition(() => this.walkExpression(expression.source), false);
}
walkCallExpression(expression) {
@ -2753,17 +2791,19 @@ class JavascriptParser extends Parser {
if (result2 === true) return;
}
if (expression.callee) {
if (expression.callee.type === "MemberExpression") {
// because of call context we need to walk the call context as expression
this.walkExpression(expression.callee.object);
if (expression.callee.computed === true)
this.walkExpression(expression.callee.property);
} else {
this.walkExpression(expression.callee);
this.inGuardPosition(() => {
if (expression.callee) {
if (expression.callee.type === "MemberExpression") {
// because of call context we need to walk the call context as expression
this.walkExpression(expression.callee.object);
if (expression.callee.computed === true)
this.walkExpression(expression.callee.property);
} else {
this.walkExpression(expression.callee);
}
}
}
if (expression.arguments) this.walkExpressions(expression.arguments);
if (expression.arguments) this.walkExpressions(expression.arguments);
}, false);
}
}
@ -3025,6 +3065,17 @@ class JavascriptParser extends Parser {
);
}
/**
* @param {Function} fn function
* @param {boolean} state guard position state
*/
inGuardPosition(fn, state) {
const old = this.scope.inGuardPosition;
this.scope.inGuardPosition = state;
fn();
this.scope.inGuardPosition = old;
}
/**
* @deprecated
* @param {any} params scope params
@ -3036,10 +3087,12 @@ class JavascriptParser extends Parser {
this.scope = {
topLevelScope: oldScope.topLevelScope,
inTry: false,
inGuardPosition: false,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
definitions: oldScope.definitions.createChild(),
guards: oldScope.guards.createChild()
};
this.undefineVariable("this");
@ -3058,10 +3111,12 @@ class JavascriptParser extends Parser {
this.scope = {
topLevelScope: oldScope.topLevelScope,
inTry: false,
inGuardPosition: false,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
definitions: oldScope.definitions.createChild(),
guards: oldScope.guards.createChild()
};
if (hasThis) {
@ -3082,10 +3137,12 @@ class JavascriptParser extends Parser {
this.scope = {
topLevelScope: oldScope.topLevelScope,
inTry: oldScope.inTry,
inGuardPosition: false,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
definitions: oldScope.definitions.createChild(),
guards: oldScope.guards.createChild()
};
fn();
@ -3333,10 +3390,12 @@ class JavascriptParser extends Parser {
this.scope = {
topLevelScope: true,
inTry: false,
inGuardPosition: false,
inShorthand: false,
isStrict: false,
isAsmJs: false,
definitions: new StackedMap()
definitions: new StackedMap(),
guards: new WriteOnlyStackedSet()
};
/** @type {ParserState} */
this.state = state;

View file

@ -0,0 +1,49 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Ivan Kopeykin @vankop
*/
"use strict";
/**
* @template T
*/
class WriteOnlyStackedSet {
constructor(sets = []) {
this._sets = sets;
this._current = undefined;
}
/**
* @param {T} el element
*/
add(el) {
if (!this._current) {
this._current = new Set();
this._sets.push(this._current);
}
this._current.add(el);
}
/**
* @param {T} el element
* @returns {boolean} result
*/
has(el) {
for (const set of this._sets) {
if (set.has(el)) return true;
}
return false;
}
clear() {
this._sets = [];
if (this._current) this._current.clear();
}
createChild() {
return new WriteOnlyStackedSet(this._sets.length ? this._sets.slice() : []);
}
}
module.exports = WriteOnlyStackedSet;

View file

@ -105,6 +105,8 @@ module.exports = {
require("../dependencies/HarmonyImportSpecifierDependency"),
"dependencies/HarmonyEvaluatedImportSpecifierDependency": () =>
require("../dependencies/HarmonyEvaluatedImportSpecifierDependency"),
"dependencies/HarmonyExportPresenceImportSpecifierDependency": () =>
require("../dependencies/HarmonyExportPresenceImportSpecifierDependency"),
"dependencies/ImportContextDependency": () =>
require("../dependencies/ImportContextDependency"),
"dependencies/ImportDependency": () =>

View file

@ -1,7 +1,93 @@
import { NotHere as aaa } from "./aaa/index.js";
import { NotHere as bbb } from "./bbb/index.js";
import { NotHere as ccc } from "./ccc/index.js";
import { NotHere as ddd } from "./ddd/index.js";
import { NotHere as aaa, /* not here */ a } from "./aaa/index.js";
import { NotHere as bbb, /* not here */ b } from "./bbb/index.js";
import { NotHere as ccc, /* not here */ c } from "./ccc/index.js";
import { NotHere as ddd, /* not here */ d } from "./ddd/index.js";
import * as m from "./module";
const val1 = Math.random();
function throw_() {
throw new Error();
}
function justFunction() {}
describe("should not add additional warnings/errors", () => {
it("simple cases", () => {
if (b) {
if (d) d();
b();
if (c) {
b();
}
}
(false && d);
(d ? d() : throw_());
// should add 2 warnings
if (a && val1 || true) {
a();
}
if (a && a.b && a.b.c) {
a();
}
// only one warning
if (a.b.c) {
a.b.c();
}
});
it("different expressions", () => {
if (a && a.b.c) {}
// should add warning (function scope)
if ((() => a())()) {}
// should add warning (unary expression)
if (!a && b) {}
// should add warning (binary expression)
if (a & true) {}
function *foo() {
// should add warning (yield expression)
if (yield a && true) {}
}
async function foo1() {
// should add warning (yield expression)
if (await a && true) {}
}
let var1;
if (var1 = b) {}
if ((var1 = b) && c && c.a) {}
// should add warning
if (justFunction`${a}`) {}
if (`${a}`) {}
});
it("in operator", () => {
if ("a" in m) { justFunction(m.a); }
if ("b" in m && "c" in m.b) { justFunction(m.b.c); }
if ("c" in m) { justFunction(m.c); }
// should add one warning
if ("a"in d.c) { justFunction(d.c.a()); }
});
it("identifier != falsy", () => {
if (c != false) {}
// should add warning since value could be undefined !== false
if (c !== false) {}
if (c != null && c.a != undefined && c.a.b != false && 0 != c.a.b.c && "" != c.a.b.c.d) {
c();
c.a();
c().a;
{
c.a.b();
const a = () => c.a.b.c.d();
const b = function () {
c.a.b.c.d();
}
}
}
// should add 2 warnings
if (c != undefined ?? undefined != c) {}
});
});
it("should do nothing", () => {
expect(aaa).toBe(undefined);

View file

@ -10,5 +10,65 @@ module.exports = [
{
moduleName: /ddd/,
message: /NoNo.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /a.+not found/
},
{
moduleName: /index/,
message: /d.+not found/
},
{
moduleName: /index/,
message: /c.+not found/
},
{
moduleName: /index/,
message: /c.+not found/
},
{
moduleName: /index/,
message: /c.+not found/
}
];

11
types.d.ts vendored
View file

@ -5271,7 +5271,7 @@ declare class JavascriptParser extends Parser {
walkUnaryExpression(expression?: any): void;
walkLeftRightExpression(expression?: any): void;
walkBinaryExpression(expression?: any): void;
walkLogicalExpression(expression?: any): void;
walkLogicalExpression(expression: LogicalExpression): void;
walkAssignmentExpression(expression?: any): void;
walkConditionalExpression(expression?: any): void;
walkNewExpression(expression?: any): void;
@ -5329,6 +5329,7 @@ declare class JavascriptParser extends Parser {
defined: () => any,
...args: AsArray<T>
): R;
inGuardPosition(fn: Function, state: boolean): void;
inScope(params: any, fn: () => void): void;
inFunctionScope(hasThis?: any, params?: any, fn?: any): void;
inBlockScope(fn?: any): void;
@ -10729,11 +10730,13 @@ declare interface RuntimeValueOptions {
}
declare interface ScopeInfo {
definitions: StackedMap<string, ScopeInfo | VariableInfo>;
guards: WriteOnlyStackedSet<string>;
topLevelScope: boolean | "arrow";
inShorthand: boolean;
isStrict: boolean;
isAsmJs: boolean;
inTry: boolean;
inGuardPosition: boolean;
}
declare interface Selector<A, B> {
(input: A): B;
@ -12478,6 +12481,12 @@ declare interface WithOptions {
declare interface WriteOnlySet<T> {
add: (T?: any) => void;
}
declare abstract class WriteOnlyStackedSet<T> {
add(el: T): void;
has(el: T): boolean;
clear(): void;
createChild(): WriteOnlyStackedSet<any>;
}
type __TypeWebpackOptions = (data: object) =>
| string
| {