|
|
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
-
- const DependencyReference = require("./DependencyReference");
- const HarmonyImportDependency = require("./HarmonyImportDependency");
- const Template = require("../Template");
- const HarmonyLinkingError = require("../HarmonyLinkingError");
-
- /** @typedef {import("../Module")} Module */
-
- /** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-non-harmony-default-strict"|"reexport-fake-namespace-object"|"rexport-non-harmony-undefined"|"safe-reexport"|"checked-reexport"|"dynamic-reexport"} ExportModeType */
-
- /** @type {Map<string, string>} */
- const EMPTY_MAP = new Map();
-
- class ExportMode {
- /**
- * @param {ExportModeType} type type of the mode
- */
- constructor(type) {
- /** @type {ExportModeType} */
- this.type = type;
- /** @type {string|null} */
- this.name = null;
- /** @type {Map<string, string>} */
- this.map = EMPTY_MAP;
- /** @type {Module|null} */
- this.module = null;
- /** @type {string|null} */
- this.userRequest = null;
- }
- }
-
- const EMPTY_STAR_MODE = new ExportMode("empty-star");
-
- class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
- constructor(
- request,
- originModule,
- sourceOrder,
- parserScope,
- id,
- name,
- activeExports,
- otherStarExports,
- strictExportPresence
- ) {
- super(request, originModule, sourceOrder, parserScope);
- this.id = id;
- this.redirectedId = undefined;
- this.name = name;
- this.activeExports = activeExports;
- this.otherStarExports = otherStarExports;
- this.strictExportPresence = strictExportPresence;
- }
-
- get type() {
- return "harmony export imported specifier";
- }
-
- get _id() {
- return this.redirectedId || this.id;
- }
-
- getMode(ignoreUnused) {
- const name = this.name;
- const id = this._id;
- const used = this.originModule.isUsed(name);
- const importedModule = this._module;
-
- if (!importedModule) {
- const mode = new ExportMode("missing");
- mode.userRequest = this.userRequest;
- return mode;
- }
-
- if (
- !ignoreUnused &&
- (name ? !used : this.originModule.usedExports === false)
- ) {
- const mode = new ExportMode("unused");
- mode.name = name || "*";
- return mode;
- }
-
- const strictHarmonyModule = this.originModule.buildMeta.strictHarmonyModule;
- if (name && id === "default" && importedModule.buildMeta) {
- if (!importedModule.buildMeta.exportsType) {
- const mode = new ExportMode(
- strictHarmonyModule
- ? "reexport-non-harmony-default-strict"
- : "reexport-non-harmony-default"
- );
- mode.name = name;
- mode.module = importedModule;
- return mode;
- } else if (importedModule.buildMeta.exportsType === "named") {
- const mode = new ExportMode("reexport-named-default");
- mode.name = name;
- mode.module = importedModule;
- return mode;
- }
- }
-
- const isNotAHarmonyModule =
- importedModule.buildMeta && !importedModule.buildMeta.exportsType;
- if (name) {
- let mode;
- if (id) {
- // export { name as name }
- if (isNotAHarmonyModule && strictHarmonyModule) {
- mode = new ExportMode("rexport-non-harmony-undefined");
- mode.name = name;
- } else {
- mode = new ExportMode("safe-reexport");
- mode.map = new Map([[name, id]]);
- }
- } else {
- // export { * as name }
- if (isNotAHarmonyModule && strictHarmonyModule) {
- mode = new ExportMode("reexport-fake-namespace-object");
- mode.name = name;
- } else {
- mode = new ExportMode("reexport-namespace-object");
- mode.name = name;
- }
- }
- mode.module = importedModule;
- return mode;
- }
-
- const hasUsedExports = Array.isArray(this.originModule.usedExports);
- const hasProvidedExports = Array.isArray(
- importedModule.buildMeta.providedExports
- );
- const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
-
- // export *
- if (hasUsedExports) {
- // reexport * with known used exports
- if (hasProvidedExports) {
- const map = new Map(
- this.originModule.usedExports
- .filter(id => {
- if (id === "default") return false;
- if (this.activeExports.has(id)) return false;
- if (activeFromOtherStarExports.has(id)) return false;
- if (!importedModule.buildMeta.providedExports.includes(id))
- return false;
- return true;
- })
- .map(item => [item, item])
- );
-
- if (map.size === 0) {
- return EMPTY_STAR_MODE;
- }
-
- const mode = new ExportMode("safe-reexport");
- mode.module = importedModule;
- mode.map = map;
- return mode;
- }
-
- const map = new Map(
- this.originModule.usedExports
- .filter(id => {
- if (id === "default") return false;
- if (this.activeExports.has(id)) return false;
- if (activeFromOtherStarExports.has(id)) return false;
-
- return true;
- })
- .map(item => [item, item])
- );
-
- if (map.size === 0) {
- return EMPTY_STAR_MODE;
- }
-
- const mode = new ExportMode("checked-reexport");
- mode.module = importedModule;
- mode.map = map;
- return mode;
- }
-
- if (hasProvidedExports) {
- const map = new Map(
- importedModule.buildMeta.providedExports
- .filter(id => {
- if (id === "default") return false;
- if (this.activeExports.has(id)) return false;
- if (activeFromOtherStarExports.has(id)) return false;
-
- return true;
- })
- .map(item => [item, item])
- );
-
- if (map.size === 0) {
- return EMPTY_STAR_MODE;
- }
-
- const mode = new ExportMode("safe-reexport");
- mode.module = importedModule;
- mode.map = map;
- return mode;
- }
-
- const mode = new ExportMode("dynamic-reexport");
- mode.module = importedModule;
- return mode;
- }
-
- getReference() {
- const mode = this.getMode(false);
-
- switch (mode.type) {
- case "missing":
- case "unused":
- case "empty-star":
- return null;
-
- case "reexport-non-harmony-default":
- case "reexport-named-default":
- return new DependencyReference(
- mode.module,
- ["default"],
- false,
- this.sourceOrder
- );
-
- case "reexport-namespace-object":
- case "reexport-non-harmony-default-strict":
- case "reexport-fake-namespace-object":
- case "rexport-non-harmony-undefined":
- return new DependencyReference(
- mode.module,
- true,
- false,
- this.sourceOrder
- );
-
- case "safe-reexport":
- case "checked-reexport":
- return new DependencyReference(
- mode.module,
- Array.from(mode.map.values()),
- false,
- this.sourceOrder
- );
-
- case "dynamic-reexport":
- return new DependencyReference(
- mode.module,
- true,
- false,
- this.sourceOrder
- );
-
- default:
- throw new Error(`Unknown mode ${mode.type}`);
- }
- }
-
- _discoverActiveExportsFromOtherStartExports() {
- if (!this.otherStarExports) return new Set();
- const result = new Set();
- // try to learn impossible exports from other star exports with provided exports
- for (const otherStarExport of this.otherStarExports) {
- const otherImportedModule = otherStarExport._module;
- if (
- otherImportedModule &&
- Array.isArray(otherImportedModule.buildMeta.providedExports)
- ) {
- for (const exportName of otherImportedModule.buildMeta
- .providedExports) {
- result.add(exportName);
- }
- }
- }
- return result;
- }
-
- getExports() {
- if (this.name) {
- return {
- exports: [this.name],
- dependencies: undefined
- };
- }
-
- const importedModule = this._module;
-
- if (!importedModule) {
- // no imported module available
- return {
- exports: null,
- dependencies: undefined
- };
- }
-
- if (Array.isArray(importedModule.buildMeta.providedExports)) {
- return {
- exports: importedModule.buildMeta.providedExports.filter(
- id => id !== "default"
- ),
- dependencies: [importedModule]
- };
- }
-
- if (importedModule.buildMeta.providedExports) {
- return {
- exports: true,
- dependencies: undefined
- };
- }
-
- return {
- exports: null,
- dependencies: [importedModule]
- };
- }
-
- getWarnings() {
- if (
- this.strictExportPresence ||
- this.originModule.buildMeta.strictHarmonyModule
- ) {
- return [];
- }
- return this._getErrors();
- }
-
- getErrors() {
- if (
- this.strictExportPresence ||
- this.originModule.buildMeta.strictHarmonyModule
- ) {
- return this._getErrors();
- }
- return [];
- }
-
- _getErrors() {
- const importedModule = this._module;
- if (!importedModule) {
- return;
- }
-
- if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
- // It's not an harmony module
- if (
- this.originModule.buildMeta.strictHarmonyModule &&
- this._id &&
- this._id !== "default"
- ) {
- // In strict harmony modules we only support the default export
- return [
- new HarmonyLinkingError(
- `Can't reexport the named export '${this._id}' from non EcmaScript module (only default export is available)`
- )
- ];
- }
- return;
- }
-
- if (!this._id) {
- return;
- }
-
- if (importedModule.isProvided(this._id) !== false) {
- // It's provided or we are not sure
- return;
- }
-
- // We are sure that it's not provided
- const idIsNotNameMessage =
- this._id !== this.name ? ` (reexported as '${this.name}')` : "";
- const errorMessage = `"export '${this._id}'${idIsNotNameMessage} was not found in '${this.userRequest}'`;
- return [new HarmonyLinkingError(errorMessage)];
- }
-
- updateHash(hash) {
- super.updateHash(hash);
- const hashValue = this.getHashValue(this._module);
- hash.update(hashValue);
- }
-
- getHashValue(importedModule) {
- if (!importedModule) {
- return "";
- }
-
- const stringifiedUsedExport = JSON.stringify(importedModule.usedExports);
- const stringifiedProvidedExport = JSON.stringify(
- importedModule.buildMeta.providedExports
- );
- return (
- importedModule.used + stringifiedUsedExport + stringifiedProvidedExport
- );
- }
-
- disconnect() {
- super.disconnect();
- this.redirectedId = undefined;
- }
- }
-
- module.exports = HarmonyExportImportedSpecifierDependency;
-
- HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends HarmonyImportDependency.Template {
- harmonyInit(dep, source, runtime, dependencyTemplates) {
- super.harmonyInit(dep, source, runtime, dependencyTemplates);
- const content = this.getContent(dep);
- source.insert(-1, content);
- }
-
- getHarmonyInitOrder(dep) {
- if (dep.name) {
- const used = dep.originModule.isUsed(dep.name);
- if (!used) return NaN;
- } else {
- const importedModule = dep._module;
-
- const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
-
- if (Array.isArray(dep.originModule.usedExports)) {
- // we know which exports are used
-
- const unused = dep.originModule.usedExports.every(id => {
- if (id === "default") return true;
- if (dep.activeExports.has(id)) return true;
- if (importedModule.isProvided(id) === false) return true;
- if (activeFromOtherStarExports.has(id)) return true;
- return false;
- });
- if (unused) return NaN;
- } else if (
- dep.originModule.usedExports &&
- importedModule &&
- Array.isArray(importedModule.buildMeta.providedExports)
- ) {
- // not sure which exports are used, but we know which are provided
-
- const unused = importedModule.buildMeta.providedExports.every(id => {
- if (id === "default") return true;
- if (dep.activeExports.has(id)) return true;
- if (activeFromOtherStarExports.has(id)) return true;
- return false;
- });
- if (unused) return NaN;
- }
- }
- return super.getHarmonyInitOrder(dep);
- }
-
- getContent(dep) {
- const mode = dep.getMode(false);
- const module = dep.originModule;
- const importedModule = dep._module;
- const importVar = dep.getImportVar();
-
- switch (mode.type) {
- case "missing":
- return `throw new Error(${JSON.stringify(
- `Cannot find module '${mode.userRequest}'`
- )});\n`;
-
- case "unused":
- return `${Template.toNormalComment(
- `unused harmony reexport ${mode.name}`
- )}\n`;
-
- case "reexport-non-harmony-default":
- return (
- "/* harmony reexport (default from non-harmony) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(mode.name),
- importVar,
- null
- )
- );
-
- case "reexport-named-default":
- return (
- "/* harmony reexport (default from named exports) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(mode.name),
- importVar,
- ""
- )
- );
-
- case "reexport-fake-namespace-object":
- return (
- "/* harmony reexport (fake namespace object from non-harmony) */ " +
- this.getReexportFakeNamespaceObjectStatement(
- module,
- module.isUsed(mode.name),
- importVar
- )
- );
-
- case "rexport-non-harmony-undefined":
- return (
- "/* harmony reexport (non default export from non-harmony) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(mode.name),
- "undefined",
- ""
- )
- );
-
- case "reexport-non-harmony-default-strict":
- return (
- "/* harmony reexport (default from non-harmony) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(mode.name),
- importVar,
- ""
- )
- );
-
- case "reexport-namespace-object":
- return (
- "/* harmony reexport (module object) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(mode.name),
- importVar,
- ""
- )
- );
-
- case "empty-star":
- return "/* empty/unused harmony star reexport */";
-
- case "safe-reexport":
- return Array.from(mode.map.entries())
- .map(item => {
- return (
- "/* harmony reexport (safe) */ " +
- this.getReexportStatement(
- module,
- module.isUsed(item[0]),
- importVar,
- importedModule.isUsed(item[1])
- ) +
- "\n"
- );
- })
- .join("");
-
- case "checked-reexport":
- return Array.from(mode.map.entries())
- .map(item => {
- return (
- "/* harmony reexport (checked) */ " +
- this.getConditionalReexportStatement(
- module,
- item[0],
- importVar,
- item[1]
- ) +
- "\n"
- );
- })
- .join("");
-
- case "dynamic-reexport": {
- const activeExports = new Set([
- ...dep.activeExports,
- ...dep._discoverActiveExportsFromOtherStartExports()
- ]);
- let content =
- "/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " +
- importVar +
- ") ";
-
- // Filter out exports which are defined by other exports
- // and filter out default export because it cannot be reexported with *
- if (activeExports.size > 0) {
- content +=
- "if(" +
- JSON.stringify(Array.from(activeExports).concat("default")) +
- ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
- } else {
- content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
- }
- const exportsName = dep.originModule.exportsArgument;
- return (
- content +
- `(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`
- );
- }
-
- default:
- throw new Error(`Unknown mode ${mode.type}`);
- }
- }
-
- getReexportStatement(module, key, name, valueKey) {
- const exportsName = module.exportsArgument;
- const returnValue = this.getReturnValue(name, valueKey);
- return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
- key
- )}, function() { return ${returnValue}; });\n`;
- }
-
- getReexportFakeNamespaceObjectStatement(module, key, name) {
- const exportsName = module.exportsArgument;
- return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
- key
- )}, function() { return __webpack_require__.t(${name}); });\n`;
- }
-
- getConditionalReexportStatement(module, key, name, valueKey) {
- if (valueKey === false) {
- return "/* unused export */\n";
- }
- const exportsName = module.exportsArgument;
- const returnValue = this.getReturnValue(name, valueKey);
- return `if(__webpack_require__.o(${name}, ${JSON.stringify(
- valueKey
- )})) __webpack_require__.d(${exportsName}, ${JSON.stringify(
- key
- )}, function() { return ${returnValue}; });\n`;
- }
-
- getReturnValue(name, valueKey) {
- if (valueKey === null) {
- return `${name}_default.a`;
- }
- if (valueKey === "") {
- return name;
- }
- if (valueKey === false) {
- return "/* unused export */ undefined";
- }
-
- return `${name}[${JSON.stringify(valueKey)}]`;
- }
- };
|