track the target binding of harmony reexports

display target binding in module info header
check conflicting star exports (fixes #7562) when statically known
This commit is contained in:
Tobias Koppers 2020-08-11 18:06:27 +02:00
parent 377348be6c
commit 163e7674a0
26 changed files with 500 additions and 279 deletions

View File

@ -47,6 +47,7 @@
* @typedef {Object} ExportSpec
* @property {string} name the name of the export
* @property {boolean=} canMangle can the export be renamed (defaults to true)
* @property {boolean=} terminalBinding is the export a terminal binding that should be checked for export star conflicts
* @property {(string | ExportSpec)[]=} exports nested exports
* @property {Module=} from when reexported: from which module
* @property {string[] | null=} export when reexported: from which export
@ -57,6 +58,7 @@
* @property {(string | ExportSpec)[] | true | null} exports exported names, true for unknown exports or null for no exports
* @property {Set<string>=} excludeExports when exports = true, list of unaffected exports
* @property {boolean=} canMangle can the export be renamed (defaults to true)
* @property {boolean=} terminalBinding are the exports terminal bindings that should be checked for export star conflicts
* @property {Module[]=} dependencies module on which the result depends on
*/

View File

@ -10,6 +10,8 @@ const makeSerializable = require("./util/makeSerializable");
const { forEachRuntime } = require("./util/runtime");
/** @typedef {import("./Dependency").RuntimeSpec} RuntimeSpec */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./util/Hash")} Hash */
/** @typedef {typeof UsageState.OnlyPropertiesUsed | typeof UsageState.NoInfo | typeof UsageState.Unknown | typeof UsageState.Used} RuntimeUsageStateType */
@ -24,19 +26,27 @@ const UsageState = Object.freeze({
});
class RestoreProvidedData {
constructor(exports, otherProvided, otherCanMangleProvide) {
constructor(
exports,
otherProvided,
otherCanMangleProvide,
otherTerminalBinding
) {
this.exports = exports;
this.otherProvided = otherProvided;
this.otherCanMangleProvide = otherCanMangleProvide;
this.otherTerminalBinding = otherTerminalBinding;
}
serialize({ write }) {
write(this.exports);
write(this.otherProvided), write(this.otherCanMangleProvide);
write(this.otherProvided);
write(this.otherCanMangleProvide);
write(this.otherTerminalBinding);
}
static deserialize({ read }) {
return new RestoreProvidedData(read(), read(), read());
return new RestoreProvidedData(read(), read(), read(), read());
}
}
@ -224,6 +234,17 @@ class ExportsInfo {
return this._otherExportsInfo;
}
/**
* @param {string[]} name export name
* @returns {ExportInfo | undefined} export info for this name
*/
getReadOnlyExportInfoRecursive(name) {
const exportInfo = this.getReadOnlyExportInfo(name[0]);
if (name.length === 1) return exportInfo;
if (!exportInfo.exportsInfo) return undefined;
return exportInfo.exportsInfo.getReadOnlyExportInfoRecursive(name.slice(1));
}
/**
* @param {string[]=} name the export name
* @returns {ExportsInfo | undefined} the nested exports info
@ -643,17 +664,20 @@ class ExportsInfo {
getRestoreProvidedData() {
const otherProvided = this._otherExportsInfo.provided;
const otherCanMangleProvide = this._otherExportsInfo.canMangleProvide;
const otherTerminalBinding = this._otherExportsInfo.terminalBinding;
const exports = [];
for (const exportInfo of this._exports.values()) {
if (
exportInfo.provided !== otherProvided ||
exportInfo.canMangleProvide !== otherCanMangleProvide ||
exportInfo.terminalBinding !== otherTerminalBinding ||
exportInfo.exportsInfoOwned
) {
exports.push({
name: exportInfo.name,
provided: exportInfo.provided,
canMangleProvide: exportInfo.canMangleProvide,
terminalBinding: exportInfo.terminalBinding,
exportsInfo: exportInfo.exportsInfoOwned
? exportInfo.exportsInfo.getRestoreProvidedData()
: undefined
@ -663,21 +687,30 @@ class ExportsInfo {
return new RestoreProvidedData(
exports,
otherProvided,
otherCanMangleProvide
otherCanMangleProvide,
otherTerminalBinding
);
}
restoreProvided({ otherProvided, otherCanMangleProvide, exports }) {
restoreProvided({
otherProvided,
otherCanMangleProvide,
otherTerminalBinding,
exports
}) {
for (const exportInfo of this._exports.values()) {
exportInfo.provided = otherProvided;
exportInfo.canMangleProvide = otherCanMangleProvide;
exportInfo.terminalBinding = otherTerminalBinding;
}
this._otherExportsInfo.provided = otherProvided;
this._otherExportsInfo.canMangleProvide = otherCanMangleProvide;
this._otherExportsInfo.terminalBinding = otherTerminalBinding;
for (const exp of exports) {
const exportInfo = this.getExportInfo(exp.name);
exportInfo.provided = exp.provided;
exportInfo.canMangleProvide = exp.canMangleProvide;
exportInfo.terminalBinding = exp.terminalBinding;
if (exp.exportsInfo) {
const exportsInfo = exportInfo.createNestedExportsInfo();
exportsInfo.restoreProvided(exp.exportsInfo);
@ -713,6 +746,11 @@ class ExportInfo {
* @type {boolean | null | undefined}
*/
this.provided = initFrom ? initFrom.provided : undefined;
/**
* is the export a terminal binding that should be checked for export star conflicts
* @type {boolean}
*/
this.terminalBinding = initFrom ? initFrom.terminalBinding : false;
/**
* true: it can be mangled
* false: is can not be mangled
@ -731,6 +769,8 @@ class ExportInfo {
this.exportsInfoOwned = false;
/** @type {ExportsInfo=} */
this.exportsInfo = undefined;
/** @type {{ module: Module, export: string[] }=} */
this.target = undefined;
}
// TODO webpack 5 remove
@ -983,6 +1023,18 @@ class ExportInfo {
this._usedName = name;
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {ExportInfo | undefined} the terminal binding export info if known
*/
getTerminalExportInfo(moduleGraph) {
if (this.terminalBinding) return this;
const { target } = this;
if (!target) return undefined;
const exportsInfo = moduleGraph.getExportsInfo(target.module);
return exportsInfo.getReadOnlyExportInfoRecursive(target.export);
}
createNestedExportsInfo() {
if (this.exportsInfoOwned) return this.exportsInfo;
this.exportsInfoOwned = true;
@ -1000,6 +1052,7 @@ class ExportInfo {
hash.update(`${this.getUsed(runtime)}`);
hash.update(`${this.provided}`);
hash.update(`${this.canMangle}`);
hash.update(`${this.terminalBinding}`);
}
getUsedInfo() {

View File

@ -6,11 +6,13 @@
"use strict";
const asyncLib = require("neo-async");
const { equals } = require("./util/ArrayHelpers");
const Queue = require("./util/Queue");
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./Dependency").ExportSpec} ExportSpec */
/** @typedef {import("./ExportsInfo")} ExportsInfo */
/** @typedef {import("./Module")} Module */
@ -110,6 +112,7 @@ class FlagDependencyExportsPlugin {
if (!exportDesc) return;
const exports = exportDesc.exports;
const canMangle = exportDesc.canMangle;
const terminalBinding = exportDesc.terminalBinding || false;
const exportDeps = exportDesc.dependencies;
if (exports === true) {
// unknown exports
@ -122,7 +125,37 @@ class FlagDependencyExportsPlugin {
changed = true;
}
} else if (Array.isArray(exports)) {
// merge in new exports
/**
* @param {Module} module from module
* @param {string[]=} exportName export name accessed
* @returns {{module: Module, export: string[]}=} resolved target
*/
const resolveTarget = (module, exportName) => {
const set = new Set();
for (;;) {
if (!exportName) break;
const exportsInfo = moduleGraph.getExportsInfo(module);
const exportInfo = exportsInfo.getReadOnlyExportInfoRecursive(
exportName
);
if (!exportInfo) break;
if (exportInfo.target) {
// check circular
if (set.has(exportInfo.target)) return undefined;
set.add(exportInfo.target);
module = exportInfo.target.module;
exportName = exportInfo.target.export;
} else {
break;
}
}
return { module, export: exportName };
};
/**
* merge in new exports
* @param {ExportsInfo} exportsInfo own exports info
* @param {(ExportSpec | string)[]} exports list of exports
*/
const mergeExports = (exportsInfo, exports) => {
for (const exportNameOrSpec of exports) {
if (typeof exportNameOrSpec === "string") {
@ -140,6 +173,10 @@ class FlagDependencyExportsPlugin {
exportInfo.canMangleProvide = false;
changed = true;
}
if (terminalBinding && !exportInfo.terminalBinding) {
exportInfo.terminalBinding = true;
changed = true;
}
} else {
const exportInfo = exportsInfo.getExportInfo(
exportNameOrSpec.name
@ -157,47 +194,67 @@ class FlagDependencyExportsPlugin {
exportInfo.canMangleProvide = false;
changed = true;
}
if (
exportNameOrSpec.exports &&
exportNameOrSpec.from
(exportNameOrSpec.terminalBinding !== undefined
? exportNameOrSpec.terminalBinding
: terminalBinding) &&
!exportInfo.terminalBinding
) {
exportInfo.terminalBinding = true;
changed = true;
}
if (exportNameOrSpec.exports) {
const nestedExportsInfo = exportInfo.createNestedExportsInfo();
const fromExportsInfo = moduleGraph.getExportsInfo(
exportNameOrSpec.from
);
const fromNestedExportsInfo = fromExportsInfo.getNestedExportsInfo(
exportNameOrSpec.export
);
mergeExports(
nestedExportsInfo,
exportNameOrSpec.exports
);
if (fromNestedExportsInfo) {
if (
nestedExportsInfo.setRedirectNamedTo(
fromNestedExportsInfo
)
}
const target =
exportNameOrSpec.from &&
resolveTarget(
exportNameOrSpec.from,
exportNameOrSpec.export
);
const oldTarget = exportInfo.target;
if (
target &&
(!oldTarget ||
oldTarget.module !== target.module ||
(target.export
? !oldTarget.export ||
!equals(oldTarget.export, target.export)
: oldTarget.export))
) {
exportInfo.target = target;
changed = true;
const targetModuleExportsInfo =
target &&
moduleGraph.getExportsInfo(target.module);
const targetExportsInfo =
targetModuleExportsInfo &&
targetModuleExportsInfo.getNestedExportsInfo(
target.export
);
if (targetExportsInfo) {
if (exportNameOrSpec.exports) {
const nestedExportsInfo =
exportInfo.exportsInfo;
if (
nestedExportsInfo.setRedirectNamedTo(
targetExportsInfo
)
) {
changed = true;
}
} else if (
exportInfo.exportsInfo !== targetExportsInfo
) {
exportInfo.exportsInfo = targetExportsInfo;
changed = true;
}
}
} else if (exportNameOrSpec.exports) {
const nestedExportsInfo = exportInfo.createNestedExportsInfo();
mergeExports(
nestedExportsInfo,
exportNameOrSpec.exports
);
} else if (exportNameOrSpec.from) {
const fromExportsInfo = moduleGraph.getExportsInfo(
exportNameOrSpec.from
);
const nestedExportsInfo = fromExportsInfo.getNestedExportsInfo(
exportNameOrSpec.export
);
if (!exportInfo.exportsInfo && nestedExportsInfo) {
exportInfo.exportsInfo = nestedExportsInfo;
changed = true;
}
}
}
}

View File

@ -14,6 +14,7 @@ const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
/** @typedef {import("./ExportsInfo")} ExportsInfo */
/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./RequestShortener")} RequestShortener */
const joinIterableWithComma = iterable => {
// This is more performant than Array.from().join(", ")
@ -35,6 +36,7 @@ const joinIterableWithComma = iterable => {
* @param {ConcatSource} source output
* @param {string} indent spacing
* @param {ExportsInfo} exportsInfo data
* @param {RequestShortener} requestShortener requestShortener
* @param {Set<ExportInfo>} alreadyPrinted deduplication set
* @returns {void}
*/
@ -42,6 +44,7 @@ const printExportsInfoToSource = (
source,
indent,
exportsInfo,
requestShortener,
alreadyPrinted = new Set()
) => {
const otherExportsInfo = exportsInfo.otherExportsInfo;
@ -73,7 +76,19 @@ const printExportsInfoToSource = (
`${indent}export ${JSON.stringify(exportInfo.name).slice(
1,
-1
)} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]`
)} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]${
exportInfo.target
? ` -> ${exportInfo.target.module.readableIdentifier(
requestShortener
)}${
exportInfo.target.export
? ` .${exportInfo.target.export
.map(e => JSON.stringify(e).slice(1, -1))
.join(".")}`
: ""
}`
: ""
}`
) + "\n"
);
if (exportInfo.exportsInfo) {
@ -81,6 +96,7 @@ const printExportsInfoToSource = (
source,
indent + " ",
exportInfo.exportsInfo,
requestShortener,
alreadyPrinted
);
}
@ -119,6 +135,7 @@ class ModuleInfoHeaderPlugin {
*/
apply(compiler) {
compiler.hooks.compilation.tap("ModuleInfoHeaderPlugin", compilation => {
const { requestShortener } = compilation;
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
hooks.renderModulePackage.tap(
"ModuleInfoHeaderPlugin",
@ -146,7 +163,7 @@ class ModuleInfoHeaderPlugin {
);
if (exportsType) {
const exportsInfo = moduleGraph.getExportsInfo(module);
printExportsInfoToSource(source, "", exportsInfo);
printExportsInfoToSource(source, "", exportsInfo, requestShortener);
}
source.add(
Template.toComment(

View File

@ -8,6 +8,7 @@
const InitFragment = require("./InitFragment");
const RuntimeGlobals = require("./RuntimeGlobals");
const Template = require("./Template");
const { equals } = require("./util/ArrayHelpers");
const propertyAccess = require("./util/propertyAccess");
/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
@ -20,14 +21,6 @@ const propertyAccess = require("./util/propertyAccess");
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
const arrayEquals = (a, b) => {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
};
/**
* @param {Module} module the module
* @param {ChunkGraph} chunkGraph the chunk graph
@ -709,7 +702,7 @@ class RuntimeTemplate {
);
return `${comment} undefined`;
}
const comment = arrayEquals(used, exportName)
const comment = equals(used, exportName)
? ""
: Template.toNormalComment(propertyAccess(exportName)) + " ";
const access = `${importVar}${comment}${propertyAccess(used)}`;

View File

@ -37,6 +37,7 @@ class HarmonyExportExpressionDependency extends NullDependency {
getExports(moduleGraph) {
return {
exports: ["default"],
terminalBinding: true,
dependencies: undefined
};
}

View File

@ -7,6 +7,7 @@
const Dependency = require("../Dependency");
const { UsageState } = require("../ExportsInfo");
const HarmonyLinkingError = require("../HarmonyLinkingError");
const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
@ -138,7 +139,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
* @param {string[]} ids the requested export name of the imported module
* @param {string | null} name the export name of for this module
* @param {Set<string>} activeExports other named exports in the module
* @param {Iterable<Dependency>} otherStarExports other star exports in the module
* @param {Iterable<HarmonyExportImportedSpecifierDependency>} otherStarExports other star exports in the module
* @param {boolean} strictExportPresence when true, missing exports in the imported module lead to errors instead of warnings
*/
constructor(
@ -366,7 +367,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
const ignoredExports = new Set([
"default",
...this.activeExports,
...this._discoverActiveExportsFromOtherStarExports(moduleGraph)
...this._discoverActiveExportsFromOtherStarExports(moduleGraph).keys()
]);
if (!noExtraExports && !noExtraImports) {
@ -487,25 +488,22 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {Set<string>} exported names
* @returns {Map<string, HarmonyExportImportedSpecifierDependency>} exported names and their origin dependency
*/
_discoverActiveExportsFromOtherStarExports(moduleGraph) {
if (!this.otherStarExports) {
return new Set();
return new Map();
}
const result = new Set();
const result = new Map();
// try to learn impossible exports from other star exports with provided exports
for (const otherStarExport of this.otherStarExports) {
const otherImportedModule = moduleGraph.getModule(otherStarExport);
if (otherImportedModule) {
const providedExports = moduleGraph.getProvidedExports(
otherImportedModule
);
if (Array.isArray(providedExports)) {
for (const exportName of providedExports) {
result.add(exportName);
const exportsInfo = moduleGraph.getExportsInfo(otherImportedModule);
for (const exportInfo of exportsInfo.exports) {
if (exportInfo.provided === true && !result.has(exportInfo.name)) {
result.set(exportInfo.name, otherStarExport);
}
}
}
@ -638,11 +636,74 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
*/
_getErrors(moduleGraph) {
const ids = this.getIds(moduleGraph);
return this.getLinkingErrors(
let errors = this.getLinkingErrors(
moduleGraph,
ids,
`(reexported as '${this.name}')`
);
if (ids.length === 0 && this.name === null) {
const potentialConflicts = this._discoverActiveExportsFromOtherStarExports(
moduleGraph
);
if (potentialConflicts.size > 0) {
const importedModule = moduleGraph.getModule(this);
if (importedModule) {
const exportsInfo = moduleGraph.getExportsInfo(importedModule);
const conflicts = new Map();
for (const exportInfo of exportsInfo.orderedExports) {
if (exportInfo.provided !== true) continue;
if (
!exportInfo.terminalBinding &&
!(exportInfo.target && exportInfo.target.export)
) {
continue;
}
if (exportInfo.name === "default") continue;
if (this.activeExports.has(exportInfo.name)) continue;
const conflictingDependency = potentialConflicts.get(
exportInfo.name
);
if (!conflictingDependency) continue;
const target = exportInfo.getTerminalExportInfo(moduleGraph);
if (!target) continue;
const conflictingModule = moduleGraph.getModule(
conflictingDependency
);
if (conflictingModule === importedModule) continue;
const conflictingExportInfo = moduleGraph.getExportInfo(
conflictingModule,
exportInfo.name
);
const conflictingTarget = conflictingExportInfo.getTerminalExportInfo(
moduleGraph
);
if (!conflictingTarget) continue;
if (target === conflictingTarget) continue;
const list = conflicts.get(conflictingDependency.request);
if (list === undefined) {
conflicts.set(conflictingDependency.request, [exportInfo.name]);
} else {
list.push(exportInfo.name);
}
}
for (const [request, exports] of conflicts) {
if (!errors) errors = [];
errors.push(
new HarmonyLinkingError(
`The requested module '${
this.request
}' contains conflicting star exports for the ${
exports.size > 1 ? "names" : "name"
} ${exports
.map(e => `'${e}'`)
.join(", ")} with the previous requested module '${request}'`
)
);
}
}
}
}
return errors;
}
/**

View File

@ -34,6 +34,7 @@ class HarmonyExportSpecifierDependency extends NullDependency {
getExports(moduleGraph) {
return {
exports: [this.name],
terminalBinding: true,
dependencies: undefined
};
}

View File

@ -24,6 +24,7 @@ const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency
const HarmonyImportSideEffectDependency = require("../dependencies/HarmonyImportSideEffectDependency");
const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
const JavascriptParser = require("../javascript/JavascriptParser");
const { equals } = require("../util/ArrayHelpers");
const LazySet = require("../util/LazySet");
const { concatComparators, keepOriginalOrder } = require("../util/comparators");
const createHash = require("../util/createHash");
@ -169,14 +170,6 @@ const joinIterableWithComma = iterable => {
return str;
};
const arrayEquals = (a, b) => {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
};
/**
* @typedef {Object} ConcatenationEntry
* @property {"concatenated" | "external"} type
@ -315,7 +308,7 @@ const getExternalImport = (
exportName.length === 0 ||
moduleGraph.getExportsInfo(importedModule).getUsedName(exportName, runtime);
if (!used) return "/* unused export */undefined";
const comment = arrayEquals(used, exportName)
const comment = equals(used, exportName)
? ""
: Template.toNormalComment(`${exportName.join(".")}`);
const reference = `${exprStart}${comment}${propertyAccess(used)}`;

14
lib/util/ArrayHelpers.js Normal file
View File

@ -0,0 +1,14 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
exports.equals = (a, b) => {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,3 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./a?3";
export * from "./b?3";

View File

@ -1,3 +1,3 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./b?4";
export * from "./a?4";

View File

@ -1,4 +1,4 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./a?6";
export * from "./b?6";
export * from "./c?6";

View File

@ -1,4 +1,4 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./d?7";
export * from "./b?7";
export * from "./c?7";

View File

@ -1 +1 @@
exports.x = "c";
Object(exports).x = "c";

View File

@ -1,3 +1,3 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./a?3";
export * from "./b?3";

View File

@ -1,3 +1,3 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./b?4";
export * from "./a?4";

View File

@ -1,4 +1,4 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./a?6";
export * from "./b?6";
export * from "./c?6";

View File

@ -1,4 +1,4 @@
// TODO: Technically this should lead to an error
// This leads to an error
export * from "./d?7";
export * from "./b?7";
export * from "./c?7";

View File

@ -1 +1 @@
exports.x = "c";
Object(exports).x = "c";

View File

@ -1 +1 @@
exports.x = "d";
Object(exports).x = "d";

View File

@ -1 +1 @@
exports.x = "d";
Object(exports).x = "d";

View File

@ -14,22 +14,22 @@ var y5 = require("./cjs/5").x;
var y6 = require("./cjs/6").x;
var y7 = require("./cjs/7").x;
it("should not overwrite when using star export (known exports)", function() {
it("should not overwrite when using star export (known exports)", function () {
expect(x1).toBe("1");
expect(x2).toBe("1");
expect(x3).toBe("a");
expect(x4).toBe("b");
expect(x5).toBe("c");
expect(x6).toBe("a");
expect(x7).toBe("d"); // Looks wrong, but is irrelevant as this should be an error anyway
expect(x7).toBe("b"); // Looks wrong, but is irrelevant as this is an error anyway
});
it("should not overwrite when using star export (unknown exports)", function() {
it("should not overwrite when using star export (unknown exports)", function () {
expect(y1).toBe("1");
expect(y2).toBe("1");
expect(y3).toBe("a");
expect(y4).toBe("b");
expect(y5).toBe("c");
expect(y6).toBe("a");
expect(y7).toBe("d"); // Looks wrong, but is irrelevant as this should be an error anyway
expect(y7).toBe("b"); // Looks wrong, but is irrelevant as this is an error anyway
});

View File

@ -0,0 +1,10 @@
module.exports = [
[/name 'x'/, /\.\/a\?3/, /\.\/b\?3/],
[/name 'x'/, /\.\/a\?4/, /\.\/b\?4/],
[/name 'x'/, /\.\/a\?6/, /\.\/b\?6/],
[/name 'x'/, /\.\/a\?7/, /\.\/b\?7/],
[/name 'x'/, /\.\/a\?3/, /\.\/b\?3/],
[/name 'x'/, /\.\/a\?4/, /\.\/b\?4/],
[/name 'x'/, /\.\/a\?6/, /\.\/b\?6/],
[/name 'x'/, /\.\/a\?7/, /\.\/b\?7/]
];

19
types.d.ts vendored
View File

@ -2553,6 +2553,11 @@ declare abstract class ExportInfo {
*/
provided: boolean;
/**
* is the export a terminal binding that should be checked for export star conflicts
*/
terminalBinding: boolean;
/**
* true: it can be mangled
* false: is can not be mangled
@ -2568,6 +2573,7 @@ declare abstract class ExportInfo {
canMangleUse: boolean;
exportsInfoOwned: boolean;
exportsInfo: ExportsInfo;
target: { module: Module; export: string[] };
readonly canMangle: boolean;
setUsedInUnknownWay(runtime: string | SortableSet<string>): boolean;
setUsedWithoutInfo(runtime: string | SortableSet<string>): boolean;
@ -2596,6 +2602,7 @@ declare abstract class ExportInfo {
* Sets the mangled name of this export
*/
setUsedName(name: string): void;
getTerminalExportInfo(moduleGraph: ModuleGraph): ExportInfo;
createNestedExportsInfo(): ExportsInfo;
getNestedExportsInfo(): ExportsInfo;
updateHash(hash?: any, runtime?: any): void;
@ -2618,6 +2625,11 @@ declare interface ExportSpec {
*/
canMangle?: boolean;
/**
* is the export a terminal binding that should be checked for export star conflicts
*/
terminalBinding?: boolean;
/**
* nested exports
*/
@ -2645,6 +2657,7 @@ declare abstract class ExportsInfo {
getOwnExportInfo(name: string): ExportInfo;
getExportInfo(name: string): ExportInfo;
getReadOnlyExportInfo(name: string): ExportInfo;
getReadOnlyExportInfoRecursive(name: string[]): ExportInfo;
getNestedExportsInfo(name?: string[]): ExportsInfo;
setUnknownExportsProvided(
canMangle?: boolean,
@ -2679,6 +2692,7 @@ declare abstract class ExportsInfo {
restoreProvided(__0: {
otherProvided: any;
otherCanMangleProvide: any;
otherTerminalBinding: any;
exports: any;
}): void;
}
@ -2698,6 +2712,11 @@ declare interface ExportsSpec {
*/
canMangle?: boolean;
/**
* are the exports terminal bindings that should be checked for export star conflicts
*/
terminalBinding?: boolean;
/**
* module on which the result depends on
*/