From 27179b427cf33ecff65c1ee8a3431c014d929a77 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2015 17:46:17 -0800 Subject: [PATCH] Adding some comments --- src/compiler/binder.ts | 4 ++++ src/compiler/checker.ts | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 65b5c9035a2..481596b9aaf 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -129,7 +129,9 @@ module ts { function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); + // The exported symbol for an export default function/class node is always named "default" var name = node.flags & NodeFlags.Default && parent ? "default" : getDeclarationName(node); + if (name !== undefined) { var symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name)); if (symbol.flags & excludes) { @@ -495,9 +497,11 @@ module ts { break; case SyntaxKind.ExportAssignment: if ((node).expression.kind === SyntaxKind.Identifier) { + // An export default clause with an identifier exports all meanings of that identifier declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Import, SymbolFlags.ImportExcludes); } else { + // An export default clause with an expression exports a value declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); } bindChildren(node, 0, /*isBlockScopeContainer*/ false); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfe7add357b..12f2f7a8528 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -571,18 +571,24 @@ module ts { } } + // When an import symbol (i.e. an alias) is referenced, we need to mark the entity it references as referenced and in turn + // repeat that until we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking + // the target of the alias as an expression (which recursively takes us back here if the target references another alias). function markImportSymbolAsReferenced(symbol: Symbol) { var links = getSymbolLinks(symbol); if (!links.referenced) { links.referenced = true; var node = getDeclarationOfImportSymbol(symbol); if (node.kind === SyntaxKind.ExportAssignment) { + // export default checkExpressionCached((node).expression); } else if (node.kind === SyntaxKind.ExportSpecifier) { + // export { } or export { as foo } checkExpressionCached((node).propertyName || (node).name); } else if (isInternalModuleImportEqualsDeclaration(node)) { + // import foo = checkExpressionCached((node).moduleReference); } } @@ -717,6 +723,7 @@ module ts { function getExportsForModule(moduleSymbol: Symbol): SymbolTable { if (compilerOptions.target < ScriptTarget.ES6) { + // A default export hides all other exports in CommonJS and AMD modules var defaultSymbol = getExportAssignmentSymbol(moduleSymbol); if (defaultSymbol) { return { @@ -729,6 +736,8 @@ module ts { visit(moduleSymbol); return result || 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) { if (!contains(visitedSymbols, symbol)) { visitedSymbols.push(symbol); @@ -738,6 +747,7 @@ module ts { } extendSymbolTable(result, symbol.exports); } + // All export * declarations are collected in an __export symbol by the binder var exportStars = symbol.exports["__export"]; if (exportStars) { forEach(exportStars.declarations, node => {