From 014ad421b62bd89e324cf0afbff654fd454ecf54 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 24 Aug 2017 07:29:13 -0700 Subject: [PATCH 1/3] `moduleAugmentations` may contain an `Identifier` --- src/compiler/checker.ts | 7 ++++--- src/compiler/program.ts | 33 ++++++++++++++++++++------------- src/compiler/types.ts | 3 ++- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82f41bc31e64c..0f407654d2295 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -638,7 +638,7 @@ namespace ts { }); } - function mergeModuleAugmentation(moduleName: LiteralExpression): void { + function mergeModuleAugmentation(moduleName: StringLiteral | Identifier): void { const moduleAugmentation = moduleName.parent; if (moduleAugmentation.symbol.declarations[0] !== moduleAugmentation) { // this is a combined symbol for multiple augmentations within the same file. @@ -670,7 +670,8 @@ namespace ts { mergeSymbol(mainModule, moduleAugmentation.symbol); } else { - error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, moduleName.text); + // moduleName will be a StringLiteral since this is not `declare global`. + error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, (moduleName as StringLiteral).text); } } } @@ -23799,7 +23800,7 @@ namespace ts { } // Initialize global symbol table - let augmentations: ReadonlyArray[]; + let augmentations: ReadonlyArray[]; for (const file of host.getSourceFiles()) { if (!isExternalOrCommonJsModule(file)) { mergeSymbolTable(globals, file.locals); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 305058285f999..9a8d615501df8 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -888,7 +888,7 @@ namespace ts { for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) { const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory); if (resolveModuleNamesWorker) { - const moduleNames = map(concatenate(newSourceFile.imports, newSourceFile.moduleAugmentations), getTextOfLiteral); + const moduleNames = getModuleImportAndAugmentationNames(newSourceFile); const oldProgramState = { program: oldProgram, file: oldSourceFile, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFilePath, newSourceFile, oldProgramState); // ensure that module resolution results are still correct @@ -1430,12 +1430,10 @@ namespace ts { return a.fileName === b.fileName; } - function moduleNameIsEqualTo(a: LiteralExpression, b: LiteralExpression): boolean { - return a.text === b.text; - } - - function getTextOfLiteral(literal: LiteralExpression): string { - return literal.text; + function moduleNameIsEqualTo(a: StringLiteral | Identifier, b: StringLiteral | Identifier): boolean { + return a.kind === SyntaxKind.StringLiteral + ? b.kind === SyntaxKind.StringLiteral && a.text === b.text + : b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText; } function collectExternalModuleReferences(file: SourceFile): void { @@ -1448,7 +1446,7 @@ namespace ts { // file.imports may not be undefined if there exists dynamic import let imports: StringLiteral[]; - let moduleAugmentations: StringLiteral[]; + let moduleAugmentations: Array; let ambientModules: string[]; // If we are importing helpers, we need to add a synthetic reference to resolve the @@ -1477,7 +1475,7 @@ namespace ts { return; - function collectModuleReferences(node: Node, inAmbientModule: boolean): void { + function collectModuleReferences(node: Statement, inAmbientModule: boolean): void { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: @@ -1499,8 +1497,8 @@ namespace ts { break; case SyntaxKind.ModuleDeclaration: if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) { - const moduleName = (node).name; // TODO: GH#17347 - const nameText = ts.getTextOfIdentifierOrLiteral(moduleName); + const moduleName = (node).name; + const nameText = getTextOfIdentifierOrLiteral(moduleName); // Ambient module declarations can be interpreted as augmentations for some existing external modules. // This will happen in two cases: // - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope @@ -1817,8 +1815,7 @@ namespace ts { collectExternalModuleReferences(file); if (file.imports.length || file.moduleAugmentations.length) { // Because global augmentation doesn't have string literal name, we can check for global augmentation as such. - const nonGlobalAugmentation = filter(file.moduleAugmentations, (moduleAugmentation) => moduleAugmentation.kind === SyntaxKind.StringLiteral); - const moduleNames = map(concatenate(file.imports, nonGlobalAugmentation), getTextOfLiteral); + const moduleNames = getModuleImportAndAugmentationNames(file); const oldProgramState = { program: oldProgram, file, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory), file, oldProgramState); Debug.assert(resolutions.length === moduleNames.length); @@ -2229,4 +2226,14 @@ namespace ts { Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names)); return names; } + + function getModuleImportAndAugmentationNames({ imports, moduleAugmentations }: SourceFile): string[] { + const res = imports.map(i => i.text); + for (const aug of moduleAugmentations) { + if (aug.kind === SyntaxKind.StringLiteral) { + res.push(aug.text); + } + } + return res; + } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8fe602ea6f94f..c81a640db51a8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2343,7 +2343,8 @@ namespace ts { /* @internal */ resolvedModules: Map; /* @internal */ resolvedTypeReferenceDirectiveNames: Map; /* @internal */ imports: ReadonlyArray; - /* @internal */ moduleAugmentations: ReadonlyArray; + // Identifier only if `declare global` + /* @internal */ moduleAugmentations: ReadonlyArray; /* @internal */ patternAmbientModules?: PatternAmbientModule[]; /* @internal */ ambientModuleNames: ReadonlyArray; /* @internal */ checkJsDirective: CheckJsDirective | undefined; From 130127da13748929ce678c8cf47f19917c35a0a1 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 25 Aug 2017 10:54:39 -0700 Subject: [PATCH 2/3] Add comment --- src/compiler/program.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9a8d615501df8..0bf0aa2bec540 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2233,6 +2233,7 @@ namespace ts { if (aug.kind === SyntaxKind.StringLiteral) { res.push(aug.text); } + // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`. } return res; } From 08689802c6b6f8c7655b9f8fe6bfbe32f4b2a237 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 25 Aug 2017 14:34:25 -0700 Subject: [PATCH 3/3] Rename function --- src/compiler/program.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0bf0aa2bec540..509cf031ccb3f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -888,7 +888,7 @@ namespace ts { for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) { const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory); if (resolveModuleNamesWorker) { - const moduleNames = getModuleImportAndAugmentationNames(newSourceFile); + const moduleNames = getModuleNames(newSourceFile); const oldProgramState = { program: oldProgram, file: oldSourceFile, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFilePath, newSourceFile, oldProgramState); // ensure that module resolution results are still correct @@ -1815,7 +1815,7 @@ namespace ts { collectExternalModuleReferences(file); if (file.imports.length || file.moduleAugmentations.length) { // Because global augmentation doesn't have string literal name, we can check for global augmentation as such. - const moduleNames = getModuleImportAndAugmentationNames(file); + const moduleNames = getModuleNames(file); const oldProgramState = { program: oldProgram, file, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory), file, oldProgramState); Debug.assert(resolutions.length === moduleNames.length); @@ -2227,7 +2227,7 @@ namespace ts { return names; } - function getModuleImportAndAugmentationNames({ imports, moduleAugmentations }: SourceFile): string[] { + function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] { const res = imports.map(i => i.text); for (const aug of moduleAugmentations) { if (aug.kind === SyntaxKind.StringLiteral) {