From 9bce51f651aad297ef9eb6df832bfdaf1de05d84 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期三, 22 四月 2026 14:27:54 +0800
Subject: [PATCH] 青岛推送
---
node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js | 280 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 230 insertions(+), 50 deletions(-)
diff --git a/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js
index cef9b10..40c295a 100644
--- a/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js
+++ b/node_modules/webpack/lib/dependencies/HarmonyImportDependencyParserPlugin.js
@@ -12,17 +12,22 @@
getImportAttributes
} = require("../javascript/JavascriptParser");
const InnerGraph = require("../optimize/InnerGraph");
+const AppendOnlyStackedSet = require("../util/AppendOnlyStackedSet");
const ConstDependency = require("./ConstDependency");
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
const HarmonyEvaluatedImportSpecifierDependency = require("./HarmonyEvaluatedImportSpecifierDependency");
const HarmonyExports = require("./HarmonyExports");
-const { ExportPresenceModes } = require("./HarmonyImportDependency");
+const {
+ ExportPresenceModes,
+ getNonOptionalPart
+} = require("./HarmonyImportDependency");
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
const { ImportPhaseUtils, createGetImportPhase } = require("./ImportPhase");
/** @typedef {import("estree").Expression} Expression */
+/** @typedef {import("estree").PrivateIdentifier} PrivateIdentifier */
/** @typedef {import("estree").Identifier} Identifier */
/** @typedef {import("estree").MemberExpression} MemberExpression */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
@@ -36,11 +41,22 @@
/** @typedef {import("../javascript/JavascriptParser").Members} Members */
/** @typedef {import("../javascript/JavascriptParser").MembersOptionals} MembersOptionals */
/** @typedef {import("./HarmonyImportDependency").Ids} Ids */
+/** @typedef {import("./HarmonyImportDependency").ExportPresenceMode} ExportPresenceMode */
/** @typedef {import("./ImportPhase").ImportPhaseType} ImportPhaseType */
+/**
+ * Defines the harmony specifier guards type used by this module.
+ * @typedef {object} HarmonySpecifierGuards
+ * @property {AppendOnlyStackedSet<string> | undefined} guards
+ */
+
+/** @typedef {Map<string, Set<string>>} Guards Map of import root to guarded member keys */
+
const harmonySpecifierTag = Symbol("harmony import");
+const harmonySpecifierGuardTag = Symbol("harmony import guard");
/**
+ * Defines the harmony settings type used by this module.
* @typedef {object} HarmonySettings
* @property {Ids} ids
* @property {string} source
@@ -53,44 +69,101 @@
const PLUGIN_NAME = "HarmonyImportDependencyParserPlugin";
+/**
+ * Gets in operator harmony import info.
+ * @param {JavascriptParser} parser the parser
+ * @param {PrivateIdentifier | Expression} left left expression
+ * @param {Expression} right right expression
+ * @returns {{ leftPart: string, members: Members, settings: HarmonySettings } | undefined} info
+ */
+const getInOperatorHarmonyImportInfo = (parser, left, right) => {
+ const leftPartEvaluated = parser.evaluateExpression(left);
+ if (leftPartEvaluated.couldHaveSideEffects()) return;
+ /** @type {string | undefined} */
+ const leftPart = leftPartEvaluated.asString();
+ if (!leftPart) return;
+
+ const rightPart = parser.evaluateExpression(right);
+ if (!rightPart.isIdentifier()) return;
+
+ const rootInfo = rightPart.rootInfo;
+ const root =
+ typeof rootInfo === "string"
+ ? rootInfo
+ : rootInfo instanceof VariableInfo
+ ? rootInfo.name
+ : undefined;
+ if (!root) return;
+
+ const settings = /** @type {HarmonySettings | undefined} */ (
+ parser.getTagData(root, harmonySpecifierTag)
+ );
+ if (!settings) {
+ return;
+ }
+
+ return {
+ leftPart,
+ members: /** @type {(() => Members)} */ (rightPart.getMembers)(),
+ settings
+ };
+};
+
module.exports = class HarmonyImportDependencyParserPlugin {
/**
+ * Creates an instance of HarmonyImportDependencyParserPlugin.
* @param {JavascriptParserOptions} options options
*/
constructor(options) {
this.options = options;
- this.exportPresenceMode =
- options.importExportsPresence !== undefined
- ? ExportPresenceModes.fromUserOption(options.importExportsPresence)
- : options.exportsPresence !== undefined
- ? ExportPresenceModes.fromUserOption(options.exportsPresence)
- : options.strictExportPresence
- ? ExportPresenceModes.ERROR
- : ExportPresenceModes.AUTO;
+ /** @type {ExportPresenceMode} */
+ this.exportPresenceMode = ExportPresenceModes.resolveFromOptions(
+ options.importExportsPresence,
+ options
+ );
this.strictThisContextOnImports = options.strictThisContextOnImports;
}
/**
+ * Gets export presence mode.
+ * @param {JavascriptParser} parser the parser
+ * @param {HarmonySettings} settings settings
+ * @param {Ids} ids ids
+ * @returns {ExportPresenceMode} exportPresenceMode
+ */
+ getExportPresenceMode(parser, settings, ids) {
+ // Guards only apply to namespace imports
+ if (settings.ids.length) return this.exportPresenceMode;
+
+ const harmonySettings = /** @type {HarmonySettings=} */ (
+ parser.currentTagData
+ );
+ if (!harmonySettings) return this.exportPresenceMode;
+
+ const data = /** @type {HarmonySpecifierGuards=} */ (
+ parser.getTagData(harmonySettings.name, harmonySpecifierGuardTag)
+ );
+
+ if (data && data.guards && data.guards.has(ids[0])) {
+ return ExportPresenceModes.NONE;
+ }
+
+ return this.exportPresenceMode;
+ }
+
+ /**
+ * Applies the plugin by registering its hooks on the compiler.
* @param {JavascriptParser} parser the parser
* @returns {void}
*/
apply(parser) {
- const { exportPresenceMode } = this;
-
- const getImportPhase = createGetImportPhase(this.options.deferImport);
+ const getImportPhase = createGetImportPhase(
+ this.options.deferImport,
+ this.options.sourceImport
+ );
/**
- * @param {Members} members members
- * @param {MembersOptionals} membersOptionals members Optionals
- * @returns {Ids} a non optional part
- */
- function getNonOptionalPart(members, membersOptionals) {
- let i = 0;
- while (i < members.length && membersOptionals[i] === false) i++;
- return i !== members.length ? members.slice(0, i) : members;
- }
-
- /**
+ * Gets non optional member chain.
* @param {MemberExpression} node member expression
* @param {number} count count
* @returns {Expression} member expression
@@ -167,31 +240,14 @@
);
parser.hooks.binaryExpression.tap(PLUGIN_NAME, (expression) => {
if (expression.operator !== "in") return;
+ const info = getInOperatorHarmonyImportInfo(
+ parser,
+ expression.left,
+ expression.right
+ );
+ if (!info) return;
- const leftPartEvaluated = parser.evaluateExpression(expression.left);
- if (leftPartEvaluated.couldHaveSideEffects()) return;
- /** @type {string | undefined} */
- const leftPart = leftPartEvaluated.asString();
- if (!leftPart) return;
-
- const rightPart = parser.evaluateExpression(expression.right);
- if (!rightPart.isIdentifier()) return;
-
- const rootInfo = rightPart.rootInfo;
- if (
- typeof rootInfo === "string" ||
- !rootInfo ||
- !rootInfo.tagInfo ||
- rootInfo.tagInfo.tag !== harmonySpecifierTag
- ) {
- return;
- }
- const settings =
- /** @type {HarmonySettings} */
- (rootInfo.tagInfo.data);
- const members =
- /** @type {(() => Members)} */
- (rightPart.getMembers)();
+ const { leftPart, members, settings } = info;
const dep = new HarmonyEvaluatedImportSpecifierDependency(
settings.source,
settings.sourceOrder,
@@ -228,6 +284,7 @@
.for(harmonySpecifierTag)
.tap(PLUGIN_NAME, (expr) => {
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
+
const dep = new HarmonyImportSpecifierDependency(
settings.source,
settings.sourceOrder,
@@ -235,7 +292,7 @@
settings.name,
/** @type {Range} */
(expr.range),
- exportPresenceMode,
+ this.exportPresenceMode,
settings.phase,
settings.attributes,
[]
@@ -285,7 +342,7 @@
settings.name,
/** @type {Range} */
(expr.range),
- exportPresenceMode,
+ this.getExportPresenceMode(parser, settings, ids),
settings.phase,
settings.attributes,
ranges
@@ -335,7 +392,7 @@
ids,
settings.name,
/** @type {Range} */ (expr.range),
- exportPresenceMode,
+ this.getExportPresenceMode(parser, settings, ids),
settings.phase,
settings.attributes,
ranges
@@ -402,7 +459,130 @@
parser.state.module.addDependency(dep);
}
});
+
+ /**
+ * Processes the provided guard.
+ * @param {Guards} guards guards
+ * @param {() => void} walk walk callback
+ * @returns {void}
+ */
+ const withGuards = (guards, walk) => {
+ const applyGuards = () => {
+ /** @type {(() => void)[]} */
+ const restoreFns = [];
+
+ for (const [rootName, members] of guards) {
+ const previous = parser.getVariableInfo(rootName);
+ const exist = /** @type {HarmonySpecifierGuards=} */ (
+ parser.getTagData(rootName, harmonySpecifierGuardTag)
+ );
+
+ const mergedGuards =
+ exist && exist.guards
+ ? exist.guards.createChild()
+ : new AppendOnlyStackedSet();
+
+ for (const memberKey of members) mergedGuards.add(memberKey);
+ parser.tagVariable(rootName, harmonySpecifierGuardTag, {
+ guards: mergedGuards
+ });
+ restoreFns.push(() => {
+ parser.setVariable(rootName, previous);
+ });
+ }
+
+ return () => {
+ for (const restore of restoreFns) {
+ restore();
+ }
+ };
+ };
+
+ const restore = applyGuards();
+ try {
+ walk();
+ } finally {
+ restore();
+ }
+ };
+
+ if (this.exportPresenceMode !== ExportPresenceModes.NONE) {
+ parser.hooks.collectGuards.tap(PLUGIN_NAME, (expression) => {
+ if (parser.scope.isAsmJs) return;
+ /** @type {Guards} */
+ const guards = new Map();
+
+ /**
+ * Processes the provided expression.
+ * @param {Expression} expression expression
+ * @param {boolean} needTruthy need to be truthy
+ */
+ const collect = (expression, needTruthy) => {
+ if (
+ expression.type === "UnaryExpression" &&
+ expression.operator === "!"
+ ) {
+ collect(expression.argument, !needTruthy);
+ return;
+ } else if (expression.type === "LogicalExpression" && needTruthy) {
+ if (expression.operator === "&&") {
+ collect(expression.left, true);
+ collect(expression.right, true);
+ } else if (expression.operator === "||") {
+ const leftEvaluation = parser.evaluateExpression(expression.left);
+ const leftBool = leftEvaluation.asBool();
+ if (leftBool === false) {
+ collect(expression.right, true);
+ }
+ } else if (expression.operator === "??") {
+ const leftEvaluation = parser.evaluateExpression(expression.left);
+ const leftNullish = leftEvaluation.asNullish();
+ if (leftNullish === true) {
+ collect(expression.right, true);
+ }
+ }
+ return;
+ }
+ if (!needTruthy) return;
+
+ // Direct `"x" in ns` guards
+ if (
+ expression.type === "BinaryExpression" &&
+ expression.operator === "in"
+ ) {
+ if (expression.right.type !== "Identifier") {
+ return;
+ }
+ const info = getInOperatorHarmonyImportInfo(
+ parser,
+ expression.left,
+ expression.right
+ );
+ if (!info) return;
+
+ const { settings, leftPart, members } = info;
+ // Only direct namespace guards
+ if (members.length > 0) return;
+ const guarded = guards.get(settings.name);
+ if (guarded) {
+ guarded.add(leftPart);
+ return;
+ }
+
+ guards.set(settings.name, new Set([leftPart]));
+ }
+ };
+
+ collect(expression, true);
+
+ if (guards.size === 0) return;
+ return (walk) => {
+ withGuards(guards, walk);
+ };
+ });
+ }
}
};
+module.exports.harmonySpecifierGuardTag = harmonySpecifierGuardTag;
module.exports.harmonySpecifierTag = harmonySpecifierTag;
--
Gitblit v1.9.3