mirror of https://github.com/webpack/webpack.git
Merge pull request #17203 from bworline/ns
Normalize property accessors for es6 namespaces and chained member/call expressions
This commit is contained in:
commit
53c98f06ee
|
@ -35,7 +35,7 @@ class HarmonyEvaluatedImportSpecifierDependency extends HarmonyImportSpecifierDe
|
||||||
* @param {string} operator operator
|
* @param {string} operator operator
|
||||||
*/
|
*/
|
||||||
constructor(request, sourceOrder, ids, name, range, assertions, operator) {
|
constructor(request, sourceOrder, ids, name, range, assertions, operator) {
|
||||||
super(request, sourceOrder, ids, name, range, false, assertions);
|
super(request, sourceOrder, ids, name, range, false, assertions, []);
|
||||||
this.operator = operator;
|
this.operator = operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,8 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
settings.name,
|
settings.name,
|
||||||
expr.range,
|
expr.range,
|
||||||
exportPresenceMode,
|
exportPresenceMode,
|
||||||
settings.assertions
|
settings.assertions,
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
dep.referencedPropertiesInDestructuring =
|
dep.referencedPropertiesInDestructuring =
|
||||||
parser.destructuringAssignmentPropertiesFor(expr);
|
parser.destructuringAssignmentPropertiesFor(expr);
|
||||||
|
@ -211,7 +212,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
.for(harmonySpecifierTag)
|
.for(harmonySpecifierTag)
|
||||||
.tap(
|
.tap(
|
||||||
"HarmonyImportDependencyParserPlugin",
|
"HarmonyImportDependencyParserPlugin",
|
||||||
(expression, members, membersOptionals) => {
|
(expression, members, membersOptionals, memberRangeStarts) => {
|
||||||
const settings = /** @type {HarmonySettings} */ (
|
const settings = /** @type {HarmonySettings} */ (
|
||||||
parser.currentTagData
|
parser.currentTagData
|
||||||
);
|
);
|
||||||
|
@ -219,6 +220,11 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
members,
|
members,
|
||||||
membersOptionals
|
membersOptionals
|
||||||
);
|
);
|
||||||
|
const rangeStarts = memberRangeStarts.slice(
|
||||||
|
0,
|
||||||
|
memberRangeStarts.length -
|
||||||
|
(members.length - nonOptionalMembers.length)
|
||||||
|
);
|
||||||
const expr =
|
const expr =
|
||||||
nonOptionalMembers !== members
|
nonOptionalMembers !== members
|
||||||
? getNonOptionalMemberChain(
|
? getNonOptionalMemberChain(
|
||||||
|
@ -234,7 +240,8 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
settings.name,
|
settings.name,
|
||||||
expr.range,
|
expr.range,
|
||||||
exportPresenceMode,
|
exportPresenceMode,
|
||||||
settings.assertions
|
settings.assertions,
|
||||||
|
rangeStarts
|
||||||
);
|
);
|
||||||
dep.referencedPropertiesInDestructuring =
|
dep.referencedPropertiesInDestructuring =
|
||||||
parser.destructuringAssignmentPropertiesFor(expr);
|
parser.destructuringAssignmentPropertiesFor(expr);
|
||||||
|
@ -249,7 +256,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
.for(harmonySpecifierTag)
|
.for(harmonySpecifierTag)
|
||||||
.tap(
|
.tap(
|
||||||
"HarmonyImportDependencyParserPlugin",
|
"HarmonyImportDependencyParserPlugin",
|
||||||
(expression, members, membersOptionals) => {
|
(expression, members, membersOptionals, memberRangeStarts) => {
|
||||||
const { arguments: args, callee } = expression;
|
const { arguments: args, callee } = expression;
|
||||||
const settings = /** @type {HarmonySettings} */ (
|
const settings = /** @type {HarmonySettings} */ (
|
||||||
parser.currentTagData
|
parser.currentTagData
|
||||||
|
@ -258,6 +265,11 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
members,
|
members,
|
||||||
membersOptionals
|
membersOptionals
|
||||||
);
|
);
|
||||||
|
const rangeStarts = memberRangeStarts.slice(
|
||||||
|
0,
|
||||||
|
memberRangeStarts.length -
|
||||||
|
(members.length - nonOptionalMembers.length)
|
||||||
|
);
|
||||||
const expr =
|
const expr =
|
||||||
nonOptionalMembers !== members
|
nonOptionalMembers !== members
|
||||||
? getNonOptionalMemberChain(
|
? getNonOptionalMemberChain(
|
||||||
|
@ -273,7 +285,8 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
||||||
settings.name,
|
settings.name,
|
||||||
expr.range,
|
expr.range,
|
||||||
exportPresenceMode,
|
exportPresenceMode,
|
||||||
settings.assertions
|
settings.assertions,
|
||||||
|
rangeStarts
|
||||||
);
|
);
|
||||||
dep.directImport = members.length === 0;
|
dep.directImport = members.length === 0;
|
||||||
dep.call = true;
|
dep.call = true;
|
||||||
|
|
|
@ -43,6 +43,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
||||||
* @param {Range} range range
|
* @param {Range} range range
|
||||||
* @param {TODO} exportPresenceMode export presence mode
|
* @param {TODO} exportPresenceMode export presence mode
|
||||||
* @param {Assertions=} assertions assertions
|
* @param {Assertions=} assertions assertions
|
||||||
|
* @param {number[]=} idRangeStarts range starts for members of ids; the two arrays are right-aligned
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
request,
|
request,
|
||||||
|
@ -51,12 +52,14 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
||||||
name,
|
name,
|
||||||
range,
|
range,
|
||||||
exportPresenceMode,
|
exportPresenceMode,
|
||||||
assertions
|
assertions,
|
||||||
|
idRangeStarts // TODO webpack 6 make this non-optional. It must always be set to properly trim ids.
|
||||||
) {
|
) {
|
||||||
super(request, sourceOrder, assertions);
|
super(request, sourceOrder, assertions);
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.range = range;
|
this.range = range;
|
||||||
|
this.idRangeStarts = idRangeStarts;
|
||||||
this.exportPresenceMode = exportPresenceMode;
|
this.exportPresenceMode = exportPresenceMode;
|
||||||
this.namespaceObjectAsContext = false;
|
this.namespaceObjectAsContext = false;
|
||||||
this.call = undefined;
|
this.call = undefined;
|
||||||
|
@ -258,6 +261,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
||||||
write(this.ids);
|
write(this.ids);
|
||||||
write(this.name);
|
write(this.name);
|
||||||
write(this.range);
|
write(this.range);
|
||||||
|
write(this.idRangeStarts);
|
||||||
write(this.exportPresenceMode);
|
write(this.exportPresenceMode);
|
||||||
write(this.namespaceObjectAsContext);
|
write(this.namespaceObjectAsContext);
|
||||||
write(this.call);
|
write(this.call);
|
||||||
|
@ -277,6 +281,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
|
||||||
this.ids = read();
|
this.ids = read();
|
||||||
this.name = read();
|
this.name = read();
|
||||||
this.range = read();
|
this.range = read();
|
||||||
|
this.idRangeStarts = read();
|
||||||
this.exportPresenceMode = read();
|
this.exportPresenceMode = read();
|
||||||
this.namespaceObjectAsContext = read();
|
this.namespaceObjectAsContext = read();
|
||||||
this.call = read();
|
this.call = read();
|
||||||
|
@ -310,14 +315,78 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
|
||||||
// Skip rendering depending when dependency is conditional
|
// Skip rendering depending when dependency is conditional
|
||||||
if (connection && !connection.isTargetActive(runtime)) return;
|
if (connection && !connection.isTargetActive(runtime)) return;
|
||||||
|
|
||||||
const ids = dep.getIds(moduleGraph);
|
const ids = dep.getIds(moduleGraph); // determine minimal set of IDs.
|
||||||
const exportExpr = this._getCodeForIds(dep, source, templateContext, ids);
|
let trimmedIds = this._trimIdsToThoseImported(ids, moduleGraph, dep);
|
||||||
const range = dep.range;
|
|
||||||
if (dep.shorthand) {
|
let [rangeStart, rangeEnd] = dep.range;
|
||||||
source.insert(range[1], `: ${exportExpr}`);
|
if (trimmedIds.length !== ids.length) {
|
||||||
} else {
|
// The array returned from dep.idRangeStarts is right-aligned with the array returned from dep.getIds.
|
||||||
source.replace(range[0], range[1] - 1, exportExpr);
|
// 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.
|
||||||
|
const idx =
|
||||||
|
dep.idRangeStarts === undefined
|
||||||
|
? -1 /* trigger failure case below */
|
||||||
|
: dep.idRangeStarts.length + (trimmedIds.length - ids.length);
|
||||||
|
if (idx < 0 || idx >= dep.idRangeStarts.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.
|
||||||
|
trimmedIds = ids;
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exportExpr = this._getCodeForIds(
|
||||||
|
dep,
|
||||||
|
source,
|
||||||
|
templateContext,
|
||||||
|
trimmedIds
|
||||||
|
);
|
||||||
|
if (dep.shorthand) {
|
||||||
|
source.insert(rangeEnd, `: ${exportExpr}`);
|
||||||
|
} else {
|
||||||
|
source.replace(rangeStart, rangeEnd - 1, exportExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Determine which IDs in the id chain are actually referring to namespaces or imports,
|
||||||
|
* and which are deeper member accessors on the imported object. Only the former should be re-rendered.
|
||||||
|
* @param {string[]} ids ids
|
||||||
|
* @param {ModuleGraph} moduleGraph moduleGraph
|
||||||
|
* @param {HarmonyImportSpecifierDependency} dependency dependency
|
||||||
|
* @returns {string[]} generated code
|
||||||
|
*/
|
||||||
|
_trimIdsToThoseImported(ids, moduleGraph, dependency) {
|
||||||
|
let trimmedIds = [];
|
||||||
|
const exportsInfo = moduleGraph.getExportsInfo(
|
||||||
|
moduleGraph.getModule(dependency)
|
||||||
|
);
|
||||||
|
let currentExportsInfo = /** @type {ExportsInfo=} */ exportsInfo;
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
if (i === 0 && ids[i] === "default") {
|
||||||
|
continue; // ExportInfo for the next level under default is still at the root ExportsInfo, so don't advance currentExportsInfo
|
||||||
|
}
|
||||||
|
const exportInfo = currentExportsInfo.getExportInfo(ids[i]);
|
||||||
|
if (exportInfo.provided === false) {
|
||||||
|
// json imports have nested ExportInfo for elements that things that are not actually exported, so check .provided
|
||||||
|
trimmedIds = ids.slice(0, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const nestedInfo = exportInfo.getNestedExportsInfo();
|
||||||
|
if (!nestedInfo) {
|
||||||
|
// once all nested exports are traversed, the next item is the actual import so stop there
|
||||||
|
trimmedIds = ids.slice(0, i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentExportsInfo = nestedInfo;
|
||||||
|
}
|
||||||
|
// Never trim to nothing. This can happen for invalid imports (e.g. import { notThere } from "./module", or import { anything } from "./missingModule")
|
||||||
|
return trimmedIds.length ? trimmedIds : ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -70,6 +70,8 @@ class BasicEvaluatedExpression {
|
||||||
this.getMembers = undefined;
|
this.getMembers = undefined;
|
||||||
/** @type {() => boolean[]} */
|
/** @type {() => boolean[]} */
|
||||||
this.getMembersOptionals = undefined;
|
this.getMembersOptionals = undefined;
|
||||||
|
/** @type {() => number[]} */
|
||||||
|
this.getMemberRangeStarts = undefined;
|
||||||
/** @type {EsTreeNode} */
|
/** @type {EsTreeNode} */
|
||||||
this.expression = undefined;
|
this.expression = undefined;
|
||||||
}
|
}
|
||||||
|
@ -384,14 +386,22 @@ class BasicEvaluatedExpression {
|
||||||
* @param {string | VariableInfoInterface} rootInfo root info
|
* @param {string | VariableInfoInterface} rootInfo root info
|
||||||
* @param {() => string[]} getMembers members
|
* @param {() => string[]} getMembers members
|
||||||
* @param {() => boolean[]=} getMembersOptionals optional members
|
* @param {() => boolean[]=} getMembersOptionals optional members
|
||||||
|
* @param {() => number[]=} getMemberRangeStarts range start of progressively increasing sub-expressions
|
||||||
* @returns {this} this
|
* @returns {this} this
|
||||||
*/
|
*/
|
||||||
setIdentifier(identifier, rootInfo, getMembers, getMembersOptionals) {
|
setIdentifier(
|
||||||
|
identifier,
|
||||||
|
rootInfo,
|
||||||
|
getMembers,
|
||||||
|
getMembersOptionals,
|
||||||
|
getMemberRangeStarts
|
||||||
|
) {
|
||||||
this.type = TypeIdentifier;
|
this.type = TypeIdentifier;
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.rootInfo = rootInfo;
|
this.rootInfo = rootInfo;
|
||||||
this.getMembers = getMembers;
|
this.getMembers = getMembers;
|
||||||
this.getMembersOptionals = getMembersOptionals;
|
this.getMembersOptionals = getMembersOptionals;
|
||||||
|
this.getMemberRangeStarts = getMemberRangeStarts;
|
||||||
this.sideEffects = true;
|
this.sideEffects = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
||||||
/** @typedef {import("../Parser").ParserState} ParserState */
|
/** @typedef {import("../Parser").ParserState} ParserState */
|
||||||
/** @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[] }} GetInfoResult */
|
/** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRangeStarts: () => number[] }} GetInfoResult */
|
||||||
|
|
||||||
const EMPTY_ARRAY = [];
|
const EMPTY_ARRAY = [];
|
||||||
const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01;
|
const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01;
|
||||||
|
@ -350,9 +350,15 @@ class JavascriptParser extends Parser {
|
||||||
/** @type {HookMap<SyncBailHook<[BaseCallExpression], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[BaseCallExpression], boolean | void>>} */
|
||||||
call: new HookMap(() => new SyncBailHook(["expression"])),
|
call: new HookMap(() => new SyncBailHook(["expression"])),
|
||||||
/** Something like "a.b()" */
|
/** Something like "a.b()" */
|
||||||
/** @type {HookMap<SyncBailHook<[CallExpression, string[], boolean[]], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[CallExpression, string[], boolean[], number[]], boolean | void>>} */
|
||||||
callMemberChain: new HookMap(
|
callMemberChain: new HookMap(
|
||||||
() => new SyncBailHook(["expression", "members", "membersOptionals"])
|
() =>
|
||||||
|
new SyncBailHook([
|
||||||
|
"expression",
|
||||||
|
"members",
|
||||||
|
"membersOptionals",
|
||||||
|
"memberRangeStarts"
|
||||||
|
])
|
||||||
),
|
),
|
||||||
/** Something like "a.b().c.d" */
|
/** Something like "a.b().c.d" */
|
||||||
/** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[]], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[]], boolean | void>>} */
|
||||||
|
@ -384,9 +390,15 @@ class JavascriptParser extends Parser {
|
||||||
binaryExpression: new SyncBailHook(["binaryExpression"]),
|
binaryExpression: new SyncBailHook(["binaryExpression"]),
|
||||||
/** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
|
||||||
expression: new HookMap(() => new SyncBailHook(["expression"])),
|
expression: new HookMap(() => new SyncBailHook(["expression"])),
|
||||||
/** @type {HookMap<SyncBailHook<[Expression, string[], boolean[]], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[Expression, string[], boolean[], number[]], boolean | void>>} */
|
||||||
expressionMemberChain: new HookMap(
|
expressionMemberChain: new HookMap(
|
||||||
() => new SyncBailHook(["expression", "members", "membersOptionals"])
|
() =>
|
||||||
|
new SyncBailHook([
|
||||||
|
"expression",
|
||||||
|
"members",
|
||||||
|
"membersOptionals",
|
||||||
|
"memberRangeStarts"
|
||||||
|
])
|
||||||
),
|
),
|
||||||
/** @type {HookMap<SyncBailHook<[Expression, string[]], boolean | void>>} */
|
/** @type {HookMap<SyncBailHook<[Expression, string[]], boolean | void>>} */
|
||||||
unhandledExpressionMemberChain: new HookMap(
|
unhandledExpressionMemberChain: new HookMap(
|
||||||
|
@ -1150,7 +1162,8 @@ class JavascriptParser extends Parser {
|
||||||
info.name,
|
info.name,
|
||||||
info.rootInfo,
|
info.rootInfo,
|
||||||
info.getMembers,
|
info.getMembers,
|
||||||
info.getMembersOptionals
|
info.getMembersOptionals,
|
||||||
|
info.getMemberRangeStarts
|
||||||
)
|
)
|
||||||
.setRange(expr.range);
|
.setRange(expr.range);
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1183,8 @@ class JavascriptParser extends Parser {
|
||||||
name: info,
|
name: info,
|
||||||
rootInfo: info,
|
rootInfo: info,
|
||||||
getMembers: () => [],
|
getMembers: () => [],
|
||||||
getMembersOptionals: () => []
|
getMembersOptionals: () => [],
|
||||||
|
getMemberRangeStarts: () => []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1184,7 +1198,8 @@ class JavascriptParser extends Parser {
|
||||||
name: info,
|
name: info,
|
||||||
rootInfo: info,
|
rootInfo: info,
|
||||||
getMembers: () => [],
|
getMembers: () => [],
|
||||||
getMembersOptionals: () => []
|
getMembersOptionals: () => [],
|
||||||
|
getMemberRangeStarts: () => []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3248,7 +3263,8 @@ class JavascriptParser extends Parser {
|
||||||
callee.getMembers(),
|
callee.getMembers(),
|
||||||
callee.getMembersOptionals
|
callee.getMembersOptionals
|
||||||
? callee.getMembersOptionals()
|
? callee.getMembersOptionals()
|
||||||
: callee.getMembers().map(() => false)
|
: callee.getMembers().map(() => false),
|
||||||
|
callee.getMemberRangeStarts ? callee.getMemberRangeStarts() : []
|
||||||
);
|
);
|
||||||
if (result1 === true) return;
|
if (result1 === true) return;
|
||||||
const result2 = this.callHooksForInfo(
|
const result2 = this.callHooksForInfo(
|
||||||
|
@ -3292,12 +3308,14 @@ class JavascriptParser extends Parser {
|
||||||
if (result1 === true) return;
|
if (result1 === true) return;
|
||||||
const members = exprInfo.getMembers();
|
const members = exprInfo.getMembers();
|
||||||
const membersOptionals = exprInfo.getMembersOptionals();
|
const membersOptionals = exprInfo.getMembersOptionals();
|
||||||
|
const memberRangeStarts = exprInfo.getMemberRangeStarts();
|
||||||
const result2 = this.callHooksForInfo(
|
const result2 = this.callHooksForInfo(
|
||||||
this.hooks.expressionMemberChain,
|
this.hooks.expressionMemberChain,
|
||||||
exprInfo.rootInfo,
|
exprInfo.rootInfo,
|
||||||
expression,
|
expression,
|
||||||
members,
|
members,
|
||||||
membersOptionals
|
membersOptionals,
|
||||||
|
memberRangeStarts
|
||||||
);
|
);
|
||||||
if (result2 === true) return;
|
if (result2 === true) return;
|
||||||
this.walkMemberExpressionWithExpressionName(
|
this.walkMemberExpressionWithExpressionName(
|
||||||
|
@ -4253,20 +4271,23 @@ class JavascriptParser extends Parser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MemberExpression} expression a member expression
|
* @param {MemberExpression} expression a member expression
|
||||||
* @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[] }} member names (reverse order) and remaining object
|
* @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRangeStarts: number[] }} member names (reverse order) and remaining object
|
||||||
*/
|
*/
|
||||||
extractMemberExpressionChain(expression) {
|
extractMemberExpressionChain(expression) {
|
||||||
/** @type {AnyNode} */
|
/** @type {AnyNode} */
|
||||||
let expr = expression;
|
let expr = expression;
|
||||||
const members = [];
|
const members = [];
|
||||||
const membersOptionals = [];
|
const membersOptionals = [];
|
||||||
|
const memberRangeStarts = [];
|
||||||
while (expr.type === "MemberExpression") {
|
while (expr.type === "MemberExpression") {
|
||||||
if (expr.computed) {
|
if (expr.computed) {
|
||||||
if (expr.property.type !== "Literal") break;
|
if (expr.property.type !== "Literal") break;
|
||||||
members.push(`${expr.property.value}`);
|
members.push(`${expr.property.value}`);
|
||||||
|
memberRangeStarts.push(expr.object.range[1]);
|
||||||
} else {
|
} else {
|
||||||
if (expr.property.type !== "Identifier") break;
|
if (expr.property.type !== "Identifier") break;
|
||||||
members.push(expr.property.name);
|
members.push(expr.property.name);
|
||||||
|
memberRangeStarts.push(expr.object.range[1]);
|
||||||
}
|
}
|
||||||
membersOptionals.push(expr.optional);
|
membersOptionals.push(expr.optional);
|
||||||
expr = expr.object;
|
expr = expr.object;
|
||||||
|
@ -4275,6 +4296,7 @@ class JavascriptParser extends Parser {
|
||||||
return {
|
return {
|
||||||
members,
|
members,
|
||||||
membersOptionals,
|
membersOptionals,
|
||||||
|
memberRangeStarts,
|
||||||
object: expr
|
object: expr
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4297,8 +4319,8 @@ class JavascriptParser extends Parser {
|
||||||
return { info, name };
|
return { info, name };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[], getMembersOptionals: () => boolean[]}} CallExpressionInfo */
|
/** @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[]}} ExpressionExpressionInfo */
|
/** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRangeStarts: () => number[]}} ExpressionExpressionInfo */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MemberExpression} expression a member expression
|
* @param {MemberExpression} expression a member expression
|
||||||
|
@ -4306,7 +4328,7 @@ class JavascriptParser extends Parser {
|
||||||
* @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info
|
* @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info
|
||||||
*/
|
*/
|
||||||
getMemberExpressionInfo(expression, allowedTypes) {
|
getMemberExpressionInfo(expression, allowedTypes) {
|
||||||
const { object, members, membersOptionals } =
|
const { object, members, membersOptionals, memberRangeStarts } =
|
||||||
this.extractMemberExpressionChain(expression);
|
this.extractMemberExpressionChain(expression);
|
||||||
switch (object.type) {
|
switch (object.type) {
|
||||||
case "CallExpression": {
|
case "CallExpression": {
|
||||||
|
@ -4332,7 +4354,8 @@ class JavascriptParser extends Parser {
|
||||||
getCalleeMembers: memoize(() => rootMembers.reverse()),
|
getCalleeMembers: memoize(() => rootMembers.reverse()),
|
||||||
name: objectAndMembersToName(`${calleeName}()`, members),
|
name: objectAndMembersToName(`${calleeName}()`, members),
|
||||||
getMembers: memoize(() => members.reverse()),
|
getMembers: memoize(() => members.reverse()),
|
||||||
getMembersOptionals: memoize(() => membersOptionals.reverse())
|
getMembersOptionals: memoize(() => membersOptionals.reverse()),
|
||||||
|
getMemberRangeStarts: memoize(() => memberRangeStarts.reverse())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "Identifier":
|
case "Identifier":
|
||||||
|
@ -4351,7 +4374,8 @@ class JavascriptParser extends Parser {
|
||||||
name: objectAndMembersToName(resolvedRoot, members),
|
name: objectAndMembersToName(resolvedRoot, members),
|
||||||
rootInfo,
|
rootInfo,
|
||||||
getMembers: memoize(() => members.reverse()),
|
getMembers: memoize(() => members.reverse()),
|
||||||
getMembersOptionals: memoize(() => membersOptionals.reverse())
|
getMembersOptionals: memoize(() => membersOptionals.reverse()),
|
||||||
|
getMemberRangeStarts: memoize(() => memberRangeStarts.reverse())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"nested": {
|
||||||
|
"object3": {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { obj1 } from './module1';
|
||||||
|
import * as m_1 from './module1';
|
||||||
|
import * as m_2 from './module2';
|
||||||
|
import * as m_3 from './module3';
|
||||||
|
import data from "./data";
|
||||||
|
|
||||||
|
const { expectSourceToContain } = require("../../../helpers/expectSource");
|
||||||
|
|
||||||
|
// It's important to preserve the same accessor syntax (quotes vs. dot notatation) after the actual export variable.
|
||||||
|
// Else, minifiers such as Closure Compiler will not be able to minify correctly in ADVANCED mode.
|
||||||
|
|
||||||
|
it("should use/preserve accessor form for import object and namespaces", function() {
|
||||||
|
var fs = require("fs");
|
||||||
|
var source = fs.readFileSync(__filename, "utf-8").toString();
|
||||||
|
|
||||||
|
// Reference the imports to generate uses in the source.
|
||||||
|
|
||||||
|
const f = false;
|
||||||
|
if (f) {
|
||||||
|
const x1 = m_1;
|
||||||
|
const x2 = obj1;
|
||||||
|
|
||||||
|
const z1 = obj1["plants"];
|
||||||
|
const z2 = obj1["funcs"]();
|
||||||
|
const z3 = m_1["obj1"]["pots"];
|
||||||
|
const z4 = m_1["obj1"]["subs"]();
|
||||||
|
|
||||||
|
const a = m_2["m_1"].obj1["flip"].flap;
|
||||||
|
const b = m_2["m_1"]["obj1"].zip["zap"];
|
||||||
|
const c = m_2.m_1.obj1["ding"].dong();
|
||||||
|
const d = m_2.m_1["obj1"].sing["song"]();
|
||||||
|
|
||||||
|
const aa = m_3["m_2"].m_1["obj1"]["zoom"];
|
||||||
|
|
||||||
|
const bb = obj1.up.down?.left.right;
|
||||||
|
|
||||||
|
data.nested.object3["unknownProperty"].depth = "deep";
|
||||||
|
}
|
||||||
|
|
||||||
|
/************ DO NOT MATCH BELOW THIS LINE ************/
|
||||||
|
|
||||||
|
// Imported objects and import namespaces should use dot notation. Any references to the properties of exports
|
||||||
|
// should be preserved as either quotes or dot notation, depending on the original source.
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const x1 = module1_namespaceObject;');
|
||||||
|
expectSourceToContain(source, 'const x2 = obj1;');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const z1 = obj1["plants"];');
|
||||||
|
expectSourceToContain(source, 'const z2 = obj1["funcs"]();');
|
||||||
|
expectSourceToContain(source, 'const z3 = obj1["pots"];');
|
||||||
|
expectSourceToContain(source, 'const z4 = obj1["subs"]();');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const a = obj1["flip"].flap;');
|
||||||
|
expectSourceToContain(source, 'const b = obj1.zip["zap"];');
|
||||||
|
expectSourceToContain(source, 'const c = obj1["ding"].dong();');
|
||||||
|
expectSourceToContain(source, 'const d = obj1.sing["song"]();');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const aa = obj1["zoom"];');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const bb = obj1.up.down?.left.right;');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'data_namespaceObject.a.a["unknownProperty"].depth = "deep";');
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const obj1 = {};
|
||||||
|
|
||||||
|
export default { obj2: {} };
|
|
@ -0,0 +1,2 @@
|
||||||
|
import * as m1 from './module1';
|
||||||
|
export { m1 as m_1 };
|
|
@ -0,0 +1,2 @@
|
||||||
|
import * as m2 from './module2';
|
||||||
|
export { m2 as m_2 };
|
|
@ -0,0 +1,5 @@
|
||||||
|
var supportsOptionalChaining = require("../../../helpers/supportsOptionalChaining");
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
return supportsOptionalChaining();
|
||||||
|
};
|
|
@ -0,0 +1,11 @@
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false
|
||||||
|
},
|
||||||
|
mode: "production",
|
||||||
|
optimization: {
|
||||||
|
mangleExports: "size"
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"nested": {
|
||||||
|
"object3": {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { obj1 } from './module1';
|
||||||
|
import * as m_1 from './module1';
|
||||||
|
import * as m_2 from './module2';
|
||||||
|
import * as m_3 from './module3';
|
||||||
|
import data from "./data";
|
||||||
|
|
||||||
|
const { expectSourceToContain } = require("../../../helpers/expectSource");
|
||||||
|
|
||||||
|
// It's important to preserve the same accessor syntax (quotes vs. dot notatation) after the actual export variable.
|
||||||
|
// Else, minifiers such as Closure Compiler will not be able to minify correctly in ADVANCED mode.
|
||||||
|
|
||||||
|
it("should use/preserve accessor form for import object and namespaces", function() {
|
||||||
|
var fs = require("fs");
|
||||||
|
var source = fs.readFileSync(__filename, "utf-8").toString();
|
||||||
|
|
||||||
|
// Reference the imports to generate uses in the source.
|
||||||
|
|
||||||
|
const f = false;
|
||||||
|
if (f) {
|
||||||
|
const x1 = m_1;
|
||||||
|
const x2 = obj1;
|
||||||
|
|
||||||
|
const z1 = obj1["plants"];
|
||||||
|
const z2 = obj1["funcs"]();
|
||||||
|
const z3 = m_1["obj1"]["pots"];
|
||||||
|
const z4 = m_1["obj1"]["subs"]();
|
||||||
|
|
||||||
|
const a = m_2["m_1"].obj1["flip"].flap;
|
||||||
|
const b = m_2["m_1"]["obj1"].zip["zap"];
|
||||||
|
const c = m_2.m_1.obj1["ding"].dong();
|
||||||
|
const d = m_2.m_1["obj1"].sing["song"]();
|
||||||
|
|
||||||
|
const aa = m_3["m_2"].m_1["obj1"]["zoom"];
|
||||||
|
|
||||||
|
const bb = obj1.up.down?.left.right;
|
||||||
|
|
||||||
|
data.nested.object3["unknownProperty"].depth = "deep";
|
||||||
|
}
|
||||||
|
|
||||||
|
/************ DO NOT MATCH BELOW THIS LINE ************/
|
||||||
|
|
||||||
|
// Imported objects and import namespaces should use dot notation. Any references to the properties of exports
|
||||||
|
// should be preserved as either quotes or dot notation, depending on the original source.
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const x1 = _module1__WEBPACK_IMPORTED_MODULE_0__;');
|
||||||
|
expectSourceToContain(source, 'const x2 = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1;');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const z1 = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1["plants"];');
|
||||||
|
expectSourceToContain(source, 'const z2 = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1["funcs"]();');
|
||||||
|
expectSourceToContain(source, 'const z3 = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1["pots"];');
|
||||||
|
expectSourceToContain(source, 'const z4 = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1["subs"]();');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const a = _module2__WEBPACK_IMPORTED_MODULE_1__.m_1.obj1["flip"].flap;');
|
||||||
|
expectSourceToContain(source, 'const b = _module2__WEBPACK_IMPORTED_MODULE_1__.m_1.obj1.zip["zap"];');
|
||||||
|
expectSourceToContain(source, 'const c = _module2__WEBPACK_IMPORTED_MODULE_1__.m_1.obj1["ding"].dong();');
|
||||||
|
expectSourceToContain(source, 'const d = _module2__WEBPACK_IMPORTED_MODULE_1__.m_1.obj1.sing["song"]();');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const aa = _module3__WEBPACK_IMPORTED_MODULE_2__.m_2.m_1.obj1["zoom"];');
|
||||||
|
|
||||||
|
expectSourceToContain(source, 'const bb = _module1__WEBPACK_IMPORTED_MODULE_0__.obj1.up.down?.left.right;');
|
||||||
|
|
||||||
|
expectSourceToContain(source, '_data__WEBPACK_IMPORTED_MODULE_3__.nested.object3["unknownProperty"].depth = "deep";');
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
export const obj1 = {};
|
||||||
|
|
||||||
|
export default { obj2: {} };
|
|
@ -0,0 +1,2 @@
|
||||||
|
import * as m1 from './module1';
|
||||||
|
export { m1 as m_1 };
|
|
@ -0,0 +1,2 @@
|
||||||
|
import * as m2 from './module2';
|
||||||
|
export { m2 as m_2 };
|
|
@ -0,0 +1,5 @@
|
||||||
|
var supportsOptionalChaining = require("../../../helpers/supportsOptionalChaining");
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
return supportsOptionalChaining();
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
node: {
|
||||||
|
__dirname: false,
|
||||||
|
__filename: false
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
concatenateModules: false,
|
||||||
|
usedExports: true,
|
||||||
|
providedExports: true,
|
||||||
|
minimize: false,
|
||||||
|
mangleExports: false
|
||||||
|
}
|
||||||
|
};
|
|
@ -507,6 +507,7 @@ declare abstract class BasicEvaluatedExpression {
|
||||||
rootInfo: string | VariableInfoInterface;
|
rootInfo: string | VariableInfoInterface;
|
||||||
getMembers: () => string[];
|
getMembers: () => string[];
|
||||||
getMembersOptionals: () => boolean[];
|
getMembersOptionals: () => boolean[];
|
||||||
|
getMemberRangeStarts: () => number[];
|
||||||
expression: NodeEstreeIndex;
|
expression: NodeEstreeIndex;
|
||||||
isUnknown(): boolean;
|
isUnknown(): boolean;
|
||||||
isNull(): boolean;
|
isNull(): boolean;
|
||||||
|
@ -591,7 +592,8 @@ declare abstract class BasicEvaluatedExpression {
|
||||||
identifier: string | VariableInfoInterface,
|
identifier: string | VariableInfoInterface,
|
||||||
rootInfo: string | VariableInfoInterface,
|
rootInfo: string | VariableInfoInterface,
|
||||||
getMembers: () => string[],
|
getMembers: () => string[],
|
||||||
getMembersOptionals?: () => boolean[]
|
getMembersOptionals?: () => boolean[],
|
||||||
|
getMemberRangeStarts?: () => number[]
|
||||||
): BasicEvaluatedExpression;
|
): BasicEvaluatedExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -786,6 +788,7 @@ declare interface CallExpressionInfo {
|
||||||
name: string;
|
name: string;
|
||||||
getMembers: () => string[];
|
getMembers: () => string[];
|
||||||
getMembersOptionals: () => boolean[];
|
getMembersOptionals: () => boolean[];
|
||||||
|
getMemberRangeStarts: () => number[];
|
||||||
}
|
}
|
||||||
declare interface CallbackAsyncQueue<T> {
|
declare interface CallbackAsyncQueue<T> {
|
||||||
(err?: null | WebpackError, result?: T): any;
|
(err?: null | WebpackError, result?: T): any;
|
||||||
|
@ -3988,6 +3991,7 @@ declare interface ExpressionExpressionInfo {
|
||||||
name: string;
|
name: string;
|
||||||
getMembers: () => string[];
|
getMembers: () => string[];
|
||||||
getMembersOptionals: () => boolean[];
|
getMembersOptionals: () => boolean[];
|
||||||
|
getMemberRangeStarts: () => number[];
|
||||||
}
|
}
|
||||||
declare interface ExtensionAliasOption {
|
declare interface ExtensionAliasOption {
|
||||||
alias: string | string[];
|
alias: string | string[];
|
||||||
|
@ -5339,7 +5343,10 @@ declare class JavascriptParser extends Parser {
|
||||||
topLevelAwait: SyncBailHook<[Expression], boolean | void>;
|
topLevelAwait: SyncBailHook<[Expression], boolean | void>;
|
||||||
call: HookMap<SyncBailHook<[BaseCallExpression], boolean | void>>;
|
call: HookMap<SyncBailHook<[BaseCallExpression], boolean | void>>;
|
||||||
callMemberChain: HookMap<
|
callMemberChain: HookMap<
|
||||||
SyncBailHook<[CallExpression, string[], boolean[]], boolean | void>
|
SyncBailHook<
|
||||||
|
[CallExpression, string[], boolean[], number[]],
|
||||||
|
boolean | void
|
||||||
|
>
|
||||||
>;
|
>;
|
||||||
memberChainOfCallMemberChain: HookMap<
|
memberChainOfCallMemberChain: HookMap<
|
||||||
SyncBailHook<
|
SyncBailHook<
|
||||||
|
@ -5358,7 +5365,7 @@ declare class JavascriptParser extends Parser {
|
||||||
binaryExpression: SyncBailHook<[BinaryExpression], boolean | void>;
|
binaryExpression: SyncBailHook<[BinaryExpression], boolean | void>;
|
||||||
expression: HookMap<SyncBailHook<[Expression], boolean | void>>;
|
expression: HookMap<SyncBailHook<[Expression], boolean | void>>;
|
||||||
expressionMemberChain: HookMap<
|
expressionMemberChain: HookMap<
|
||||||
SyncBailHook<[Expression, string[], boolean[]], boolean | void>
|
SyncBailHook<[Expression, string[], boolean[], number[]], boolean | void>
|
||||||
>;
|
>;
|
||||||
unhandledExpressionMemberChain: HookMap<
|
unhandledExpressionMemberChain: HookMap<
|
||||||
SyncBailHook<[Expression, string[]], boolean | void>
|
SyncBailHook<[Expression, string[]], boolean | void>
|
||||||
|
@ -5947,6 +5954,7 @@ declare class JavascriptParser extends Parser {
|
||||||
| YieldExpression
|
| YieldExpression
|
||||||
| Super;
|
| Super;
|
||||||
membersOptionals: boolean[];
|
membersOptionals: boolean[];
|
||||||
|
memberRangeStarts: number[];
|
||||||
};
|
};
|
||||||
getFreeInfoFromVariable(varName: string): {
|
getFreeInfoFromVariable(varName: string): {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
Loading…
Reference in New Issue