7
7
*/
8
8
9
9
import type ng from '@angular/compiler-cli' ;
10
- import ts from 'typescript' ;
10
+ import { createHash } from 'node:crypto' ;
11
+ import nodePath from 'node:path' ;
12
+ import type ts from 'typescript' ;
11
13
12
14
export type AngularCompilerOptions = ng . CompilerOptions ;
13
15
export type AngularCompilerHost = ng . CompilerHost ;
@@ -24,36 +26,146 @@ export interface AngularHostOptions {
24
26
processWebWorker ( workerFile : string , containingFile : string ) : string ;
25
27
}
26
28
27
- // Temporary deep import for host augmentation support.
28
- // TODO: Move these to a private exports location or move the implementation into this package.
29
- const {
30
- augmentHostWithCaching,
31
- augmentHostWithReplacements,
32
- augmentProgramWithVersioning,
33
- } = require ( '@ngtools/webpack/src/ivy/host' ) ;
34
-
35
29
/**
36
30
* Patches in-place the `getSourceFiles` function on an instance of a TypeScript
37
31
* `Program` to ensure that all returned SourceFile instances have a `version`
38
32
* field. The `version` field is required when used with a TypeScript BuilderProgram.
39
33
* @param program The TypeScript Program instance to patch.
40
34
*/
41
35
export function ensureSourceFileVersions ( program : ts . Program ) : void {
42
- augmentProgramWithVersioning ( program ) ;
36
+ const baseGetSourceFiles = program . getSourceFiles ;
37
+ // TODO: Update Angular compiler to add versions to all internal files and remove this
38
+ program . getSourceFiles = function ( ...parameters ) {
39
+ const files : readonly ( ts . SourceFile & { version ?: string } ) [ ] = baseGetSourceFiles (
40
+ ...parameters ,
41
+ ) ;
42
+
43
+ for ( const file of files ) {
44
+ if ( file . version === undefined ) {
45
+ file . version = createHash ( 'sha256' ) . update ( file . text ) . digest ( 'hex' ) ;
46
+ }
47
+ }
48
+
49
+ return files ;
50
+ } ;
51
+ }
52
+
53
+ function augmentHostWithCaching ( host : ts . CompilerHost , cache : Map < string , ts . SourceFile > ) : void {
54
+ const baseGetSourceFile = host . getSourceFile ;
55
+ host . getSourceFile = function (
56
+ fileName ,
57
+ languageVersion ,
58
+ onError ,
59
+ shouldCreateNewSourceFile ,
60
+ ...parameters
61
+ ) {
62
+ if ( ! shouldCreateNewSourceFile && cache . has ( fileName ) ) {
63
+ return cache . get ( fileName ) ;
64
+ }
65
+
66
+ const file = baseGetSourceFile . call (
67
+ host ,
68
+ fileName ,
69
+ languageVersion ,
70
+ onError ,
71
+ true ,
72
+ ...parameters ,
73
+ ) ;
74
+
75
+ if ( file ) {
76
+ cache . set ( fileName , file ) ;
77
+ }
78
+
79
+ return file ;
80
+ } ;
81
+ }
82
+
83
+ function augmentResolveModuleNames (
84
+ typescript : typeof ts ,
85
+ host : ts . CompilerHost ,
86
+ resolvedModuleModifier : (
87
+ resolvedModule : ts . ResolvedModule | undefined ,
88
+ moduleName : string ,
89
+ ) => ts . ResolvedModule | undefined ,
90
+ moduleResolutionCache ?: ts . ModuleResolutionCache ,
91
+ ) : void {
92
+ if ( host . resolveModuleNames ) {
93
+ const baseResolveModuleNames = host . resolveModuleNames ;
94
+ host . resolveModuleNames = function ( moduleNames : string [ ] , ...parameters ) {
95
+ return moduleNames . map ( ( name ) => {
96
+ const result = baseResolveModuleNames . call ( host , [ name ] , ...parameters ) ;
97
+
98
+ return resolvedModuleModifier ( result [ 0 ] , name ) ;
99
+ } ) ;
100
+ } ;
101
+ } else {
102
+ host . resolveModuleNames = function (
103
+ moduleNames : string [ ] ,
104
+ containingFile : string ,
105
+ _reusedNames : string [ ] | undefined ,
106
+ redirectedReference : ts . ResolvedProjectReference | undefined ,
107
+ options : ts . CompilerOptions ,
108
+ ) {
109
+ return moduleNames . map ( ( name ) => {
110
+ const result = typescript . resolveModuleName (
111
+ name ,
112
+ containingFile ,
113
+ options ,
114
+ host ,
115
+ moduleResolutionCache ,
116
+ redirectedReference ,
117
+ ) . resolvedModule ;
118
+
119
+ return resolvedModuleModifier ( result , name ) ;
120
+ } ) ;
121
+ } ;
122
+ }
123
+ }
124
+
125
+ function normalizePath ( path : string ) : string {
126
+ return nodePath . win32 . normalize ( path ) . replace ( / \\ / g, nodePath . posix . sep ) ;
127
+ }
128
+
129
+ function augmentHostWithReplacements (
130
+ typescript : typeof ts ,
131
+ host : ts . CompilerHost ,
132
+ replacements : Record < string , string > ,
133
+ moduleResolutionCache ?: ts . ModuleResolutionCache ,
134
+ ) : void {
135
+ if ( Object . keys ( replacements ) . length === 0 ) {
136
+ return ;
137
+ }
138
+
139
+ const normalizedReplacements : Record < string , string > = { } ;
140
+ for ( const [ key , value ] of Object . entries ( replacements ) ) {
141
+ normalizedReplacements [ normalizePath ( key ) ] = normalizePath ( value ) ;
142
+ }
143
+
144
+ const tryReplace = ( resolvedModule : ts . ResolvedModule | undefined ) => {
145
+ const replacement = resolvedModule && normalizedReplacements [ resolvedModule . resolvedFileName ] ;
146
+ if ( replacement ) {
147
+ return {
148
+ resolvedFileName : replacement ,
149
+ isExternalLibraryImport : / [ / \\ ] n o d e _ m o d u l e s [ / \\ ] / . test ( replacement ) ,
150
+ } ;
151
+ } else {
152
+ return resolvedModule ;
153
+ }
154
+ } ;
155
+
156
+ augmentResolveModuleNames ( typescript , host , tryReplace , moduleResolutionCache ) ;
43
157
}
44
158
45
159
export function createAngularCompilerHost (
160
+ typescript : typeof ts ,
46
161
compilerOptions : AngularCompilerOptions ,
47
162
hostOptions : AngularHostOptions ,
48
163
) : AngularCompilerHost {
49
164
// Create TypeScript compiler host
50
- const host : AngularCompilerHost = ts . createIncrementalCompilerHost ( compilerOptions ) ;
51
- // Set the parsing mode to the same as TS 5.3 default for tsc. This provides a parse
165
+ const host : AngularCompilerHost = typescript . createIncrementalCompilerHost ( compilerOptions ) ;
166
+ // Set the parsing mode to the same as TS 5.3+ default for tsc. This provides a parse
52
167
// performance improvement by skipping non-type related JSDoc parsing.
53
- // NOTE: The check for this enum can be removed when TS 5.3 support is the minimum.
54
- if ( ts . JSDocParsingMode ) {
55
- host . jsDocParsingMode = ts . JSDocParsingMode . ParseForTypeErrors ;
56
- }
168
+ host . jsDocParsingMode = typescript . JSDocParsingMode . ParseForTypeErrors ;
57
169
58
170
// The AOT compiler currently requires this hook to allow for a transformResource hook.
59
171
// Once the AOT compiler allows only a transformResource hook, this can be reevaluated.
@@ -90,14 +202,14 @@ export function createAngularCompilerHost(
90
202
// Augment TypeScript Host for file replacements option
91
203
if ( hostOptions . fileReplacements ) {
92
204
// Provide a resolution cache since overriding resolution prevents automatic creation
93
- const resolutionCache = ts . createModuleResolutionCache (
205
+ const resolutionCache = typescript . createModuleResolutionCache (
94
206
host . getCurrentDirectory ( ) ,
95
207
host . getCanonicalFileName . bind ( host ) ,
96
208
compilerOptions ,
97
209
) ;
98
210
host . getModuleResolutionCache = ( ) => resolutionCache ;
99
211
100
- augmentHostWithReplacements ( host , hostOptions . fileReplacements , resolutionCache ) ;
212
+ augmentHostWithReplacements ( typescript , host , hostOptions . fileReplacements , resolutionCache ) ;
101
213
}
102
214
103
215
// Augment TypeScript Host with source file caching if provided
0 commit comments