refactor to HarmonyDestructuredImportSpecifierDependency

This commit is contained in:
ahabhgk 2024-04-19 00:54:46 +08:00
parent 15cf31c462
commit a93725ff9c
6 changed files with 223 additions and 233 deletions

View File

@ -1,151 +0,0 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Gengkun He @ahabhgk
*/
"use strict";
const Template = require("../Template");
const makeSerializable = require("../util/makeSerializable");
const NullDependency = require("./NullDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("./HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
/**
* @param {DestructuringAssignmentProperty} property property
* @param {((property: DestructuringAssignmentProperty) => void) | undefined=} onProperty on property
* @param {((property: DestructuringAssignmentProperty) => void) | undefined=} onClean on property end
* @param {(() => void) | undefined=} onTerminate on a terminal property
*/
function traversePropertyInDestructuring(
property,
onProperty,
onClean,
onTerminate
) {
onProperty && onProperty(property);
if (!property.pattern) {
onTerminate && onTerminate();
} else {
for (const p of property.pattern) {
traversePropertyInDestructuring(p, onProperty, onClean, onTerminate);
}
}
onClean && onClean(property);
}
/**
* @param {Set<DestructuringAssignmentProperty>} properties properties
* @returns {string[][]} all ids
*/
function getAllIdsInDestructuring(properties) {
/** @type {string[][]} */
const allIds = [];
for (const p of properties) {
const ids = [];
traversePropertyInDestructuring(
p,
p => ids.push(p.id),
p => ids.pop(),
() => allIds.push([...ids])
);
}
return allIds;
}
class DestructuringAssignmentPropertyKeyDependency extends NullDependency {
/**
* @param {string[]} ids ids
* @param {HarmonyImportSpecifierDependency} specifier import specifier
* @param {Range} range range of the property key id
* @param {boolean | string} shorthand destructuring property is in shorthand
*/
constructor(ids, specifier, range, shorthand) {
super();
this.ids = ids;
this.specifier = specifier;
this.range = range;
this.shorthand = shorthand;
}
get type() {
return "destructuring assignment property id";
}
/**
* @param {ObjectSerializerContext} context context
*/
serialize(context) {
const { write } = context;
write(this.ids);
write(this.specifier);
write(this.range);
write(this.shorthand);
super.serialize(context);
}
/**
* @param {ObjectDeserializerContext} context context
*/
deserialize(context) {
const { read } = context;
this.ids = read();
this.specifier = read();
this.range = read();
this.shorthand = read();
super.deserialize(context);
}
}
DestructuringAssignmentPropertyKeyDependency.Template = class DestructuringAssignmentPropertyIdDependencyTemplate extends (
NullDependency.Template
) {
/**
* @param {Dependency} dependency the dependency for which the template should be applied
* @param {ReplaceSource} source the current replace source which can be modified
* @param {DependencyTemplateContext} templateContext the context object
* @returns {void}
*/
apply(dependency, source, { moduleGraph, runtime }) {
const dep = /** @type {DestructuringAssignmentPropertyKeyDependency} */ (
dependency
);
const { ids, specifier, shorthand } = dep;
const specifierIds = specifier.ids.slice(
specifier.ids[0] === "default" ? 1 : 0
);
const module = moduleGraph.getModule(specifier);
const used = moduleGraph
.getExportsInfo(module)
.getUsedName(specifierIds.concat(ids), runtime);
if (!used) return;
const newName = used[used.length - 1];
const name = ids[ids.length - 1];
if (newName === name) return;
const comment = Template.toNormalComment(name) + " ";
const key = comment + JSON.stringify(newName);
source.replace(
dep.range[0],
dep.range[1] - 1,
shorthand ? `${key}: ${name}` : `${key}`
);
}
};
makeSerializable(
DestructuringAssignmentPropertyKeyDependency,
"webpack/lib/dependencies/DestructuringAssignmentPropertyKeyDependency"
);
module.exports = DestructuringAssignmentPropertyKeyDependency;
module.exports.traversePropertyInDestructuring =
traversePropertyInDestructuring;
module.exports.getAllIdsInDestructuring = getAllIdsInDestructuring;

View File

@ -0,0 +1,188 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Gengkun He @ahabhgk
*/
"use strict";
const Template = require("../Template");
const makeSerializable = require("../util/makeSerializable");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../Dependency").ReferencedExport} ReferencedExport */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../javascript/JavascriptParser").Attributes} Attributes */
/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/**
* @param {DestructuringAssignmentProperty} property property
* @param {((property: DestructuringAssignmentProperty) => void) | undefined=} onProperty on property
* @param {((property: DestructuringAssignmentProperty) => void) | undefined=} onClean on property end
* @param {(() => void) | undefined=} onTerminate on a terminal property
*/
function traversePropertyInDestructuring(
property,
onProperty,
onClean,
onTerminate
) {
onProperty && onProperty(property);
if (!property.pattern) {
onTerminate && onTerminate();
} else {
for (const p of property.pattern) {
traversePropertyInDestructuring(p, onProperty, onClean, onTerminate);
}
}
onClean && onClean(property);
}
class HarmonyDestructuredImportSpecifierDependency extends HarmonyImportSpecifierDependency {
/**
* @param {string} request the request string
* @param {number} sourceOrder source order
* @param {string[]} ids ids
* @param {string} name name
* @param {Range} range range
* @param {TODO} exportPresenceMode export presence mode
* @param {Attributes | undefined} attributes assertions
* @param {Range[] | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
*/
constructor(
request,
sourceOrder,
ids,
name,
range,
exportPresenceMode,
attributes,
idRanges
) {
super(
request,
sourceOrder,
ids,
name,
range,
exportPresenceMode,
attributes,
idRanges
);
/** @type {{ ids: string[], range: Range | undefined, shorthand: boolean | string }[]} */
this.flattenedProperties = [];
/** @type {string[][]} */
this.allIdsInDestructuring = [];
}
get type() {
return "destructured harmony import specifier";
}
/**
* @param {Set<DestructuringAssignmentProperty>} properties destructuring assignment properties
*/
setDestructuringAssignmentProperties(properties) {
for (const property of properties) {
const ids = [];
traversePropertyInDestructuring(
property,
({ id, range, shorthand }) => {
ids.push(id);
this.flattenedProperties.push({
ids: [...ids],
range,
shorthand
});
},
() => ids.pop(),
() => this.allIdsInDestructuring.push([...ids])
);
}
}
/**
* @param {string[]=} ids ids
* @returns {string[][]} referenced exports
*/
_getReferencedExportsInDestructuring(ids) {
return this.allIdsInDestructuring.map(idsInDestructuring =>
ids ? ids.concat(idsInDestructuring) : idsInDestructuring
);
}
/**
* @param {ObjectSerializerContext} context context
*/
serialize(context) {
const { write } = context;
write(this.properties);
write(this.flattenedProperties);
write(this.allIdsInDestructuring);
super.serialize(context);
}
/**
* @param {ObjectDeserializerContext} context context
*/
deserialize(context) {
const { read } = context;
this.properties = read();
this.flattenedProperties = read();
this.allIdsInDestructuring = read();
super.deserialize(context);
}
}
HarmonyDestructuredImportSpecifierDependency.Template = class HarmonyDestructuredImportSpecifierDependencyTemplate extends (
HarmonyImportSpecifierDependency.Template
) {
/**
* @param {Dependency} dependency the dependency for which the template should be applied
* @param {ReplaceSource} source the current replace source which can be modified
* @param {DependencyTemplateContext} templateContext the context object
* @returns {void}
*/
apply(dependency, source, templateContext) {
super.apply(dependency, source, templateContext);
const { moduleGraph, runtime } = templateContext;
const dep = /** @type {HarmonyDestructuredImportSpecifierDependency} */ (
dependency
);
const { flattenedProperties } = dep;
for (const {
ids: idsInDestructuring,
range,
shorthand
} of flattenedProperties) {
const ids = dep.ids.concat(idsInDestructuring);
if (ids[0] === "default") ids.shift();
const module = moduleGraph.getModule(dep);
const used = moduleGraph.getExportsInfo(module).getUsedName(ids, runtime);
if (!used) return;
const newName = used[used.length - 1];
const name = ids[ids.length - 1];
if (newName === name) continue;
const comment = Template.toNormalComment(name) + " ";
const key = comment + JSON.stringify(newName);
source.replace(
range[0],
range[1] - 1,
shorthand ? `${key}: ${name}` : `${key}`
);
}
}
};
makeSerializable(
HarmonyDestructuredImportSpecifierDependency,
"webpack/lib/dependencies/HarmonyDestructuredImportSpecifierDependency"
);
module.exports = HarmonyDestructuredImportSpecifierDependency;

View File

@ -8,9 +8,9 @@
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
const InnerGraph = require("../optimize/InnerGraph");
const ConstDependency = require("./ConstDependency");
const DestructuringAssignmentPropertyKeyDependency = require("./DestructuringAssignmentPropertyKeyDependency");
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
const HarmonyDestructuredImportSpecifierDependency = require("./HarmonyDestructuredImportSpecifierDependency");
const HarmonyEvaluatedImportSpecifierDependency = require("./HarmonyEvaluatedImportSpecifierDependency");
const HarmonyExports = require("./HarmonyExports");
const { ExportPresenceModes } = require("./HarmonyImportDependency");
@ -94,36 +94,6 @@ function getAttributes(node) {
return result;
}
/**
* @param {Set<DestructuringAssignmentProperty>} properties properties
* @param {HarmonyImportSpecifierDependency} specifier import specifier dependency
* @param {JavascriptParser} parser javascript parser
*/
function replaceDestructuringAssignmentPropertiesKeys(
properties,
specifier,
parser
) {
for (const p of properties) {
const ids = [];
DestructuringAssignmentPropertyKeyDependency.traversePropertyInDestructuring(
p,
p => {
ids.push(p.id);
if (!p.range) return;
const dep = new DestructuringAssignmentPropertyKeyDependency(
[...ids],
specifier,
p.range,
p.shorthand
);
parser.state.module.addPresentationalDependency(dep);
},
() => ids.pop()
);
}
}
module.exports = class HarmonyImportDependencyParserPlugin {
/**
* @param {JavascriptParserOptions} options options
@ -254,7 +224,11 @@ module.exports = class HarmonyImportDependencyParserPlugin {
.for(harmonySpecifierTag)
.tap("HarmonyImportDependencyParserPlugin", expr => {
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
const dep = new HarmonyImportSpecifierDependency(
const properties = parser.destructuringAssignmentPropertiesFor(expr);
const Dep = properties
? HarmonyDestructuredImportSpecifierDependency
: HarmonyImportSpecifierDependency;
const dep = new Dep(
settings.source,
settings.sourceOrder,
settings.ids,
@ -264,14 +238,10 @@ module.exports = class HarmonyImportDependencyParserPlugin {
settings.assertions,
[]
);
dep.referencedPropertiesInDestructuring =
parser.destructuringAssignmentPropertiesFor(expr);
if (dep.referencedPropertiesInDestructuring) {
replaceDestructuringAssignmentPropertiesKeys(
dep.referencedPropertiesInDestructuring,
dep,
parser
);
if (properties) {
/** @type {HarmonyDestructuredImportSpecifierDependency} */ (
dep
).setDestructuringAssignmentProperties(properties);
}
dep.shorthand = parser.scope.inShorthand;
dep.directImport = true;
@ -308,7 +278,11 @@ module.exports = class HarmonyImportDependencyParserPlugin {
)
: expression;
const ids = settings.ids.concat(nonOptionalMembers);
const dep = new HarmonyImportSpecifierDependency(
const properties = parser.destructuringAssignmentPropertiesFor(expr);
const Dep = properties
? HarmonyDestructuredImportSpecifierDependency
: HarmonyImportSpecifierDependency;
const dep = new Dep(
settings.source,
settings.sourceOrder,
ids,
@ -318,14 +292,10 @@ module.exports = class HarmonyImportDependencyParserPlugin {
settings.assertions,
ranges
);
dep.referencedPropertiesInDestructuring =
parser.destructuringAssignmentPropertiesFor(expr);
if (dep.referencedPropertiesInDestructuring) {
replaceDestructuringAssignmentPropertiesKeys(
dep.referencedPropertiesInDestructuring,
dep,
parser
);
if (properties) {
/** @type {HarmonyDestructuredImportSpecifierDependency} */ (
dep
).setDestructuringAssignmentProperties(properties);
}
dep.asiSafe = !parser.isAsiPosition(
/** @type {Range} */ (expr.range)[0]

View File

@ -12,9 +12,6 @@ const {
const { getTrimmedIdsAndRange } = require("../util/chainedImports");
const makeSerializable = require("../util/makeSerializable");
const propertyAccess = require("../util/propertyAccess");
const {
getAllIdsInDestructuring
} = require("./DestructuringAssignmentPropertyKeyDependency");
const HarmonyImportDependency = require("./HarmonyImportDependency");
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
@ -50,8 +47,8 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
* @param {string} name name
* @param {Range} range range
* @param {TODO} exportPresenceMode export presence mode
* @param {Attributes=} attributes assertions
* @param {Range[]=} idRanges ranges for members of ids; the two arrays are right-aligned
* @param {Attributes | undefined} attributes assertions
* @param {Range[] | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
*/
constructor(
request,
@ -188,24 +185,10 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
/**
* @param {string[]=} ids ids
* @returns {(string[] | ReferencedExport)[]} referenced exports
* @returns {string[][]} referenced exports
*/
_getReferencedExportsInDestructuring(ids) {
if (this.referencedPropertiesInDestructuring) {
/** @type {ReferencedExport[]} */
const refs = [];
for (const idsInDestructuring of getAllIdsInDestructuring(
this.referencedPropertiesInDestructuring
)) {
refs.push({
name: ids ? ids.concat(idsInDestructuring) : idsInDestructuring,
canMangle: true
});
}
return refs;
} else {
return ids ? [ids] : Dependency.EXPORTS_OBJECT_REFERENCED;
}
return ids ? [ids] : Dependency.EXPORTS_OBJECT_REFERENCED;
}
/**

View File

@ -20,7 +20,7 @@ const {
JAVASCRIPT_MODULE_TYPE_AUTO,
JAVASCRIPT_MODULE_TYPE_ESM
} = require("../ModuleTypeConstants");
const DestructuringAssignmentPropertyKeyDependency = require("./DestructuringAssignmentPropertyKeyDependency");
const HarmonyDestructuredImportSpecifierDependency = require("./HarmonyDestructuredImportSpecifierDependency");
const HarmonyDetectionParserPlugin = require("./HarmonyDetectionParserPlugin");
const HarmonyExportDependencyParserPlugin = require("./HarmonyExportDependencyParserPlugin");
const HarmonyImportDependencyParserPlugin = require("./HarmonyImportDependencyParserPlugin");
@ -83,6 +83,15 @@ class HarmonyModulesPlugin {
new HarmonyEvaluatedImportSpecifierDependency.Template()
);
compilation.dependencyFactories.set(
HarmonyDestructuredImportSpecifierDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
HarmonyDestructuredImportSpecifierDependency,
new HarmonyDestructuredImportSpecifierDependency.Template()
);
compilation.dependencyTemplates.set(
HarmonyExportHeaderDependency,
new HarmonyExportHeaderDependency.Template()
@ -121,15 +130,6 @@ class HarmonyModulesPlugin {
new HarmonyAcceptImportDependency.Template()
);
compilation.dependencyFactories.set(
DestructuringAssignmentPropertyKeyDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
DestructuringAssignmentPropertyKeyDependency,
new DestructuringAssignmentPropertyKeyDependency.Template()
);
/**
* @param {Parser} parser parser parser
* @param {JavascriptParserOptions} parserOptions parserOptions

View File

@ -83,8 +83,8 @@ module.exports = {
require("../dependencies/CssUrlDependency"),
"dependencies/DelegatedSourceDependency": () =>
require("../dependencies/DelegatedSourceDependency"),
"dependencies/DestructuringAssignmentPropertyKeyDependency": () =>
require("../dependencies/DestructuringAssignmentPropertyKeyDependency"),
"dependencies/HarmonyDestructuredImportSpecifierDependency": () =>
require("../dependencies/HarmonyDestructuredImportSpecifierDependency"),
"dependencies/DllEntryDependency": () =>
require("../dependencies/DllEntryDependency"),
"dependencies/EntryDependency": () =>