From 5b80ab372d82d5c703d483fb98f4ecde34693c52 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Wed, 1 May 2019 14:03:39 +0100 Subject: [PATCH] fix(ivy): use `CompilerHost.resolveModuleNames()` if available (#30017) Sometimes we need to override module resolution behaviour. We do this by implementing the optional method `resolveModuleNames()` on `CompilerHost`. This commit ensures that we always try this method first before falling back to the standard `ts.resolveModuleName` PR Close #30017 --- .../src/ngtsc/imports/src/emitter.ts | 8 ++++---- .../src/ngtsc/imports/src/resolver.ts | 4 ++-- packages/compiler-cli/src/ngtsc/program.ts | 8 ++++---- .../src/ngtsc/util/src/typescript.ts | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts index f9052c8182..fcfb24edcd 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts @@ -11,7 +11,7 @@ import {ExternalReference} from '@angular/compiler/src/compiler'; import * as ts from 'typescript'; import {LogicalFileSystem, LogicalProjectPath} from '../../path'; -import {getSourceFile, isDeclaration, nodeNameForError} from '../../util/src/typescript'; +import {getSourceFile, isDeclaration, nodeNameForError, resolveModuleName} from '../../util/src/typescript'; import {findExportedNameOfNode} from './find_export'; import {ImportMode, Reference} from './references'; @@ -162,12 +162,12 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { private enumerateExportsOfModule(specifier: string, fromFile: string): Map|null { // First, resolve the module specifier to its entry point, and get the ts.Symbol for it. - const resolved = ts.resolveModuleName(specifier, fromFile, this.options, this.host); - if (resolved.resolvedModule === undefined) { + const resolvedModule = resolveModuleName(specifier, fromFile, this.options, this.host); + if (resolvedModule === undefined) { return null; } - const entryPointFile = this.program.getSourceFile(resolved.resolvedModule.resolvedFileName); + const entryPointFile = this.program.getSourceFile(resolvedModule.resolvedFileName); if (entryPointFile === undefined) { return null; } diff --git a/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts b/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts index 6fd244555a..309aee999a 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts @@ -8,6 +8,7 @@ import * as ts from 'typescript'; +import {resolveModuleName} from '../../util/src/typescript'; import {Reference} from './references'; export interface ReferenceResolver { @@ -28,8 +29,7 @@ export class ModuleResolver { resolveModuleName(module: string, containingFile: ts.SourceFile): ts.SourceFile|null { const resolved = - ts.resolveModuleName(module, containingFile.fileName, this.compilerOptions, this.host) - .resolvedModule; + resolveModuleName(module, containingFile.fileName, this.compilerOptions, this.host); if (resolved === undefined) { return null; } diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index ddb741b11d..0cb0c9b856 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -33,7 +33,7 @@ import {IvyCompilation, declarationTransformFactory, ivyTransformFactory} from ' import {aliasTransformFactory} from './transform/src/alias'; import {TypeCheckContext, TypeCheckingConfig, typeCheckFilePath} from './typecheck'; import {normalizeSeparators} from './util/src/path'; -import {getRootDirs, isDtsPath} from './util/src/typescript'; +import {getRootDirs, isDtsPath, resolveModuleName} from './util/src/typescript'; export class NgtscProgram implements api.Program { private tsProgram: ts.Program; @@ -253,10 +253,10 @@ export class NgtscProgram implements api.Program { // of the root files. const containingFile = this.tsProgram.getRootFileNames()[0]; const [entryPath, moduleName] = entryRoute.split('#'); - const resolved = ts.resolveModuleName(entryPath, containingFile, this.options, this.host); + const resolvedModule = resolveModuleName(entryPath, containingFile, this.options, this.host); - if (resolved.resolvedModule) { - entryRoute = entryPointKeyFor(resolved.resolvedModule.resolvedFileName, moduleName); + if (resolvedModule) { + entryRoute = entryPointKeyFor(resolvedModule.resolvedFileName, moduleName); } } diff --git a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts index d9df799747..dbd598f59e 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts @@ -91,3 +91,20 @@ export function nodeDebugInfo(node: ts.Node): string { const {line, character} = ts.getLineAndCharacterOfPosition(sf, node.pos); return `[${sf.fileName}: ${ts.SyntaxKind[node.kind]} @ ${line}:${character}]`; } + +/** + * Resolve the specified `moduleName` using the given `compilerOptions` and `compilerHost`. + * + * This helper will attempt to use the `CompilerHost.resolveModuleNames()` method if available. + * Otherwise it will fallback on the `ts.ResolveModuleName()` function. + */ +export function resolveModuleName( + moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions, + compilerHost: ts.CompilerHost): ts.ResolvedModule|undefined { + if (compilerHost.resolveModuleNames) { + return compilerHost.resolveModuleNames([moduleName], containingFile)[0]; + } else { + return ts.resolveModuleName(moduleName, containingFile, compilerOptions, compilerHost) + .resolvedModule; + } +} \ No newline at end of file