From 4d05bfdf4aa3aab07e696f34f0912ba93e01cc51 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 25 Aug 2017 15:14:51 -0700 Subject: [PATCH] `moduleAugmentations` may contain an `Identifier` (#18009) * `moduleAugmentations` may contain an `Identifier` * Add comment * Rename function --- src/compiler/checker.ts | 7 ++++--- src/compiler/program.ts | 34 +++++++++++++++++++++------------- src/compiler/types.ts | 3 ++- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c7513deba56..088cb4bb851 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -640,7 +640,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. @@ -672,7 +672,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); } } } @@ -23800,7 +23801,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 800e2f9e619..ec220ad248e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -890,7 +890,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 = getModuleNames(newSourceFile); const oldProgramState = { program: oldProgram, file: oldSourceFile, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFilePath, newSourceFile, oldProgramState); // ensure that module resolution results are still correct @@ -1434,12 +1434,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 { @@ -1452,7 +1450,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 @@ -1481,7 +1479,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: @@ -1503,8 +1501,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 @@ -1821,8 +1819,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 = getModuleNames(file); const oldProgramState = { program: oldProgram, file, modifiedFilePaths }; const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory), file, oldProgramState); Debug.assert(resolutions.length === moduleNames.length); @@ -2233,4 +2230,15 @@ namespace ts { Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names)); return names; } + + function getModuleNames({ 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); + } + // Do nothing if it's an Identifier; we don't need to do module resolution for `declare global`. + } + return res; + } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f5cca6a6820..87ac4afbab1 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;