From 20d1f730870511d4c1e647d88a615a18824cd686 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 22 Mar 2015 09:10:10 -0700 Subject: [PATCH] Add support for exporting imported symbols --- src/compiler/checker.ts | 48 ++++++++++++++------------------------- src/compiler/emitter.ts | 27 +++++++++++++++++----- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 17 ++++++++++++++ 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a68a53436e3..facf7297755 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -323,7 +323,7 @@ module ts { if (!isExternalModule(location)) break; case SyntaxKind.ModuleDeclaration: if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.ModuleMember)) { - if (!(result.flags & SymbolFlags.Alias && getDeclarationOfAliasSymbol(result).kind === SyntaxKind.ExportSpecifier)) { + if (result.flags & meaning || !(result.flags & SymbolFlags.Alias && getDeclarationOfAliasSymbol(result).kind === SyntaxKind.ExportSpecifier)) { break loop; } result = undefined; @@ -495,23 +495,6 @@ module ts { return false; } - // An alias symbol is created by one of the following declarations: - // import = ... - // import from ... - // import * as from ... - // import { x as } from ... - // export { x as } from ... - // export = ... - // export default ... - function isAliasSymbolDeclaration(node: Node): boolean { - return node.kind === SyntaxKind.ImportEqualsDeclaration || - node.kind === SyntaxKind.ImportClause && !!(node).name || - node.kind === SyntaxKind.NamespaceImport || - node.kind === SyntaxKind.ImportSpecifier || - node.kind === SyntaxKind.ExportSpecifier || - node.kind === SyntaxKind.ExportAssignment; - } - function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration { return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined); } @@ -10987,7 +10970,7 @@ module ts { let node = getDeclarationOfAliasSymbol(symbol); if (node) { if (node.kind === SyntaxKind.ImportClause) { - return unescapeIdentifier(symbol.name) + ".default"; + return getGeneratedNameForNode(node.parent) + ".default"; } if (node.kind === SyntaxKind.ImportSpecifier) { let moduleName = getGeneratedNameForNode(node.parent.parent.parent); @@ -11012,7 +10995,7 @@ module ts { } function getExpressionNameSubstitution(node: Identifier): string { - let symbol = getNodeLinks(node).resolvedSymbol; + let symbol = getNodeLinks(node).resolvedSymbol || (isDeclarationName(node) ? getSymbolOfNode(node.parent) : undefined); if (symbol) { // Whan an identifier resolves to a parented symbol, it references an exported entity from // another declaration of the same internal module. @@ -11033,16 +11016,19 @@ module ts { } } - function isValueExportDeclaration(node: Node): boolean { - if (node.kind === SyntaxKind.ExportAssignment) { - return (node).expression.kind === SyntaxKind.Identifier ? isAliasResolvedToValue(getSymbolOfNode(node)) : true; - } - if (node.kind === SyntaxKind.ExportDeclaration) { - let exportClause = (node).exportClause; - return exportClause && forEach(exportClause.elements, isValueExportDeclaration); - } - if (node.kind === SyntaxKind.ExportSpecifier) { - return isAliasResolvedToValue(getSymbolOfNode(node)); + function isValueAliasDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return isAliasResolvedToValue(getSymbolOfNode(node)); + case SyntaxKind.ExportDeclaration: + let exportClause = (node).exportClause; + return exportClause && forEach(exportClause.elements, isValueAliasDeclaration); + case SyntaxKind.ExportAssignment: + return (node).expression.kind === SyntaxKind.Identifier ? isAliasResolvedToValue(getSymbolOfNode(node)) : true; } return false; } @@ -11187,7 +11173,7 @@ module ts { return { getGeneratedNameForNode, getExpressionNameSubstitution, - isValueExportDeclaration, + isValueAliasDeclaration, isReferencedAliasDeclaration, getNodeCheckFlags, isTopLevelValueImportEqualsWithEntityName, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index bcc9e19d696..03d4cc74fac 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2598,7 +2598,12 @@ module ts { case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: return (parent).name === node; + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: + return (parent).name === node || (parent).propertyName === node; case SyntaxKind.BreakStatement: case SyntaxKind.ContinueStatement: case SyntaxKind.ExportAssignment: @@ -3873,7 +3878,7 @@ module ts { emitNodeWithoutSourceMap(specifier.name); emitEnd(specifier.name); write(" = "); - emitNodeWithoutSourceMap(name); + emitExpressionIdentifier(name); write(";"); } } @@ -5003,6 +5008,13 @@ module ts { return node.kind === SyntaxKind.ImportDeclaration && !(node).importClause; } + function emitExportImportAssignments(node: Node) { + if (isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) { + emitExportMemberAssignments((node).name); + } + forEachChild(node, emitExportImportAssignments); + } + function emitImportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration) { if (contains(externalImports, node)) { let exportedImport = node.kind === SyntaxKind.ImportEqualsDeclaration && (node.flags & NodeFlags.Export) !== 0; @@ -5023,6 +5035,7 @@ module ts { emitRequire(getExternalModuleName(node)); write(";"); emitEnd(node); + emitExportImportAssignments(node); emitTrailingComments(node); } else { @@ -5032,6 +5045,7 @@ module ts { emit(namespaceDeclaration.name); write(";"); } + emitExportImportAssignments(node); } } } @@ -5054,12 +5068,13 @@ module ts { emit(node.moduleReference); write(";"); emitEnd(node); + emitExportImportAssignments(node); emitTrailingComments(node); } } function emitExportDeclaration(node: ExportDeclaration) { - if (node.moduleSpecifier && (!node.exportClause || resolver.isValueExportDeclaration(node))) { + if (node.moduleSpecifier && (!node.exportClause || resolver.isValueAliasDeclaration(node))) { emitStart(node); let generatedName = resolver.getGeneratedNameForNode(node); if (node.exportClause) { @@ -5072,7 +5087,7 @@ module ts { write(";"); } for (let specifier of node.exportClause.elements) { - if (resolver.isValueExportDeclaration(specifier)) { + if (resolver.isValueAliasDeclaration(specifier)) { writeLine(); emitStart(specifier); emitContainingModuleName(specifier); @@ -5104,7 +5119,7 @@ module ts { } function emitExportAssignment(node: ExportAssignment) { - if (!node.isExportEquals && resolver.isValueExportDeclaration(node)) { + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { writeLine(); emitStart(node); emitContainingModuleName(node); @@ -5144,7 +5159,7 @@ module ts { externalImports.push(node); hasExportStars = true; } - else if (resolver.isValueExportDeclaration(node)) { + else if (resolver.isValueAliasDeclaration(node)) { // export { x, y } from "mod" where at least one export is a value symbol externalImports.push(node); } @@ -5254,7 +5269,7 @@ module ts { } function emitExportEquals(emitAsReturn: boolean) { - if (exportEquals && resolver.isValueExportDeclaration(exportEquals)) { + if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) { writeLine(); emitStart(exportEquals); write(emitAsReturn ? "return " : "module.exports = "); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 75b1364aa5d..359af6828c1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1199,7 +1199,7 @@ module ts { export interface EmitResolver { getGeneratedNameForNode(node: Node): string; getExpressionNameSubstitution(node: Identifier): string; - isValueExportDeclaration(node: Node): boolean; + isValueAliasDeclaration(node: Node): boolean; isReferencedAliasDeclaration(node: Node): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4fce9c928f7..bf9c38188d3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -834,6 +834,23 @@ module ts { return false; } + // An alias symbol is created by one of the following declarations: + // import = ... + // import from ... + // import * as from ... + // import { x as } from ... + // export { x as } from ... + // export = ... + // export default ... + export function isAliasSymbolDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.ImportEqualsDeclaration || + node.kind === SyntaxKind.ImportClause && !!(node).name || + node.kind === SyntaxKind.NamespaceImport || + node.kind === SyntaxKind.ImportSpecifier || + node.kind === SyntaxKind.ExportSpecifier || + node.kind === SyntaxKind.ExportAssignment; + } + export function getClassBaseTypeNode(node: ClassDeclaration) { let heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword); return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;