6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
+ import { ParseError , parseTemplate , TmplAstNode } from '@angular/compiler' ;
9
10
import * as ts from 'typescript' ;
10
11
11
12
import { absoluteFromSourceFile , AbsoluteFsPath , getSourceFileOrError } from '../../file_system' ;
@@ -14,7 +15,7 @@ import {IncrementalBuild} from '../../incremental/api';
14
15
import { ReflectionHost } from '../../reflection' ;
15
16
import { isShim } from '../../shims' ;
16
17
import { getSourceFileOrNull } from '../../util/src/typescript' ;
17
- import { OptimizeFor , ProgramTypeCheckAdapter , TemplateTypeChecker , TypeCheckingConfig , TypeCheckingProgramStrategy , UpdateMode } from '../api' ;
18
+ import { OptimizeFor , ProgramTypeCheckAdapter , TemplateId , TemplateTypeChecker , TypeCheckingConfig , TypeCheckingProgramStrategy , UpdateMode } from '../api' ;
18
19
19
20
import { InliningMode , ShimTypeCheckingData , TypeCheckContextImpl , TypeCheckingHost } from './context' ;
20
21
import { findTypeCheckBlock , shouldReportDiagnostic , TemplateSourceResolver , translateDiagnostic } from './diagnostics' ;
@@ -37,6 +38,47 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
37
38
private compilerHost : Pick < ts . CompilerHost , 'getCanonicalFileName' > ,
38
39
private priorBuild : IncrementalBuild < unknown , FileTypeCheckingData > ) { }
39
40
41
+ resetOverrides ( ) : void {
42
+ for ( const fileRecord of this . state . values ( ) ) {
43
+ if ( fileRecord . templateOverrides !== null ) {
44
+ fileRecord . templateOverrides = null ;
45
+ fileRecord . shimData . clear ( ) ;
46
+ fileRecord . isComplete = false ;
47
+ }
48
+ }
49
+ }
50
+
51
+ overrideComponentTemplate ( component : ts . ClassDeclaration , template : string ) :
52
+ { nodes : TmplAstNode [ ] , errors ?: ParseError [ ] } {
53
+ const { nodes, errors} = parseTemplate ( template , 'override.html' , {
54
+ preserveWhitespaces : true ,
55
+ leadingTriviaChars : [ ] ,
56
+ } ) ;
57
+
58
+ if ( errors !== undefined ) {
59
+ return { nodes, errors} ;
60
+ }
61
+
62
+ const filePath = absoluteFromSourceFile ( component . getSourceFile ( ) ) ;
63
+
64
+ const fileRecord = this . getFileData ( filePath ) ;
65
+ const id = fileRecord . sourceManager . getTemplateId ( component ) ;
66
+
67
+ if ( fileRecord . templateOverrides === null ) {
68
+ fileRecord . templateOverrides = new Map ( ) ;
69
+ }
70
+
71
+ fileRecord . templateOverrides . set ( id , nodes ) ;
72
+
73
+ // Clear data for the shim in question, so it'll be regenerated on the next request.
74
+ const shimFile = this . typeCheckingStrategy . shimPathForComponent ( component ) ;
75
+ fileRecord . shimData . delete ( shimFile ) ;
76
+ fileRecord . isComplete = false ;
77
+ this . isComplete = false ;
78
+
79
+ return { nodes} ;
80
+ }
81
+
40
82
/**
41
83
* Retrieve type-checking diagnostics from the given `ts.SourceFile` using the most recent
42
84
* type-checking program.
@@ -106,6 +148,10 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
106
148
const sfPath = absoluteFromSourceFile ( sf ) ;
107
149
if ( this . state . has ( sfPath ) ) {
108
150
const existingResults = this . state . get ( sfPath ) ! ;
151
+ if ( existingResults . templateOverrides !== null ) {
152
+ // Cannot adopt prior results if template overrides have been requested.
153
+ return ;
154
+ }
109
155
110
156
if ( existingResults . isComplete ) {
111
157
// All data for this file has already been generated, so no need to adopt anything.
@@ -114,7 +160,8 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
114
160
}
115
161
116
162
const previousResults = this . priorBuild . priorTypeCheckingResultsFor ( sf ) ;
117
- if ( previousResults === null || ! previousResults . isComplete ) {
163
+ if ( previousResults === null || ! previousResults . isComplete ||
164
+ previousResults . templateOverrides !== null ) {
118
165
return ;
119
166
}
120
167
@@ -214,6 +261,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
214
261
if ( ! this . state . has ( path ) ) {
215
262
this . state . set ( path , {
216
263
hasInlines : false ,
264
+ templateOverrides : null ,
217
265
sourceManager : new TemplateSourceManager ( ) ,
218
266
isComplete : false ,
219
267
shimData : new Map ( ) ,
@@ -248,6 +296,11 @@ export interface FileTypeCheckingData {
248
296
*/
249
297
sourceManager : TemplateSourceManager ;
250
298
299
+ /**
300
+ * Map of template overrides applied to any components in this input file.
301
+ */
302
+ templateOverrides : Map < TemplateId , TmplAstNode [ ] > | null ;
303
+
251
304
/**
252
305
* Data for each shim generated from this input file.
253
306
*
@@ -280,6 +333,20 @@ class WholeProgramTypeCheckingHost implements TypeCheckingHost {
280
333
return ! fileData . shimData . has ( shimPath ) ;
281
334
}
282
335
336
+ getTemplateOverride ( sfPath : AbsoluteFsPath , node : ts . ClassDeclaration ) : TmplAstNode [ ] | null {
337
+ const fileData = this . impl . getFileData ( sfPath ) ;
338
+ if ( fileData . templateOverrides === null ) {
339
+ return null ;
340
+ }
341
+
342
+ const templateId = fileData . sourceManager . getTemplateId ( node ) ;
343
+ if ( fileData . templateOverrides . has ( templateId ) ) {
344
+ return fileData . templateOverrides . get ( templateId ) ! ;
345
+ }
346
+
347
+ return null ;
348
+ }
349
+
283
350
recordShimData ( sfPath : AbsoluteFsPath , data : ShimTypeCheckingData ) : void {
284
351
const fileData = this . impl . getFileData ( sfPath ) ;
285
352
fileData . shimData . set ( data . path , data ) ;
@@ -324,6 +391,20 @@ class SingleFileTypeCheckingHost implements TypeCheckingHost {
324
391
return ! this . fileData . shimData . has ( shimPath ) ;
325
392
}
326
393
394
+ getTemplateOverride ( sfPath : AbsoluteFsPath , node : ts . ClassDeclaration ) : TmplAstNode [ ] | null {
395
+ this . assertPath ( sfPath ) ;
396
+ if ( this . fileData . templateOverrides === null ) {
397
+ return null ;
398
+ }
399
+
400
+ const templateId = this . fileData . sourceManager . getTemplateId ( node ) ;
401
+ if ( this . fileData . templateOverrides . has ( templateId ) ) {
402
+ return this . fileData . templateOverrides . get ( templateId ) ! ;
403
+ }
404
+
405
+ return null ;
406
+ }
407
+
327
408
recordShimData ( sfPath : AbsoluteFsPath , data : ShimTypeCheckingData ) : void {
328
409
this . assertPath ( sfPath ) ;
329
410
0 commit comments