webpack/lib/dependencies/HarmonyExportDependencyPars...

247 lines
8.3 KiB
JavaScript
Raw Permalink Normal View History

2015-01-13 00:45:30 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
"use strict";
const WebpackError = require("../WebpackError");
2024-10-31 22:43:31 +08:00
const { getImportAttributes } = require("../javascript/JavascriptParser");
2020-01-29 21:24:55 +08:00
const InnerGraph = require("../optimize/InnerGraph");
2018-07-30 23:08:51 +08:00
const ConstDependency = require("./ConstDependency");
const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
const HarmonyExportImportedSpecifierDependency = require("./HarmonyExportImportedSpecifierDependency");
2018-07-30 23:08:51 +08:00
const HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
const { ExportPresenceModes } = require("./HarmonyImportDependency");
const {
2025-07-03 17:06:45 +08:00
getImportMode,
harmonySpecifierTag
} = require("./HarmonyImportDependencyParserPlugin");
2018-07-30 23:08:51 +08:00
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
2015-01-13 00:45:30 +08:00
2024-03-18 23:28:40 +08:00
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
2023-06-17 03:44:20 +08:00
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
2025-04-07 21:09:05 +08:00
/** @typedef {import("../javascript/JavascriptParser").ClassDeclaration} ClassDeclaration */
2024-03-14 23:15:13 +08:00
/** @typedef {import("../javascript/JavascriptParser").FunctionDeclaration} FunctionDeclaration */
2024-03-18 23:28:40 +08:00
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
2025-09-09 23:41:52 +08:00
/** @typedef {import("./HarmonyImportDependencyParserPlugin").HarmonySettings} HarmonySettings */
2023-06-17 03:44:20 +08:00
const { HarmonyStarExportsList } = HarmonyExportImportedSpecifierDependency;
2025-06-04 02:20:37 +08:00
const PLUGIN_NAME = "HarmonyExportDependencyParserPlugin";
module.exports = class HarmonyExportDependencyParserPlugin {
2023-05-22 08:03:05 +08:00
/**
* @param {import("../../declarations/WebpackOptions").JavascriptParserOptions} options options
*/
constructor(options) {
this.exportPresenceMode =
options.reexportExportsPresence !== undefined
? ExportPresenceModes.fromUserOption(options.reexportExportsPresence)
: options.exportsPresence !== undefined
2024-01-14 09:41:34 +08:00
? ExportPresenceModes.fromUserOption(options.exportsPresence)
: options.strictExportPresence
? ExportPresenceModes.ERROR
: ExportPresenceModes.AUTO;
this.deferImport = options.deferImport;
}
2024-03-14 23:15:13 +08:00
/**
* @param {JavascriptParser} parser the parser
* @returns {void}
*/
apply(parser) {
const { exportPresenceMode } = this;
parser.hooks.export.tap(PLUGIN_NAME, (statement) => {
2025-06-04 02:20:37 +08:00
const dep = new HarmonyExportHeaderDependency(
/** @type {Range | false} */ (
statement.declaration && statement.declaration.range
),
/** @type {Range} */ (statement.range)
);
dep.loc = Object.create(
/** @type {DependencyLocation} */ (statement.loc)
);
dep.loc.index = -1;
parser.state.module.addPresentationalDependency(dep);
return true;
});
parser.hooks.exportImport.tap(PLUGIN_NAME, (statement, source) => {
parser.state.lastHarmonyImportOrder =
(parser.state.lastHarmonyImportOrder || 0) + 1;
const clearDep = new ConstDependency(
"",
/** @type {Range} */ (statement.range)
);
clearDep.loc = /** @type {DependencyLocation} */ (statement.loc);
clearDep.loc.index = -1;
parser.state.module.addPresentationalDependency(clearDep);
let defer = false;
if (this.deferImport) {
({ defer } = getImportMode(parser, statement));
if (defer) {
const error = new WebpackError(
"Deferred re-export (`export defer * as namespace from '...'`) is not a part of the Import Defer proposal.\nUse the following code instead:\n import defer * as namespace from '...';\n export { namespace };"
);
error.loc = statement.loc || undefined;
parser.state.current.addError(error);
}
}
2025-06-04 02:20:37 +08:00
const sideEffectDep = new HarmonyImportSideEffectDependency(
/** @type {string} */ (source),
parser.state.lastHarmonyImportOrder,
getImportAttributes(statement),
defer
2025-06-04 02:20:37 +08:00
);
sideEffectDep.loc = Object.create(
/** @type {DependencyLocation} */ (statement.loc)
);
sideEffectDep.loc.index = -1;
parser.state.current.addDependency(sideEffectDep);
return true;
});
parser.hooks.exportExpression.tap(PLUGIN_NAME, (statement, node) => {
const isFunctionDeclaration = node.type === "FunctionDeclaration";
const exprRange = /** @type {Range} */ (node.range);
const statementRange = /** @type {Range} */ (statement.range);
const comments = parser.getComments([statementRange[0], exprRange[0]]);
const dep = new HarmonyExportExpressionDependency(
exprRange,
statementRange,
comments
.map((c) => {
2025-06-04 02:20:37 +08:00
switch (c.type) {
case "Block":
return `/*${c.value}*/`;
case "Line":
return `//${c.value}\n`;
}
return "";
})
.join(""),
node.type.endsWith("Declaration") &&
/** @type {FunctionDeclaration | ClassDeclaration} */ (node).id
? /** @type {FunctionDeclaration | ClassDeclaration} */
(node).id.name
: isFunctionDeclaration
? {
range: [
exprRange[0],
node.params.length > 0
? /** @type {Range} */ (node.params[0].range)[0]
: /** @type {Range} */ (node.body.range)[0]
],
prefix: `${node.async ? "async " : ""}function${
node.generator ? "*" : ""
} `,
suffix: `(${node.params.length > 0 ? "" : ") "}`
}
2025-06-04 02:20:37 +08:00
: undefined
);
dep.loc = Object.create(
/** @type {DependencyLocation} */ (statement.loc)
);
dep.loc.index = -1;
parser.state.current.addDependency(dep);
InnerGraph.addVariableUsage(
parser,
node.type.endsWith("Declaration") &&
2025-04-07 21:09:05 +08:00
/** @type {FunctionDeclaration | ClassDeclaration} */ (node).id
2025-06-04 02:20:37 +08:00
? /** @type {FunctionDeclaration | ClassDeclaration} */ (node).id.name
: "*default*",
"default"
);
return true;
});
2018-02-25 09:00:20 +08:00
parser.hooks.exportSpecifier.tap(
2025-06-04 02:20:37 +08:00
PLUGIN_NAME,
2018-02-25 09:00:20 +08:00
(statement, id, name, idx) => {
2025-09-09 23:41:52 +08:00
const settings =
/** @type {HarmonySettings} */
(parser.getTagData(id, harmonySpecifierTag));
2018-02-25 09:00:20 +08:00
const harmonyNamedExports = (parser.state.harmonyNamedExports =
parser.state.harmonyNamedExports || new Set());
harmonyNamedExports.add(name);
2020-01-29 21:24:55 +08:00
InnerGraph.addVariableUsage(parser, id, name);
2024-08-02 02:36:27 +08:00
const dep = settings
? new HarmonyExportImportedSpecifierDependency(
settings.source,
settings.sourceOrder,
settings.ids,
name,
harmonyNamedExports,
null,
exportPresenceMode,
null,
settings.attributes,
settings.defer
2024-08-02 02:36:27 +08:00
)
: new HarmonyExportSpecifierDependency(id, name);
2024-03-18 23:28:40 +08:00
dep.loc = Object.create(
/** @type {DependencyLocation} */ (statement.loc)
);
2018-02-25 09:00:20 +08:00
dep.loc.index = idx;
2024-08-15 20:32:58 +08:00
const isAsiSafe = !parser.isAsiPosition(
/** @type {Range} */
(statement.range)[0]
);
if (!isAsiSafe) {
parser.setAsiPosition(/** @type {Range} */ (statement.range)[1]);
}
2018-02-25 09:00:20 +08:00
parser.state.current.addDependency(dep);
return true;
}
2018-02-25 09:00:20 +08:00
);
parser.hooks.exportImportSpecifier.tap(
2025-06-04 02:20:37 +08:00
PLUGIN_NAME,
2018-02-25 09:00:20 +08:00
(statement, source, id, name, idx) => {
const harmonyNamedExports = (parser.state.harmonyNamedExports =
parser.state.harmonyNamedExports || new Set());
2025-07-03 17:06:45 +08:00
/** @type {InstanceType<HarmonyStarExportsList> | null} */
2018-02-25 09:00:20 +08:00
let harmonyStarExports = null;
if (name) {
harmonyNamedExports.add(name);
} else {
harmonyStarExports = parser.state.harmonyStarExports =
parser.state.harmonyStarExports || new HarmonyStarExportsList();
2018-02-25 09:00:20 +08:00
}
const attributes = getImportAttributes(statement);
const defer = this.deferImport
? getImportMode(parser, statement).defer
: false;
2018-02-25 09:00:20 +08:00
const dep = new HarmonyExportImportedSpecifierDependency(
2025-07-03 17:06:45 +08:00
/** @type {string} */
(source),
2018-02-25 09:00:20 +08:00
parser.state.lastHarmonyImportOrder,
id ? [id] : [],
2018-02-25 09:00:20 +08:00
name,
harmonyNamedExports,
2025-07-03 17:06:45 +08:00
// eslint-disable-next-line unicorn/prefer-spread
2018-02-25 09:00:20 +08:00
harmonyStarExports && harmonyStarExports.slice(),
exportPresenceMode,
harmonyStarExports,
attributes,
defer
2018-02-25 09:00:20 +08:00
);
if (harmonyStarExports) {
harmonyStarExports.push(dep);
}
2024-03-18 23:28:40 +08:00
dep.loc = Object.create(
/** @type {DependencyLocation} */ (statement.loc)
);
2018-02-25 09:00:20 +08:00
dep.loc.index = idx;
const isAsiSafe = !parser.isAsiPosition(
/** @type {Range} */
(statement.range)[0]
);
if (!isAsiSafe) {
parser.setAsiPosition(/** @type {Range} */ (statement.range)[1]);
}
2018-02-25 09:00:20 +08:00
parser.state.current.addDependency(dep);
return true;
}
2018-02-25 09:00:20 +08:00
);
2015-01-13 00:45:30 +08:00
}
};