diff --git a/lib/dependencies/HarmonyImportDependencyParserPlugin.js b/lib/dependencies/HarmonyImportDependencyParserPlugin.js index 24eb72e31b4..6fd2d50dcd7 100644 --- a/lib/dependencies/HarmonyImportDependencyParserPlugin.js +++ b/lib/dependencies/HarmonyImportDependencyParserPlugin.js @@ -212,7 +212,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { .for(harmonySpecifierTag) .tap( "HarmonyImportDependencyParserPlugin", - (expression, members, membersOptionals, memberRangeStarts) => { + (expression, members, membersOptionals, memberRanges) => { const settings = /** @type {HarmonySettings} */ ( parser.currentTagData ); @@ -220,10 +220,9 @@ module.exports = class HarmonyImportDependencyParserPlugin { members, membersOptionals ); - const rangeStarts = memberRangeStarts.slice( + const ranges = memberRanges.slice( 0, - memberRangeStarts.length - - (members.length - nonOptionalMembers.length) + memberRanges.length - (members.length - nonOptionalMembers.length) ); const expr = nonOptionalMembers !== members @@ -241,7 +240,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { expr.range, exportPresenceMode, settings.assertions, - rangeStarts + ranges ); dep.referencedPropertiesInDestructuring = parser.destructuringAssignmentPropertiesFor(expr); @@ -256,7 +255,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { .for(harmonySpecifierTag) .tap( "HarmonyImportDependencyParserPlugin", - (expression, members, membersOptionals, memberRangeStarts) => { + (expression, members, membersOptionals, memberRanges) => { const { arguments: args, callee } = expression; const settings = /** @type {HarmonySettings} */ ( parser.currentTagData @@ -265,10 +264,9 @@ module.exports = class HarmonyImportDependencyParserPlugin { members, membersOptionals ); - const rangeStarts = memberRangeStarts.slice( + const ranges = memberRanges.slice( 0, - memberRangeStarts.length - - (members.length - nonOptionalMembers.length) + memberRanges.length - (members.length - nonOptionalMembers.length) ); const expr = nonOptionalMembers !== members @@ -286,7 +284,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { expr.range, exportPresenceMode, settings.assertions, - rangeStarts + ranges ); dep.directImport = members.length === 0; dep.call = true; diff --git a/lib/dependencies/HarmonyImportSpecifierDependency.js b/lib/dependencies/HarmonyImportSpecifierDependency.js index c6ff4f3a9ea..eabff212316 100644 --- a/lib/dependencies/HarmonyImportSpecifierDependency.js +++ b/lib/dependencies/HarmonyImportSpecifierDependency.js @@ -43,7 +43,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { * @param {Range} range range * @param {TODO} exportPresenceMode export presence mode * @param {Assertions=} assertions assertions - * @param {number[]=} idRangeStarts range starts for members of ids; the two arrays are right-aligned + * @param {Range[]=} idRanges ranges for members of ids; the two arrays are right-aligned */ constructor( request, @@ -53,13 +53,13 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { range, exportPresenceMode, assertions, - idRangeStarts // TODO webpack 6 make this non-optional. It must always be set to properly trim ids. + idRanges // TODO webpack 6 make this non-optional. It must always be set to properly trim ids. ) { super(request, sourceOrder, assertions); this.ids = ids; this.name = name; this.range = range; - this.idRangeStarts = idRangeStarts; + this.idRanges = idRanges; this.exportPresenceMode = exportPresenceMode; this.namespaceObjectAsContext = false; this.call = undefined; @@ -261,7 +261,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { write(this.ids); write(this.name); write(this.range); - write(this.idRangeStarts); + write(this.idRanges); write(this.exportPresenceMode); write(this.namespaceObjectAsContext); write(this.call); @@ -281,7 +281,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { this.ids = read(); this.name = read(); this.range = read(); - this.idRangeStarts = read(); + this.idRanges = read(); this.exportPresenceMode = read(); this.namespaceObjectAsContext = read(); this.call = read(); @@ -320,15 +320,15 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen let [rangeStart, rangeEnd] = dep.range; if (trimmedIds.length !== ids.length) { - // The array returned from dep.idRangeStarts is right-aligned with the array returned from dep.getIds. + // The array returned from dep.idRanges is right-aligned with the array returned from dep.getIds. // Meaning, the two arrays may not always have the same number of elements, but the last element of - // dep.idRangeStarts corresponds to [the starting range position of] the last element of dep.getIds. - // Use this to find the correct range end position based on the number of ids that were trimmed. + // dep.idRanges corresponds to [the expression fragment to the left of] the last element of dep.getIds. + // Use this to find the correct replacement range based on the number of ids that were trimmed. const idx = - dep.idRangeStarts === undefined + dep.idRanges === undefined ? -1 /* trigger failure case below */ - : dep.idRangeStarts.length + (trimmedIds.length - ids.length); - if (idx < 0 || idx >= dep.idRangeStarts.length) { + : dep.idRanges.length + (trimmedIds.length - ids.length); + if (idx < 0 || idx >= dep.idRanges.length) { // cspell:ignore minifiers // Should not happen but we can't throw an error here because of backward compatibility with // external plugins in wp5. Instead, we just disable trimming for now. This may break some minifiers. @@ -336,7 +336,7 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen // TODO webpack 6 remove the "trimmedIds = ids" above and uncomment the following line instead. // throw new Error("Missing range starts data for id replacement trimming."); } else { - rangeEnd = dep.idRangeStarts[idx]; + [rangeStart, rangeEnd] = dep.idRanges[idx]; } } diff --git a/lib/javascript/BasicEvaluatedExpression.js b/lib/javascript/BasicEvaluatedExpression.js index 4c0bba66026..c15cd9bcfa8 100644 --- a/lib/javascript/BasicEvaluatedExpression.js +++ b/lib/javascript/BasicEvaluatedExpression.js @@ -6,6 +6,7 @@ "use strict"; /** @typedef {import("estree").Node} EsTreeNode */ +/** @typedef {import("./JavascriptParser").Range} Range */ /** @typedef {import("./JavascriptParser").VariableInfoInterface} VariableInfoInterface */ const TypeUnknown = 0; @@ -70,8 +71,8 @@ class BasicEvaluatedExpression { this.getMembers = undefined; /** @type {() => boolean[]} */ this.getMembersOptionals = undefined; - /** @type {() => number[]} */ - this.getMemberRangeStarts = undefined; + /** @type {() => Range[]} */ + this.getMemberRanges = undefined; /** @type {EsTreeNode} */ this.expression = undefined; } @@ -386,7 +387,7 @@ class BasicEvaluatedExpression { * @param {string | VariableInfoInterface} rootInfo root info * @param {() => string[]} getMembers members * @param {() => boolean[]=} getMembersOptionals optional members - * @param {() => number[]=} getMemberRangeStarts range start of progressively increasing sub-expressions + * @param {() => Range[]=} getMemberRanges ranges of progressively increasing sub-expressions * @returns {this} this */ setIdentifier( @@ -394,14 +395,14 @@ class BasicEvaluatedExpression { rootInfo, getMembers, getMembersOptionals, - getMemberRangeStarts + getMemberRanges ) { this.type = TypeIdentifier; this.identifier = identifier; this.rootInfo = rootInfo; this.getMembers = getMembers; this.getMembersOptionals = getMembersOptionals; - this.getMemberRangeStarts = getMemberRangeStarts; + this.getMemberRanges = getMemberRanges; this.sideEffects = true; return this; } diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index c8f27d115c4..50d2ba58d1e 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -91,7 +91,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); /** @typedef {import("../Parser").ParserState} ParserState */ /** @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[], getMemberRangeStarts: () => number[] }} GetInfoResult */ +/** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[] }} GetInfoResult */ const EMPTY_ARRAY = []; const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01; @@ -350,14 +350,14 @@ class JavascriptParser extends Parser { /** @type {HookMap>} */ call: new HookMap(() => new SyncBailHook(["expression"])), /** Something like "a.b()" */ - /** @type {HookMap>} */ + /** @type {HookMap>} */ callMemberChain: new HookMap( () => new SyncBailHook([ "expression", "members", "membersOptionals", - "memberRangeStarts" + "memberRanges" ]) ), /** Something like "a.b().c.d" */ @@ -390,14 +390,14 @@ class JavascriptParser extends Parser { binaryExpression: new SyncBailHook(["binaryExpression"]), /** @type {HookMap>} */ expression: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap>} */ + /** @type {HookMap>} */ expressionMemberChain: new HookMap( () => new SyncBailHook([ "expression", "members", "membersOptionals", - "memberRangeStarts" + "memberRanges" ]) ), /** @type {HookMap>} */ @@ -1163,7 +1163,7 @@ class JavascriptParser extends Parser { info.rootInfo, info.getMembers, info.getMembersOptionals, - info.getMemberRangeStarts + info.getMemberRanges ) .setRange(expr.range); } @@ -1184,7 +1184,7 @@ class JavascriptParser extends Parser { rootInfo: info, getMembers: () => [], getMembersOptionals: () => [], - getMemberRangeStarts: () => [] + getMemberRanges: () => [] }; } }); @@ -1199,7 +1199,7 @@ class JavascriptParser extends Parser { rootInfo: info, getMembers: () => [], getMembersOptionals: () => [], - getMemberRangeStarts: () => [] + getMemberRanges: () => [] }; } }); @@ -3264,7 +3264,7 @@ class JavascriptParser extends Parser { callee.getMembersOptionals ? callee.getMembersOptionals() : callee.getMembers().map(() => false), - callee.getMemberRangeStarts ? callee.getMemberRangeStarts() : [] + callee.getMemberRanges ? callee.getMemberRanges() : [] ); if (result1 === true) return; const result2 = this.callHooksForInfo( @@ -3308,14 +3308,14 @@ class JavascriptParser extends Parser { if (result1 === true) return; const members = exprInfo.getMembers(); const membersOptionals = exprInfo.getMembersOptionals(); - const memberRangeStarts = exprInfo.getMemberRangeStarts(); + const memberRanges = exprInfo.getMemberRanges(); const result2 = this.callHooksForInfo( this.hooks.expressionMemberChain, exprInfo.rootInfo, expression, members, membersOptionals, - memberRangeStarts + memberRanges ); if (result2 === true) return; this.walkMemberExpressionWithExpressionName( @@ -4271,23 +4271,23 @@ class JavascriptParser extends Parser { /** * @param {MemberExpression} expression a member expression - * @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRangeStarts: number[] }} member names (reverse order) and remaining object + * @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRanges: Range[] }} member names (reverse order) and remaining object */ extractMemberExpressionChain(expression) { /** @type {AnyNode} */ let expr = expression; const members = []; const membersOptionals = []; - const memberRangeStarts = []; + const memberRanges = []; while (expr.type === "MemberExpression") { if (expr.computed) { if (expr.property.type !== "Literal") break; - members.push(`${expr.property.value}`); - memberRangeStarts.push(expr.object.range[1]); + members.push(`${expr.property.value}`); // the literal + memberRanges.push(expr.object.range); // the range of the expression fragment before the literal } else { if (expr.property.type !== "Identifier") break; - members.push(expr.property.name); - memberRangeStarts.push(expr.object.range[1]); + members.push(expr.property.name); // the identifier + memberRanges.push(expr.object.range); // the range of the expression fragment before the identifier } membersOptionals.push(expr.optional); expr = expr.object; @@ -4296,7 +4296,7 @@ class JavascriptParser extends Parser { return { members, membersOptionals, - memberRangeStarts, + memberRanges, object: expr }; } @@ -4319,8 +4319,8 @@ class JavascriptParser extends Parser { return { info, name }; } - /** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRangeStarts: () => number[]}} CallExpressionInfo */ - /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRangeStarts: () => number[]}} ExpressionExpressionInfo */ + /** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} CallExpressionInfo */ + /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} ExpressionExpressionInfo */ /** * @param {MemberExpression} expression a member expression @@ -4328,7 +4328,7 @@ class JavascriptParser extends Parser { * @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info */ getMemberExpressionInfo(expression, allowedTypes) { - const { object, members, membersOptionals, memberRangeStarts } = + const { object, members, membersOptionals, memberRanges } = this.extractMemberExpressionChain(expression); switch (object.type) { case "CallExpression": { @@ -4355,7 +4355,7 @@ class JavascriptParser extends Parser { name: objectAndMembersToName(`${calleeName}()`, members), getMembers: memoize(() => members.reverse()), getMembersOptionals: memoize(() => membersOptionals.reverse()), - getMemberRangeStarts: memoize(() => memberRangeStarts.reverse()) + getMemberRanges: memoize(() => memberRanges.reverse()) }; } case "Identifier": @@ -4375,7 +4375,7 @@ class JavascriptParser extends Parser { rootInfo, getMembers: memoize(() => members.reverse()), getMembersOptionals: memoize(() => membersOptionals.reverse()), - getMemberRangeStarts: memoize(() => memberRangeStarts.reverse()) + getMemberRanges: memoize(() => memberRanges.reverse()) }; } } diff --git a/package.json b/package.json index 70b51627ed5..17a77f37f76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack", - "version": "5.85.0", + "version": "5.85.1", "author": "Tobias Koppers @sokra", "description": "Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.", "license": "MIT", diff --git a/test/configCases/code-generation/re-export-namespace-concat/index.js b/test/configCases/code-generation/re-export-namespace-concat/index.js index 3d9549b5f82..aa2dbb6b823 100644 --- a/test/configCases/code-generation/re-export-namespace-concat/index.js +++ b/test/configCases/code-generation/re-export-namespace-concat/index.js @@ -35,6 +35,12 @@ it("should use/preserve accessor form for import object and namespaces", functio const bb = obj1.up.down?.left.right; data.nested.object3["unknownProperty"].depth = "deep"; + + (obj1)["aaa"].bbb; + (m_1.obj1)["ccc"].ddd; + (obj1["eee"]).fff; + (m_1.obj1["ggg"]).hhh; + (((m_1).obj1)["iii"]).jjj; } /************ DO NOT MATCH BELOW THIS LINE ************/ @@ -60,4 +66,10 @@ it("should use/preserve accessor form for import object and namespaces", functio expectSourceToContain(source, 'const bb = obj1.up.down?.left.right;'); expectSourceToContain(source, 'data_namespaceObject.a.a["unknownProperty"].depth = "deep";'); + + expectSourceToContain(source, '(obj1)["aaa"].bbb;'); + expectSourceToContain(source, '(obj1)["ccc"].ddd;'); + expectSourceToContain(source, '(obj1["eee"]).fff;'); + expectSourceToContain(source, '(obj1["ggg"]).hhh;'); + expectSourceToContain(source, '((obj1)["iii"]).jjj;'); }); diff --git a/test/configCases/code-generation/re-export-namespace/index.js b/test/configCases/code-generation/re-export-namespace/index.js index caaf1475498..d41eb1f4d32 100644 --- a/test/configCases/code-generation/re-export-namespace/index.js +++ b/test/configCases/code-generation/re-export-namespace/index.js @@ -35,6 +35,12 @@ it("should use/preserve accessor form for import object and namespaces", functio const bb = obj1.up.down?.left.right; data.nested.object3["unknownProperty"].depth = "deep"; + + (obj1)["aaa"].bbb; + (m_1.obj1)["ccc"].ddd; + (obj1["eee"]).fff; + (m_1.obj1["ggg"]).hhh; + (((m_1).obj1)["iii"]).jjj; } /************ DO NOT MATCH BELOW THIS LINE ************/ @@ -61,4 +67,9 @@ it("should use/preserve accessor form for import object and namespaces", functio expectSourceToContain(source, '_data__WEBPACK_IMPORTED_MODULE_3__.nested.object3["unknownProperty"].depth = "deep";'); + expectSourceToContain(source, '(_module1__WEBPACK_IMPORTED_MODULE_0__.obj1)["aaa"].bbb;'); + expectSourceToContain(source, '(_module1__WEBPACK_IMPORTED_MODULE_0__.obj1)["ccc"].ddd;'); + expectSourceToContain(source, '(_module1__WEBPACK_IMPORTED_MODULE_0__.obj1["eee"]).fff;'); + expectSourceToContain(source, '(_module1__WEBPACK_IMPORTED_MODULE_0__.obj1["ggg"]).hhh;'); + expectSourceToContain(source, '((_module1__WEBPACK_IMPORTED_MODULE_0__.obj1)["iii"]).jjj;'); }); diff --git a/types.d.ts b/types.d.ts index 1fe56c5204e..1d3a711e4a0 100644 --- a/types.d.ts +++ b/types.d.ts @@ -507,7 +507,7 @@ declare abstract class BasicEvaluatedExpression { rootInfo: string | VariableInfoInterface; getMembers: () => string[]; getMembersOptionals: () => boolean[]; - getMemberRangeStarts: () => number[]; + getMemberRanges: () => [number, number][]; expression: NodeEstreeIndex; isUnknown(): boolean; isNull(): boolean; @@ -593,7 +593,7 @@ declare abstract class BasicEvaluatedExpression { rootInfo: string | VariableInfoInterface, getMembers: () => string[], getMembersOptionals?: () => boolean[], - getMemberRangeStarts?: () => number[] + getMemberRanges?: () => [number, number][] ): BasicEvaluatedExpression; /** @@ -788,7 +788,7 @@ declare interface CallExpressionInfo { name: string; getMembers: () => string[]; getMembersOptionals: () => boolean[]; - getMemberRangeStarts: () => number[]; + getMemberRanges: () => [number, number][]; } declare interface CallbackAsyncQueue { (err?: null | WebpackError, result?: T): any; @@ -3991,7 +3991,7 @@ declare interface ExpressionExpressionInfo { name: string; getMembers: () => string[]; getMembersOptionals: () => boolean[]; - getMemberRangeStarts: () => number[]; + getMemberRanges: () => [number, number][]; } declare interface ExtensionAliasOption { alias: string | string[]; @@ -5344,7 +5344,7 @@ declare class JavascriptParser extends Parser { call: HookMap>; callMemberChain: HookMap< SyncBailHook< - [CallExpression, string[], boolean[], number[]], + [CallExpression, string[], boolean[], [number, number][]], boolean | void > >; @@ -5365,7 +5365,10 @@ declare class JavascriptParser extends Parser { binaryExpression: SyncBailHook<[BinaryExpression], boolean | void>; expression: HookMap>; expressionMemberChain: HookMap< - SyncBailHook<[Expression, string[], boolean[], number[]], boolean | void> + SyncBailHook< + [Expression, string[], boolean[], [number, number][]], + boolean | void + > >; unhandledExpressionMemberChain: HookMap< SyncBailHook<[Expression, string[]], boolean | void> @@ -5954,7 +5957,7 @@ declare class JavascriptParser extends Parser { | YieldExpression | Super; membersOptionals: boolean[]; - memberRangeStarts: number[]; + memberRanges: [number, number][]; }; getFreeInfoFromVariable(varName: string): { name: string; diff --git a/yarn.lock b/yarn.lock index 2211ed01d26..36280b13328 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1138,9 +1138,9 @@ "@types/istanbul-lib-report" "*" "@types/jest@^29.5.0": - version "29.5.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" - integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== + version "29.5.2" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.2.tgz#86b4afc86e3a8f3005b297ed8a72494f89e6395b" + integrity sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg== dependencies: expect "^29.0.0" pretty-format "^29.0.0"