Unifying ES6 and TypeScript external modules

Export assignments are now equivalent to export of member named "default"
Export assignments and exports defaults collected by binder
Export * declarations collected by binder
Simplified logic for marking import symbols as referenced
Removed "location" parameter from resolveEntityName
Improved error position reporting in resolveEntityName
This commit is contained in:
Anders Hejlsberg 2015-03-02 12:17:05 -08:00
parent 84760c298f
commit 234358e6c6
4 changed files with 223 additions and 233 deletions

View File

@ -112,6 +112,10 @@ module ts {
return "__new";
case SyntaxKind.IndexSignature:
return "__index";
case SyntaxKind.ExportAssignment:
return "default";
case SyntaxKind.ExportDeclaration:
return "__export";
}
}
@ -137,9 +141,9 @@ module ts {
: Diagnostics.Duplicate_identifier_0;
forEach(symbol.declarations, declaration => {
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration)));
});
file.bindDiagnostics.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
file.bindDiagnostics.push(createDiagnosticForNode(node.name || node, message, getDisplayName(node)));
symbol = createSymbol(0, name);
}
@ -310,13 +314,6 @@ module ts {
}
}
function bindExportDeclaration(node: ExportDeclaration) {
if (!node.exportClause) {
((<ExportContainer>container).exportStars || ((<ExportContainer>container).exportStars = [])).push(node);
}
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
}
function bindFunctionOrConstructorType(node: SignatureDeclaration) {
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
// to the one we would get for: { <...>(...): T }
@ -478,9 +475,6 @@ module ts {
case SyntaxKind.ExportSpecifier:
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ExportDeclaration:
bindExportDeclaration(<ExportDeclaration>node);
break;
case SyntaxKind.ImportClause:
if ((<ImportClause>node).name) {
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes, /*isBlockScopeContainer*/ false);
@ -489,6 +483,22 @@ module ts {
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.ExportDeclaration:
if (!(<ExportDeclaration>node).exportClause) {
// All export * declarations are collected in an __export symbol
declareSymbol(container.symbol.exports, container.symbol, <Declaration>node, SymbolFlags.ExportStar, 0);
}
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).expression.kind === SyntaxKind.Identifier) {
declareSymbol(container.symbol.exports, container.symbol, <Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes);
}
else {
declareSymbol(container.symbol.exports, container.symbol, <Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.SourceFile:
if (isExternalModule(<SourceFile>node)) {
bindAnonymousDeclaration(<SourceFile>node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).fileName) + '"', /*isBlockScopeContainer*/ true);

View File

@ -465,7 +465,8 @@ module ts {
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier;
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment;
}
function getDeclarationOfImportSymbol(symbol: Symbol): Declaration {
@ -518,7 +519,11 @@ module ts {
function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol {
return (<ExportDeclaration>node.parent.parent).moduleSpecifier ?
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node) :
resolveEntityName(node, node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
}
function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
return resolveEntityName(<Identifier>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
}
function getTargetOfImportDeclaration(node: Declaration): Symbol {
@ -533,6 +538,8 @@ module ts {
return getTargetOfImportSpecifier(<ImportSpecifier>node);
case SyntaxKind.ExportSpecifier:
return getTargetOfExportSpecifier(<ExportSpecifier>node);
case SyntaxKind.ExportAssignment:
return getTargetOfExportAssignment(<ExportAssignment>node);
}
}
@ -556,6 +563,31 @@ module ts {
return links.target;
}
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
var symbol = getSymbolOfNode(node);
var target = resolveImport(symbol);
if (target && target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target)) {
markImportSymbolAsReferenced(symbol);
}
}
function markImportSymbolAsReferenced(symbol: Symbol) {
var links = getSymbolLinks(symbol);
if (!links.referenced) {
links.referenced = true;
var node = getDeclarationOfImportSymbol(symbol);
if (node.kind === SyntaxKind.ExportAssignment) {
checkExpressionCached((<ExportAssignment>node).expression);
}
else if (node.kind === SyntaxKind.ExportSpecifier) {
checkExpressionCached((<ExportSpecifier>node).propertyName || (<ExportSpecifier>node).name);
}
else if (isInternalModuleImportEqualsDeclaration(node)) {
checkExpressionCached(<Expression>(<ImportEqualsDeclaration>node).moduleReference);
}
}
}
// This function is only for imports with entity names
function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, importDeclaration?: ImportEqualsDeclaration): Symbol {
if (!importDeclaration) {
@ -573,13 +605,13 @@ module ts {
}
// Check for case 1 and 3 in the above example
if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
return resolveEntityName(importDeclaration, entityName, SymbolFlags.Namespace);
return resolveEntityName(entityName, SymbolFlags.Namespace);
}
else {
// Case 2 in above example
// entityName.kind could be a QualifiedName or a Missing identifier
Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration);
return resolveEntityName(importDeclaration, entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
}
}
@ -588,28 +620,28 @@ module ts {
}
// Resolves a qualified name and any involved import aliases
function resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol {
function resolveEntityName(name: EntityName, meaning: SymbolFlags): Symbol {
if (getFullWidth(name) === 0) {
return undefined;
}
if (name.kind === SyntaxKind.Identifier) {
var symbol = resolveName(location,(<Identifier>name).text, meaning, Diagnostics.Cannot_find_name_0, <Identifier>name);
var symbol = resolveName(name, (<Identifier>name).text, meaning, Diagnostics.Cannot_find_name_0, <Identifier>name);
if (!symbol) {
return;
return undefined;
}
}
else if (name.kind === SyntaxKind.QualifiedName) {
var namespace = resolveEntityName(location,(<QualifiedName>name).left, SymbolFlags.Namespace);
if (!namespace || namespace === unknownSymbol || getFullWidth((<QualifiedName>name).right) === 0) return;
var symbol = getSymbol(getExportsOfSymbol(namespace), (<QualifiedName>name).right.text, meaning);
var namespace = resolveEntityName((<QualifiedName>name).left, SymbolFlags.Namespace);
if (!namespace || namespace === unknownSymbol || getFullWidth((<QualifiedName>name).right) === 0) {
return undefined;
}
var right = (<QualifiedName>name).right;
var symbol = getSymbol(getExportsOfSymbol(namespace), right.text, meaning);
if (!symbol) {
error(location, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace),
declarationNameToString((<QualifiedName>name).right));
return;
error(right, Diagnostics.Module_0_has_no_exported_member_1, getFullyQualifiedName(namespace), declarationNameToString(right));
return undefined;
}
}
Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
return symbol.flags & meaning ? symbol : resolveImport(symbol);
}
@ -658,6 +690,10 @@ module ts {
error(moduleReferenceLiteral, Diagnostics.Cannot_find_external_module_0, moduleName);
}
function getExportAssignmentSymbol(moduleSymbol: Symbol): Symbol {
return moduleSymbol.exports["default"];
}
function getResolvedExportAssignmentSymbol(moduleSymbol: Symbol): Symbol {
var symbol = getExportAssignmentSymbol(moduleSymbol);
if (symbol) {
@ -670,64 +706,6 @@ module ts {
}
}
function getExportAssignmentSymbol(symbol: Symbol): Symbol {
checkTypeOfExportAssignmentSymbol(symbol);
return getSymbolLinks(symbol).exportAssignmentSymbol;
}
function checkTypeOfExportAssignmentSymbol(containerSymbol: Symbol): void {
var symbolLinks = getSymbolLinks(containerSymbol);
if (!symbolLinks.exportAssignmentChecked) {
var exportInformation = collectExportInformationForSourceFileOrModule(containerSymbol);
if (exportInformation.exportAssignments.length) {
if (exportInformation.exportAssignments.length > 1) {
// TypeScript 1.0 spec (April 2014): 11.2.4
// It is an error for an external module to contain more than one export assignment.
forEach(exportInformation.exportAssignments, node => error(node, Diagnostics.A_module_cannot_have_more_than_one_export_assignment));
}
var node = exportInformation.exportAssignments[0];
if (exportInformation.hasExportedMember) {
// TypeScript 1.0 spec (April 2014): 11.2.3
// If an external module contains an export assignment it is an error
// for the external module to also contain export declarations.
// The two types of exports are mutually exclusive.
error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements);
}
if (node.expression.kind === SyntaxKind.Identifier && (<Identifier>node.expression).text) {
var exportSymbol = resolveName(node, (<Identifier>node.expression).text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace,
Diagnostics.Cannot_find_name_0, <Identifier>node.expression);
}
else {
var exportSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "*default*");
exportSymbol.parent = containerSymbol;
(<TransientSymbol>exportSymbol).type = checkExpression(node.expression);
}
symbolLinks.exportAssignmentSymbol = exportSymbol || unknownSymbol;
}
symbolLinks.exportAssignmentChecked = true;
}
}
function collectExportInformationForSourceFileOrModule(symbol: Symbol) {
var seenExportedMember = false;
var result: ExportAssignment[] = [];
forEach(symbol.declarations, declaration => {
var block = <Block>(declaration.kind === SyntaxKind.SourceFile ? declaration : (<ModuleDeclaration>declaration).body);
forEach(block.statements, node => {
if (node.kind === SyntaxKind.ExportAssignment) {
result.push(<ExportAssignment>node);
}
else {
seenExportedMember = seenExportedMember || (node.flags & NodeFlags.Export) !== 0;
}
});
});
return {
hasExportedMember: seenExportedMember,
exportAssignments: result
};
}
function getExportsOfSymbol(symbol: Symbol): SymbolTable {
return symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : symbol.exports;
}
@ -738,6 +716,14 @@ module ts {
}
function getExportsForModule(moduleSymbol: Symbol): SymbolTable {
if (compilerOptions.target < ScriptTarget.ES6) {
var defaultSymbol = getExportAssignmentSymbol(moduleSymbol);
if (defaultSymbol) {
return {
"default": defaultSymbol
};
}
}
var result: SymbolTable;
var visitedSymbols: Symbol[] = [];
visit(moduleSymbol);
@ -752,13 +738,12 @@ module ts {
}
extendSymbolTable(result, symbol.exports);
}
forEach(symbol.declarations, node => {
if (node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.ModuleDeclaration) {
forEach((<ExportContainer>node).exportStars, exportStar => {
visit(resolveExternalModuleName(exportStar, exportStar.moduleSpecifier));
});
}
});
var exportStars = symbol.exports["__export"];
if (exportStars) {
forEach(exportStars.declarations, node => {
visit(resolveExternalModuleName(node, (<ExportDeclaration>node).moduleSpecifier));
});
}
}
}
}
@ -2001,6 +1986,10 @@ module ts {
if (declaration.kind === SyntaxKind.CatchClause) {
return links.type = anyType;
}
// Handle export default expressions
if (declaration.kind === SyntaxKind.ExportAssignment) {
return links.type = checkExpression((<ExportAssignment>declaration).expression);
}
// Handle variable, parameter or property
links.type = resolvingType;
var type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
@ -3055,7 +3044,7 @@ module ts {
function getTypeFromTypeReferenceNode(node: TypeReferenceNode): Type {
var links = getNodeLinks(node);
if (!links.resolvedType) {
var symbol = resolveEntityName(node, node.typeName, SymbolFlags.Type);
var symbol = resolveEntityName(node.typeName, SymbolFlags.Type);
if (symbol) {
var type: Type;
if ((symbol.flags & SymbolFlags.TypeParameter) && isTypeParameterReferenceIllegalInConstraint(node, symbol)) {
@ -5001,22 +4990,6 @@ module ts {
}
}
/*Transitively mark all linked imports as referenced*/
function markLinkedImportsAsReferenced(node: ImportEqualsDeclaration): void {
if (node) {
var nodeLinks = getNodeLinks(node);
while (nodeLinks.importOnRightSide) {
var rightSide = nodeLinks.importOnRightSide;
nodeLinks.importOnRightSide = undefined;
getSymbolLinks(rightSide).referenced = true;
Debug.assert((rightSide.flags & SymbolFlags.Import) !== 0);
nodeLinks = getNodeLinks(getDeclarationOfKind(rightSide, SyntaxKind.ImportEqualsDeclaration))
}
}
}
function checkIdentifier(node: Identifier): Type {
var symbol = getResolvedSymbol(node);
@ -5030,44 +5003,8 @@ module ts {
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression);
}
if (symbol.flags & SymbolFlags.Import) {
//var symbolLinks = getSymbolLinks(symbol);
//if (!symbolLinks.referenced) {
// if (!isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol))) {
// symbolLinks.referenced = true;
// }
//}
// TODO: AndersH: This needs to be simplified. In an import of the form "import x = a.b.c;" we only need
// to resolve "a" and mark it as referenced. If "b" and/or "c" are aliases, we would be able to access them
// unless they're exported, and in that case they're already implicitly referenced.
var symbolLinks = getSymbolLinks(symbol);
if (!symbolLinks.referenced) {
var importOrExportAssignment = getLeftSideOfImportEqualsOrExportAssignment(node);
// decision about whether import is referenced can be made now if
// - import that are used anywhere except right side of import declarations
// - imports that are used on the right side of exported import declarations
// for other cases defer decision until the check of left side
if (!importOrExportAssignment ||
(importOrExportAssignment.flags & NodeFlags.Export) ||
(importOrExportAssignment.kind === SyntaxKind.ExportAssignment)) {
// Mark the import as referenced so that we emit it in the final .js file.
// exception: identifiers that appear in type queries, const enums, modules that contain only const enums
symbolLinks.referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol));
}
else {
var nodeLinks = getNodeLinks(importOrExportAssignment);
Debug.assert(!nodeLinks.importOnRightSide);
nodeLinks.importOnRightSide = symbol;
}
}
if (symbolLinks.referenced) {
markLinkedImportsAsReferenced(<ImportEqualsDeclaration>getDeclarationOfKind(symbol, SyntaxKind.ImportEqualsDeclaration));
}
if (symbol.flags & SymbolFlags.Import && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol))) {
markImportSymbolAsReferenced(symbol);
}
checkCollisionWithCapturedSuperVariable(node, node);
@ -9081,7 +9018,7 @@ module ts {
var staticBaseType = getTypeOfSymbol(baseType.symbol);
checkTypeAssignableTo(staticType, getTypeWithoutConstructors(staticBaseType), node.name,
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
if (baseType.symbol !== resolveEntityName(node, baseTypeNode.typeName, SymbolFlags.Value)) {
if (baseType.symbol !== resolveEntityName(baseTypeNode.typeName, SymbolFlags.Value)) {
error(baseTypeNode, Diagnostics.Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0, typeToString(baseType));
}
@ -9656,30 +9593,25 @@ module ts {
function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) {
checkGrammarModifiers(node);
if (isInternalModuleImportEqualsDeclaration(node)) {
if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) {
checkImportBinding(node);
var symbol = getSymbolOfNode(node);
var target = resolveImport(symbol);
if (target !== unknownSymbol) {
if (target.flags & SymbolFlags.Value) {
// Target is a value symbol, check that it is not hidden by a local declaration with the same name and
// ensure it can be evaluated as an expression
var moduleName = getFirstIdentifier(<EntityName>node.moduleReference);
if (resolveEntityName(node, moduleName, SymbolFlags.Value | SymbolFlags.Namespace).flags & SymbolFlags.Namespace) {
checkExpressionOrQualifiedName(<EntityName>node.moduleReference);
}
else {
error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName));
}
}
if (target.flags & SymbolFlags.Type) {
checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0);
}
if (node.flags & NodeFlags.Export) {
markExportAsReferenced(node);
}
}
else {
if (checkExternalImportOrExportDeclaration(node)) {
checkImportBinding(node);
if (isInternalModuleImportEqualsDeclaration(node)) {
var target = resolveImport(getSymbolOfNode(node));
if (target !== unknownSymbol) {
if (target.flags & SymbolFlags.Value) {
// Target is a value symbol, check that it is not hidden by a local declaration with the same name
var moduleName = getFirstIdentifier(<EntityName>node.moduleReference);
if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace).flags & SymbolFlags.Namespace)) {
error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName));
}
}
if (target.flags & SymbolFlags.Type) {
checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0);
}
}
}
}
}
@ -9690,13 +9622,21 @@ module ts {
}
if (!node.moduleSpecifier || checkExternalImportOrExportDeclaration(node)) {
if (node.exportClause) {
forEach(node.exportClause.elements, checkImportSymbol);
forEach(node.exportClause.elements, checkExportSpecifier);
}
}
}
function checkExportSpecifier(node: ExportSpecifier) {
checkImportSymbol(node);
if (!(<ExportDeclaration>node.parent.parent).moduleSpecifier) {
markExportAsReferenced(node);
}
}
function checkExportAssignment(node: ExportAssignment) {
if (node.parent.kind === SyntaxKind.ModuleBlock && (<ModuleDeclaration>node.parent.parent).name.kind === SyntaxKind.Identifier) {
var container = node.parent.kind === SyntaxKind.SourceFile ? <SourceFile>node.parent : <ModuleDeclaration>node.parent.parent;
if (container.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>container).name.kind === SyntaxKind.Identifier) {
error(node, Diagnostics.An_export_assignment_cannot_be_used_in_an_internal_module);
return;
}
@ -9704,12 +9644,64 @@ module ts {
if (!checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) {
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
}
var container = node.parent;
if (container.kind !== SyntaxKind.SourceFile) {
// In a module, the immediate parent will be a block, so climb up one more parent
container = container.parent;
if (node.expression.kind === SyntaxKind.Identifier) {
markExportAsReferenced(node);
}
else {
checkExpressionCached(node.expression);
}
checkExternalModuleExports(container);
}
function getModuleStatements(node: Declaration): ModuleElement[] {
if (node.kind === SyntaxKind.SourceFile) {
return (<SourceFile>node).statements;
}
if (node.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>node).body.kind === SyntaxKind.ModuleBlock) {
return (<ModuleBlock>(<ModuleDeclaration>node).body).statements;
}
return emptyArray;
}
function hasExportedMembers(moduleSymbol: Symbol) {
var declarations = moduleSymbol.declarations;
for (var i = 0; i < declarations.length; i++) {
var statements = getModuleStatements(declarations[i]);
for (var j = 0; j < statements.length; j++) {
var node = statements[j];
if (node.kind === SyntaxKind.ExportDeclaration) {
var exportClause = (<ExportDeclaration>node).exportClause;
if (!exportClause) {
return true;
}
var specifiers = exportClause.elements;
for (var k = 0; k < specifiers.length; k++) {
var specifier = specifiers[k];
if (!(specifier.propertyName && specifier.name && specifier.name.text === "default")) {
return true;
}
}
}
else if (node.kind !== SyntaxKind.ExportAssignment && node.flags & NodeFlags.Export) {
return true;
}
}
}
}
function checkExternalModuleExports(node: SourceFile | ModuleDeclaration) {
var moduleSymbol = getSymbolOfNode(node);
var links = getSymbolLinks(moduleSymbol);
if (!links.exportsChecked) {
var defaultSymbol = getExportAssignmentSymbol(moduleSymbol);
if (defaultSymbol) {
if (hasExportedMembers(moduleSymbol)) {
var declaration = getDeclarationOfImportSymbol(defaultSymbol);
error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements);
}
}
links.exportsChecked = true;
}
checkTypeOfExportAssignmentSymbol(getSymbolOfNode(container));
}
function checkSourceElement(node: Node): void {
@ -9928,13 +9920,7 @@ module ts {
checkFunctionExpressionBodies(node);
if (isExternalModule(node)) {
var symbol = getExportAssignmentSymbol(node.symbol);
if (symbol && symbol.flags & SymbolFlags.Import) {
// Mark the import as referenced so that we emit it in the final .js file.
getSymbolLinks(symbol).referenced = true;
// mark any import declarations that depend upon this import as referenced
markLinkedImportsAsReferenced(<ImportEqualsDeclaration>getDeclarationOfKind(symbol, SyntaxKind.ImportEqualsDeclaration))
}
checkExternalModuleExports(node);
}
if (potentialThisCollisions.length) {
@ -10182,7 +10168,7 @@ module ts {
}
if (entityName.parent.kind === SyntaxKind.ExportAssignment) {
return resolveEntityName(/*location*/ entityName.parent.parent, <Identifier>entityName,
return resolveEntityName(<Identifier>entityName,
/*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Import);
}
@ -10207,7 +10193,7 @@ module ts {
// Include Import in the meaning, this ensures that we do not follow aliases to where they point and instead
// return the alias symbol.
var meaning: SymbolFlags = SymbolFlags.Value | SymbolFlags.Import;
return resolveEntityName(entityName, <Identifier>entityName, meaning);
return resolveEntityName(<Identifier>entityName, meaning);
}
else if (entityName.kind === SyntaxKind.PropertyAccessExpression) {
var symbol = getNodeLinks(entityName).resolvedSymbol;
@ -10229,7 +10215,7 @@ module ts {
// Include Import in the meaning, this ensures that we do not follow aliases to where they point and instead
// return the alias symbol.
meaning |= SymbolFlags.Import;
return resolveEntityName(entityName, <EntityName>entityName, meaning);
return resolveEntityName(<EntityName>entityName, meaning);
}
// Do we want to return undefined here?
@ -10301,7 +10287,7 @@ module ts {
// This is necessary as an identifier in short-hand property assignment can contains two meaning:
// property name and property value.
if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) {
return resolveEntityName(location, (<ShorthandPropertyAssignment>location).name, SymbolFlags.Value);
return resolveEntityName((<ShorthandPropertyAssignment>location).name, SymbolFlags.Value);
}
return undefined;
}
@ -10567,9 +10553,9 @@ module ts {
}
}
function getExportAssignmentName(node: SourceFile): string {
var symbol = getExportAssignmentSymbol(getSymbolOfNode(node));
return symbol && symbol !== unknownSymbol && symbolIsValue(symbol) && !isConstEnumSymbol(symbol) ? symbolToString(symbol): undefined;
function hasExportDefaultValue(node: SourceFile): boolean {
var symbol = getResolvedExportAssignmentSymbol(getSymbolOfNode(node));
return symbol && symbol !== unknownSymbol && symbolIsValue(symbol) && !isConstEnumSymbol(symbol);
}
function isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean {
@ -10596,11 +10582,6 @@ module ts {
if (getSymbolLinks(symbol).referenced) {
return true;
}
// logic below will answer 'true' for exported import declaration in a nested module that itself is not exported.
// As a consequence this might cause emitting extra.
if (node.kind === SyntaxKind.ImportEqualsDeclaration && node.flags & NodeFlags.Export && isImportResolvedToValue(symbol)) {
return true;
}
}
return forEachChild(node, isReferencedImportDeclaration);
}
@ -10676,7 +10657,7 @@ module ts {
return {
getGeneratedNameForNode,
getExpressionNameSubstitution,
getExportAssignmentName,
hasExportDefaultValue,
isReferencedImportDeclaration,
getNodeCheckFlags,
isTopLevelValueImportEqualsWithEntityName,

View File

@ -1580,6 +1580,7 @@ module ts {
var tempParameters: Identifier[];
var externalImports: ExternalImportInfo[];
var exportSpecifiers: Map<ExportSpecifier[]>;
var exportDefault: ExportAssignment | ExportSpecifier;
/** write emitted output to disk*/
var writeEmittedFiles = writeJavaScriptFile;
@ -3446,7 +3447,7 @@ module ts {
}
function emitExportMemberAssignments(name: Identifier) {
if (exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
if (!exportDefault && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
forEach(exportSpecifiers[name.text], specifier => {
writeLine();
emitStart(specifier.name);
@ -4665,13 +4666,20 @@ module ts {
function createExternalModuleInfo(sourceFile: SourceFile) {
externalImports = [];
exportSpecifiers = {};
exportDefault = undefined;
forEach(sourceFile.statements, node => {
if (node.kind === SyntaxKind.ExportDeclaration && !(<ExportDeclaration>node).moduleSpecifier) {
forEach((<ExportDeclaration>node).exportClause.elements, specifier => {
if (specifier.name.text === "default") {
exportDefault = exportDefault || specifier;
}
var name = (specifier.propertyName || specifier.name).text;
(exportSpecifiers[name] || (exportSpecifiers[name] = [])).push(specifier);
});
}
else if (node.kind === SyntaxKind.ExportAssignment) {
exportDefault = exportDefault || <ExportAssignment>node;
}
else {
var info = createExternalImportInfo(node);
if (info) {
@ -4759,17 +4767,7 @@ module ts {
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
// TODO: Handle export default expressions
var exportName = resolver.getExportAssignmentName(node);
if (exportName) {
writeLine();
var exportAssignment = getFirstExportAssignment(node);
emitStart(exportAssignment);
write("return ");
emit(exportAssignment.expression);
write(";");
emitEnd(exportAssignment);
}
emitExportDefault(node, /*emitAsReturn*/ true);
decreaseIndent();
writeLine();
write("});");
@ -4779,16 +4777,22 @@ module ts {
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
// TODO: Handle export default expressions
var exportName = resolver.getExportAssignmentName(node);
if (exportName) {
emitExportDefault(node, /*emitAsReturn*/ false);
}
function emitExportDefault(sourceFile: SourceFile, emitAsReturn: boolean) {
if (exportDefault && resolver.hasExportDefaultValue(sourceFile)) {
writeLine();
var exportAssignment = getFirstExportAssignment(node);
emitStart(exportAssignment);
write("module.exports = ");
emit(exportAssignment.expression);
emitStart(exportDefault);
write(emitAsReturn ? "return " : "module.exports = ");
if (exportDefault.kind === SyntaxKind.ExportAssignment) {
emit((<ExportAssignment>exportDefault).expression);
}
else {
emit((<ExportSpecifier>exportDefault).propertyName);
}
write(";");
emitEnd(exportAssignment);
emitEnd(exportDefault);
}
}
@ -4845,6 +4849,7 @@ module ts {
else {
externalImports = undefined;
exportSpecifiers = undefined;
exportDefault = undefined;
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);

View File

@ -863,11 +863,7 @@ module ts {
members: NodeArray<EnumMember>;
}
export interface ExportContainer {
exportStars?: ExportDeclaration[]; // List of 'export *' statements (initialized by binding)
}
export interface ModuleDeclaration extends Declaration, ModuleElement, ExportContainer {
export interface ModuleDeclaration extends Declaration, ModuleElement {
name: Identifier | LiteralExpression;
body: ModuleBlock | ModuleDeclaration;
}
@ -912,7 +908,7 @@ module ts {
name: Identifier;
}
export interface ExportDeclaration extends Statement, ModuleElement {
export interface ExportDeclaration extends Declaration, ModuleElement {
exportClause?: NamedExports;
moduleSpecifier?: Expression;
}
@ -932,7 +928,7 @@ module ts {
export type ImportSpecifier = ImportOrExportSpecifier;
export type ExportSpecifier = ImportOrExportSpecifier;
export interface ExportAssignment extends Statement, ModuleElement {
export interface ExportAssignment extends Declaration, ModuleElement {
isExportEquals?: boolean;
expression: Expression;
}
@ -946,7 +942,7 @@ module ts {
}
// Source files are declarations when they are external modules.
export interface SourceFile extends Declaration, ExportContainer {
export interface SourceFile extends Declaration {
statements: NodeArray<ModuleElement>;
endOfFileToken: Node;
@ -1191,7 +1187,7 @@ module ts {
export interface EmitResolver {
getGeneratedNameForNode(node: ModuleDeclaration | EnumDeclaration | ImportDeclaration | ExportDeclaration): string;
getExpressionNameSubstitution(node: Identifier): string;
getExportAssignmentName(node: SourceFile): string;
hasExportDefaultValue(node: SourceFile): boolean;
isReferencedImportDeclaration(node: Node): boolean;
isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean;
getNodeCheckFlags(node: Node): NodeCheckFlags;
@ -1227,11 +1223,9 @@ module ts {
Signature = 0x00020000, // Call, construct, or index signature
TypeParameter = 0x00040000, // Type parameter
TypeAlias = 0x00080000, // Type alias
// Export markers (see comment in declareModuleMember in binder)
ExportValue = 0x00100000, // Exported value marker
ExportType = 0x00200000, // Exported type marker
ExportNamespace = 0x00400000, // Exported namespace marker
ExportValue = 0x00100000, // Exported value marker (see comment in declareModuleMember in binder)
ExportType = 0x00200000, // Exported type marker (see comment in declareModuleMember in binder)
ExportNamespace = 0x00400000, // Exported namespace marker (see comment in declareModuleMember in binder)
Import = 0x00800000, // Import
Instantiated = 0x01000000, // Instantiated symbol
Merged = 0x02000000, // Merged symbol (created during program binding)
@ -1239,6 +1233,7 @@ module ts {
Prototype = 0x08000000, // Prototype property (no source representation)
UnionProperty = 0x10000000, // Property in union type
Optional = 0x20000000, // Optional property
ExportStar = 0x40000000, // Export * declaration
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
@ -1306,10 +1301,9 @@ module ts {
declaredType?: Type; // Type of class, interface, enum, or type parameter
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
exportAssignmentChecked?: boolean; // True if export assignment was checked
exportAssignmentSymbol?: Symbol; // Symbol exported from external module
unionType?: UnionType; // Containing union type for union property
resolvedExports?: SymbolTable; // Resolved exports of module
exportsChecked?: boolean; // True if exports of external module have been checked
}
export interface TransientSymbol extends Symbol, SymbolLinks { }