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
This commit is contained in:
Pete Bacon Darwin 2019-05-01 14:03:39 +01:00 committed by Kara Erickson
parent 638ba4a2cf
commit 5b80ab372d
4 changed files with 27 additions and 10 deletions

View File

@ -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<ts.Declaration, string>|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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}
}