/
ngcc_compiler_host.ts
95 lines (85 loc) 路 4.29 KB
/
ngcc_compiler_host.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';
import {AbsoluteFsPath, FileSystem, NgtscCompilerHost} from '../../../src/ngtsc/file_system';
import {isWithinPackage} from '../analysis/util';
import {isRelativePath} from '../utils';
import {EntryPointFileCache} from './source_file_cache';
/**
* Represents a compiler host that resolves a module import as a JavaScript source file if
* available, instead of the .d.ts typings file that would have been resolved by TypeScript. This
* is necessary for packages that have their typings in the same directory as the sources, which
* would otherwise let TypeScript prefer the .d.ts file instead of the JavaScript source file.
*/
export class NgccSourcesCompilerHost extends NgtscCompilerHost {
constructor(
fs: FileSystem, options: ts.CompilerOptions, private cache: EntryPointFileCache,
private moduleResolutionCache: ts.ModuleResolutionCache,
protected packagePath: AbsoluteFsPath) {
super(fs, options);
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget): ts.SourceFile|undefined {
return this.cache.getCachedSourceFile(fileName, languageVersion);
}
resolveModuleNames(
moduleNames: string[], containingFile: string, reusedNames?: string[],
redirectedReference?: ts.ResolvedProjectReference): Array<ts.ResolvedModule|undefined> {
return moduleNames.map(moduleName => {
const {resolvedModule} = ts.resolveModuleName(
moduleName, containingFile, this.options, this, this.moduleResolutionCache,
redirectedReference);
// If the module request originated from a relative import in a JavaScript source file,
// TypeScript may have resolved the module to its .d.ts declaration file if the .js source
// file was in the same directory. This is undesirable, as we need to have the actual
// JavaScript being present in the program. This logic recognizes this scenario and rewrites
// the resolved .d.ts declaration file to its .js counterpart, if it exists.
if (resolvedModule?.extension === ts.Extension.Dts && containingFile.endsWith('.js') &&
isRelativePath(moduleName)) {
const jsFile = resolvedModule.resolvedFileName.replace(/\.d\.ts$/, '.js');
if (this.fileExists(jsFile)) {
return {...resolvedModule, resolvedFileName: jsFile, extension: ts.Extension.Js};
}
}
// Prevent loading JavaScript source files outside of the package root, which would happen for
// packages that don't have .d.ts files. As ngcc should only operate on the .js files
// contained within the package, any files outside the package are simply discarded. This does
// result in a partial program with error diagnostics, however ngcc won't gather diagnostics
// for the program it creates so these diagnostics won't be reported.
if (resolvedModule?.extension === ts.Extension.Js &&
!isWithinPackage(this.packagePath, this.fs.resolve(resolvedModule.resolvedFileName))) {
return undefined;
}
return resolvedModule;
});
}
}
/**
* A compiler host implementation that is used for the typings program. It leverages the entry-point
* cache for source files and module resolution, as these results can be reused across the sources
* program.
*/
export class NgccDtsCompilerHost extends NgtscCompilerHost {
constructor(
fs: FileSystem, options: ts.CompilerOptions, private cache: EntryPointFileCache,
private moduleResolutionCache: ts.ModuleResolutionCache) {
super(fs, options);
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget): ts.SourceFile|undefined {
return this.cache.getCachedSourceFile(fileName, languageVersion);
}
resolveModuleNames(
moduleNames: string[], containingFile: string, reusedNames?: string[],
redirectedReference?: ts.ResolvedProjectReference): Array<ts.ResolvedModule|undefined> {
return moduleNames.map(moduleName => {
const {resolvedModule} = ts.resolveModuleName(
moduleName, containingFile, this.options, this, this.moduleResolutionCache,
redirectedReference);
return resolvedModule;
});
}
}