Skip to content

Commit dc79e95

Browse files
authored
fix: collect only specific expressions for destructuring assignment
1 parent 90ae8af commit dc79e95

File tree

7 files changed

+133
-47
lines changed

7 files changed

+133
-47
lines changed

lib/DefinePlugin.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,13 @@ class DefinePlugin {
489489
if (nested && !hooked.has(nested)) {
490490
// only detect the same nested key once
491491
hooked.add(nested);
492+
parser.hooks.collectDestructuringAssignmentProperties.tap(
493+
PLUGIN_NAME,
494+
(expr) => {
495+
const nameInfo = parser.getNameForExpression(expr);
496+
if (nameInfo && nameInfo.name === nested) return true;
497+
}
498+
);
492499
parser.hooks.expression.for(nested).tap(
493500
{
494501
name: PLUGIN_NAME,
@@ -687,6 +694,13 @@ class DefinePlugin {
687694
PLUGIN_NAME,
688695
withValueDependency(key, evaluateToString("object"))
689696
);
697+
parser.hooks.collectDestructuringAssignmentProperties.tap(
698+
PLUGIN_NAME,
699+
(expr) => {
700+
const nameInfo = parser.getNameForExpression(expr);
701+
if (nameInfo && nameInfo.name === key) return true;
702+
}
703+
);
690704
parser.hooks.expression.for(key).tap(PLUGIN_NAME, (expr) => {
691705
addValueDependency(key);
692706
let strCode = stringifyObj(

lib/dependencies/HarmonyImportDependencyParserPlugin.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
const CommentCompilationWarning = require("../CommentCompilationWarning");
99
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
1010
const WebpackError = require("../WebpackError");
11-
const { getImportAttributes } = require("../javascript/JavascriptParser");
11+
const {
12+
VariableInfo,
13+
getImportAttributes
14+
} = require("../javascript/JavascriptParser");
1215
const InnerGraph = require("../optimize/InnerGraph");
1316
const ConstDependency = require("./ConstDependency");
1417
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
@@ -211,6 +214,20 @@ module.exports = class HarmonyImportDependencyParserPlugin {
211214
InnerGraph.onUsage(parser.state, (e) => (dep.usedByExports = e));
212215
return true;
213216
});
217+
parser.hooks.collectDestructuringAssignmentProperties.tap(
218+
PLUGIN_NAME,
219+
(expr) => {
220+
const nameInfo = parser.getNameForExpression(expr);
221+
if (
222+
nameInfo &&
223+
nameInfo.rootInfo instanceof VariableInfo &&
224+
nameInfo.rootInfo.name &&
225+
parser.getTagData(nameInfo.rootInfo.name, harmonySpecifierTag)
226+
) {
227+
return true;
228+
}
229+
}
230+
);
214231
parser.hooks.expression
215232
.for(harmonySpecifierTag)
216233
.tap(PLUGIN_NAME, (expr) => {

lib/dependencies/ImportMetaPlugin.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ class ImportMetaPlugin {
9696
PLUGIN_NAME,
9797
toConstantDependency(parser, JSON.stringify("object"))
9898
);
99+
parser.hooks.collectDestructuringAssignmentProperties.tap(
100+
PLUGIN_NAME,
101+
(expr) => {
102+
if (expr.type === "MetaProperty") return true;
103+
}
104+
);
99105
parser.hooks.expression
100106
.for("import.meta")
101107
.tap(PLUGIN_NAME, (metaProperty) => {

lib/dependencies/ImportParserPlugin.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ class ImportParserPlugin {
4646
*/
4747
const exportsFromEnumerable = (enumerable) =>
4848
Array.from(enumerable, (e) => [e]);
49+
parser.hooks.collectDestructuringAssignmentProperties.tap(
50+
PLUGIN_NAME,
51+
(expr) => {
52+
if (expr.type === "ImportExpression") return true;
53+
}
54+
);
4955
parser.hooks.importCall.tap(PLUGIN_NAME, (expr) => {
5056
const param = parser.evaluateExpression(expr.source);
5157

lib/javascript/JavascriptParser.js

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,10 @@ class JavascriptParser extends Parser {
522522
varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])),
523523
/** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
524524
pattern: new HookMap(() => new SyncBailHook(["pattern"])),
525+
/** @type {SyncBailHook<[Expression], boolean | void>} */
526+
collectDestructuringAssignmentProperties: new SyncBailHook([
527+
"expression"
528+
]),
525529
/** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
526530
canRename: new HookMap(() => new SyncBailHook(["initExpression"])),
527531
/** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
@@ -2607,34 +2611,48 @@ class JavascriptParser extends Parser {
26072611
* @param {AssignmentExpression} expression assignment expression
26082612
*/
26092613
preWalkAssignmentExpression(expression) {
2614+
this.enterDestructuringAssignment(expression.left, expression.right);
2615+
}
2616+
2617+
/**
2618+
* @param {Pattern} pattern pattern
2619+
* @param {Expression} expression assignment expression
2620+
* @returns {Expression | undefined} destructuring expression
2621+
*/
2622+
enterDestructuringAssignment(pattern, expression) {
26102623
if (
2611-
expression.left.type !== "ObjectPattern" ||
2624+
pattern.type !== "ObjectPattern" ||
26122625
!this.destructuringAssignmentProperties
26132626
) {
26142627
return;
26152628
}
2616-
const keys = this._preWalkObjectPattern(expression.left);
2617-
if (!keys) return;
2618-
2619-
// check multiple assignments
2620-
if (this.destructuringAssignmentProperties.has(expression)) {
2621-
const set =
2622-
/** @type {Set<DestructuringAssignmentProperty>} */
2623-
(this.destructuringAssignmentProperties.get(expression));
2624-
this.destructuringAssignmentProperties.delete(expression);
2625-
for (const id of set) keys.add(id);
2626-
}
26272629

2628-
this.destructuringAssignmentProperties.set(
2629-
expression.right.type === "AwaitExpression"
2630-
? expression.right.argument
2631-
: expression.right,
2632-
keys
2633-
);
2630+
const expr =
2631+
expression.type === "AwaitExpression" ? expression.argument : expression;
2632+
2633+
const destructuring =
2634+
expr.type === "AssignmentExpression"
2635+
? this.enterDestructuringAssignment(expr.left, expr.right)
2636+
: this.hooks.collectDestructuringAssignmentProperties.call(expr)
2637+
? expr
2638+
: undefined;
2639+
2640+
if (destructuring) {
2641+
const keys = this._preWalkObjectPattern(pattern);
2642+
if (!keys) return;
26342643

2635-
if (expression.right.type === "AssignmentExpression") {
2636-
this.preWalkAssignmentExpression(expression.right);
2644+
// check multiple assignments
2645+
if (this.destructuringAssignmentProperties.has(destructuring)) {
2646+
const set =
2647+
/** @type {Set<DestructuringAssignmentProperty>} */
2648+
(this.destructuringAssignmentProperties.get(destructuring));
2649+
for (const id of keys) set.add(id);
2650+
} else {
2651+
this.destructuringAssignmentProperties.set(destructuring, keys);
2652+
}
26372653
}
2654+
2655+
return destructuring;
26382656
}
26392657

26402658
/**
@@ -2995,25 +3013,8 @@ class JavascriptParser extends Parser {
29953013
* @param {VariableDeclarator} declarator variable declarator
29963014
*/
29973015
preWalkVariableDeclarator(declarator) {
2998-
if (
2999-
!declarator.init ||
3000-
declarator.id.type !== "ObjectPattern" ||
3001-
!this.destructuringAssignmentProperties
3002-
) {
3003-
return;
3004-
}
3005-
const keys = this._preWalkObjectPattern(declarator.id);
3006-
3007-
if (!keys) return;
3008-
this.destructuringAssignmentProperties.set(
3009-
declarator.init.type === "AwaitExpression"
3010-
? declarator.init.argument
3011-
: declarator.init,
3012-
keys
3013-
);
3014-
3015-
if (declarator.init.type === "AssignmentExpression") {
3016-
this.preWalkAssignmentExpression(declarator.init);
3016+
if (declarator.init) {
3017+
this.enterDestructuringAssignment(declarator.id, declarator.init);
30173018
}
30183019
}
30193020

@@ -5179,7 +5180,7 @@ class JavascriptParser extends Parser {
51795180
}
51805181

51815182
/**
5182-
* @param {MemberExpression} expression an expression
5183+
* @param {Expression} expression an expression
51835184
* @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => string[]} | undefined} name info
51845185
*/
51855186
getNameForExpression(expression) {

test/cases/esm/import-meta/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,16 @@ it("should add warning on direct import.meta usage", () => {
4848
expect(Object.keys(import.meta)).toHaveLength(0);
4949
});
5050

51-
it("should support destructuring assignment", () => {
51+
it("should support destructuring assignment", async () => {
5252
let version, url2, c;
5353
({ webpack: version } = { url: url2 } = { c } = import.meta);
5454
expect(version).toBeTypeOf("number");
5555
expect(url2).toBe(url);
5656
expect(c).toBe(undefined);
57+
58+
let version2, url3, d;
59+
({ webpack: version2 } = await ({ url: url3 } = ({ d } = await import.meta)));
60+
expect(version2).toBeTypeOf("number");
61+
expect(url3).toBe(url);
62+
expect(d).toBe(undefined);
5763
});

types.d.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,12 @@ declare abstract class BasicEvaluatedExpression {
663663
| MethodDefinition
664664
| PropertyDefinition
665665
| VariableDeclarator
666-
| SwitchCase
667-
| CatchClause
668666
| ObjectPattern
669667
| ArrayPattern
670668
| RestElement
671669
| AssignmentPattern
670+
| SwitchCase
671+
| CatchClause
672672
| Property
673673
| AssignmentProperty
674674
| ClassBody
@@ -894,12 +894,12 @@ declare abstract class BasicEvaluatedExpression {
894894
| MethodDefinition
895895
| PropertyDefinition
896896
| VariableDeclarator
897-
| SwitchCase
898-
| CatchClause
899897
| ObjectPattern
900898
| ArrayPattern
901899
| RestElement
902900
| AssignmentPattern
901+
| SwitchCase
902+
| CatchClause
903903
| Property
904904
| AssignmentProperty
905905
| ClassBody
@@ -6855,6 +6855,10 @@ declare class JavascriptParser extends ParserClass {
68556855
varDeclarationUsing: HookMap<SyncBailHook<[Identifier], boolean | void>>;
68566856
varDeclarationVar: HookMap<SyncBailHook<[Identifier], boolean | void>>;
68576857
pattern: HookMap<SyncBailHook<[Identifier], boolean | void>>;
6858+
collectDestructuringAssignmentProperties: SyncBailHook<
6859+
[Expression],
6860+
boolean | void
6861+
>;
68586862
canRename: HookMap<SyncBailHook<[Expression], boolean | void>>;
68596863
rename: HookMap<SyncBailHook<[Expression], boolean | void>>;
68606864
assign: HookMap<SyncBailHook<[AssignmentExpression], boolean | void>>;
@@ -7329,6 +7333,38 @@ declare class JavascriptParser extends ParserClass {
73297333
): void;
73307334
blockPreWalkExpressionStatement(statement: ExpressionStatement): void;
73317335
preWalkAssignmentExpression(expression: AssignmentExpression): void;
7336+
enterDestructuringAssignment(
7337+
pattern: Pattern,
7338+
expression: Expression
7339+
):
7340+
| undefined
7341+
| ImportExpressionImport
7342+
| UnaryExpression
7343+
| ArrayExpression
7344+
| ArrowFunctionExpression
7345+
| AssignmentExpression
7346+
| AwaitExpression
7347+
| BinaryExpression
7348+
| SimpleCallExpression
7349+
| NewExpression
7350+
| ChainExpression
7351+
| ClassExpression
7352+
| ConditionalExpression
7353+
| FunctionExpression
7354+
| Identifier
7355+
| SimpleLiteral
7356+
| RegExpLiteral
7357+
| BigIntLiteral
7358+
| LogicalExpression
7359+
| MemberExpression
7360+
| MetaProperty
7361+
| ObjectExpression
7362+
| SequenceExpression
7363+
| TaggedTemplateExpression
7364+
| TemplateLiteral
7365+
| ThisExpression
7366+
| UpdateExpression
7367+
| YieldExpression;
73327368
modulePreWalkImportDeclaration(
73337369
statement: ImportDeclarationJavascriptParser
73347370
): void;
@@ -7874,7 +7910,7 @@ declare class JavascriptParser extends ParserClass {
78747910
allowedTypes: number
78757911
): undefined | CallExpressionInfo | ExpressionExpressionInfo;
78767912
getNameForExpression(
7877-
expression: MemberExpression
7913+
expression: Expression
78787914
):
78797915
| undefined
78807916
| {

0 commit comments

Comments
 (0)