mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Handle export * reexport errors smartly
This commit is contained in:
+37
-15
@@ -1020,41 +1020,62 @@ namespace ts {
|
||||
return links.resolvedExports || (links.resolvedExports = getExportsForModule(moduleSymbol));
|
||||
}
|
||||
|
||||
function extendExportSymbols(originalModule: Symbol, target: SymbolTable, source: SymbolTable) {
|
||||
interface ExportStarDiagnosticsLookupTable {
|
||||
[id: string]: {specifierText: string, exportsWithDuplicate: ExportDeclaration[]};
|
||||
}
|
||||
|
||||
function extendExportSymbols(target: SymbolTable, source: SymbolTable, lookupTable?: ExportStarDiagnosticsLookupTable, exportNode?: ExportDeclaration) {
|
||||
for (let id in source) {
|
||||
if (id !== "default" && !hasProperty(target, id)) {
|
||||
target[id] = source[id];
|
||||
if (lookupTable && exportNode) {
|
||||
lookupTable[id] = {
|
||||
specifierText: getTextOfNode(exportNode.moduleSpecifier),
|
||||
exportsWithDuplicate: []
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (id !== "default" && hasProperty(target, id)) {
|
||||
diagnostics.add(createFileDiagnostic(getSourceFileOfNode(originalModule.valueDeclaration), 0, 0, Diagnostics.Duplicate_identifier_0, id));
|
||||
else if (lookupTable && exportNode && id !== "default" && hasProperty(target, id)) {
|
||||
lookupTable[id].exportsWithDuplicate.push(exportNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExportsForModule(moduleSymbol: Symbol): SymbolTable {
|
||||
let result: SymbolTable;
|
||||
let visitedSymbols: Symbol[] = [];
|
||||
visit(moduleSymbol);
|
||||
return result || moduleSymbol.exports;
|
||||
return visit(moduleSymbol) || moduleSymbol.exports;
|
||||
|
||||
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
|
||||
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
|
||||
function visit(symbol: Symbol) {
|
||||
function visit(symbol: Symbol): SymbolTable {
|
||||
if (symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol)) {
|
||||
visitedSymbols.push(symbol);
|
||||
if (symbol !== moduleSymbol) {
|
||||
if (!result) {
|
||||
result = cloneSymbolTable(moduleSymbol.exports);
|
||||
}
|
||||
extendExportSymbols(moduleSymbol, result, symbol.exports);
|
||||
}
|
||||
let symbols: SymbolTable = cloneSymbolTable(symbol.exports);
|
||||
// All export * declarations are collected in an __export symbol by the binder
|
||||
let exportStars = symbol.exports["__export"];
|
||||
if (exportStars) {
|
||||
let nestedSymbols: SymbolTable = {};
|
||||
let lookupTable: ExportStarDiagnosticsLookupTable = {};
|
||||
for (let node of exportStars.declarations) {
|
||||
visit(resolveExternalModuleName(node, (<ExportDeclaration>node).moduleSpecifier));
|
||||
let resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier);
|
||||
let exportedSymbols = visit(resolvedModule);
|
||||
extendExportSymbols(
|
||||
nestedSymbols,
|
||||
exportedSymbols,
|
||||
lookupTable,
|
||||
node as ExportDeclaration
|
||||
);
|
||||
}
|
||||
for (let id in lookupTable) {
|
||||
if (id !== "export=" && lookupTable[id].exportsWithDuplicate.length && !(id in symbols)) { // It's not an error if the file with multiple export *'s with duplicate names exports a member with that name itself
|
||||
for (let node of lookupTable[id].exportsWithDuplicate) {
|
||||
diagnostics.add(createDiagnosticForNode(node, Diagnostics.An_export_Asterisk_from_0_declaration_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, lookupTable[id].specifierText, id));
|
||||
}
|
||||
}
|
||||
}
|
||||
extendExportSymbols(symbols, nestedSymbols);
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13701,13 +13722,14 @@ namespace ts {
|
||||
|
||||
function checkExternalModuleExports(node: SourceFile | ModuleDeclaration) {
|
||||
let moduleSymbol = getSymbolOfNode(node);
|
||||
let links = getSymbolLinks(moduleSymbol);
|
||||
let links: SymbolLinks = getSymbolLinks(moduleSymbol);
|
||||
if (!links.exportsChecked) {
|
||||
let exportEqualsSymbol = moduleSymbol.exports["export="];
|
||||
if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) {
|
||||
let declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration;
|
||||
error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements);
|
||||
}
|
||||
getExportsOfModule(moduleSymbol); // Checks for export * conflicts
|
||||
links.exportsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,6 +832,10 @@
|
||||
"category": "Error",
|
||||
"code": 2307
|
||||
},
|
||||
"An 'export * from {0}' declaration has already exported a member named '{1}'. Consider explicitly re-exporting to resolve the ambiguity.": {
|
||||
"category": "Error",
|
||||
"code": 2308
|
||||
},
|
||||
"An export assignment cannot be used in a module with other exported elements.": {
|
||||
"category": "Error",
|
||||
"code": 2309
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
tests/cases/conformance/es6/modules/main.ts(1,8): error TS1192: Module '"tests/cases/conformance/es6/modules/t4"' has no default export.
|
||||
tests/cases/conformance/es6/modules/t4.ts(3,1): error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'x'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
tests/cases/conformance/es6/modules/t4.ts(3,1): error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'y'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/modules/t1.ts (0 errors) ====
|
||||
@@ -16,10 +18,14 @@ tests/cases/conformance/es6/modules/main.ts(1,8): error TS1192: Module '"tests/c
|
||||
var z = "z";
|
||||
export { x, y, z };
|
||||
|
||||
==== tests/cases/conformance/es6/modules/t4.ts (0 errors) ====
|
||||
==== tests/cases/conformance/es6/modules/t4.ts (2 errors) ====
|
||||
export * from "./t1";
|
||||
export * from "./t2";
|
||||
export * from "./t3";
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'x'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'y'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
|
||||
==== tests/cases/conformance/es6/modules/main.ts (1 errors) ====
|
||||
import hello, { x, y, z, foo } from "./t4";
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
tests/cases/conformance/es6/modules/main.ts(1,8): error TS1192: Module '"tests/cases/conformance/es6/modules/t4"' has no default export.
|
||||
tests/cases/conformance/es6/modules/t4.ts(3,1): error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'x'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
tests/cases/conformance/es6/modules/t4.ts(3,1): error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'y'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/modules/t1.ts (0 errors) ====
|
||||
@@ -16,10 +18,14 @@ tests/cases/conformance/es6/modules/main.ts(1,8): error TS1192: Module '"tests/c
|
||||
var z = "z";
|
||||
export { x, y, z };
|
||||
|
||||
==== tests/cases/conformance/es6/modules/t4.ts (0 errors) ====
|
||||
==== tests/cases/conformance/es6/modules/t4.ts (2 errors) ====
|
||||
export * from "./t1";
|
||||
export * from "./t2";
|
||||
export * from "./t3";
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'x'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2308: An 'export * from "./t1"' declaration has already exported a member named 'y'. Consider explicitly re-exporting to resolve the ambiguity.
|
||||
|
||||
==== tests/cases/conformance/es6/modules/main.ts (1 errors) ====
|
||||
import hello, { x, y, z, foo } from "./t4";
|
||||
|
||||
Reference in New Issue
Block a user