1
1
import * as ts from 'typescript' ;
2
+ import { normalize , resolve } from '@angular-devkit/core' ;
2
3
import { Tree , DirEntry } from '@angular-devkit/schematics' ;
3
4
4
5
export function visitTSSourceFiles < Result = void > (
@@ -17,6 +18,190 @@ export function visitTSSourceFiles<Result = void>(
17
18
return result ;
18
19
}
19
20
21
+ export function visitTemplates (
22
+ tree : Tree ,
23
+ visitor : (
24
+ template : {
25
+ fileName : string ;
26
+ content : string ;
27
+ inline : boolean ;
28
+ start : number ;
29
+ } ,
30
+ tree : Tree
31
+ ) => void
32
+ ) : void {
33
+ visitTSSourceFiles ( tree , source => {
34
+ visitComponents ( source , ( _ , decoratorExpressionNode ) => {
35
+ ts . forEachChild ( decoratorExpressionNode , function findTemplates ( n ) {
36
+ if ( ts . isPropertyAssignment ( n ) && ts . isIdentifier ( n . name ) ) {
37
+ if (
38
+ n . name . text === 'template' &&
39
+ ts . isStringLiteralLike ( n . initializer )
40
+ ) {
41
+ // Need to add an offset of one to the start because the template quotes are
42
+ // not part of the template content.
43
+ const templateStartIdx = n . initializer . getStart ( ) + 1 ;
44
+ visitor (
45
+ {
46
+ fileName : source . fileName ,
47
+ content : n . initializer . text ,
48
+ inline : true ,
49
+ start : templateStartIdx ,
50
+ } ,
51
+ tree
52
+ ) ;
53
+ return ;
54
+ } else if (
55
+ n . name . text === 'templateUrl' &&
56
+ ts . isStringLiteralLike ( n . initializer )
57
+ ) {
58
+ const parts = normalize ( source . fileName )
59
+ . split ( '/' )
60
+ . slice ( 0 , - 1 ) ;
61
+ const templatePath = resolve (
62
+ normalize ( parts . join ( '/' ) ) ,
63
+ normalize ( n . initializer . text )
64
+ ) ;
65
+ if ( ! tree . exists ( templatePath ) ) {
66
+ return ;
67
+ }
68
+
69
+ const fileContent = tree . read ( templatePath ) ;
70
+ if ( ! fileContent ) {
71
+ return ;
72
+ }
73
+
74
+ visitor (
75
+ {
76
+ fileName : templatePath ,
77
+ content : fileContent . toString ( ) ,
78
+ inline : false ,
79
+ start : 0 ,
80
+ } ,
81
+ tree
82
+ ) ;
83
+ return ;
84
+ }
85
+ }
86
+
87
+ ts . forEachChild ( n , findTemplates ) ;
88
+ } ) ;
89
+ } ) ;
90
+ } ) ;
91
+ }
92
+
93
+ export function visitNgModuleImports (
94
+ sourceFile : ts . SourceFile ,
95
+ callback : (
96
+ importNode : ts . PropertyAssignment ,
97
+ elementExpressions : ts . NodeArray < ts . Expression >
98
+ ) => void
99
+ ) {
100
+ visitNgModuleProperty ( sourceFile , callback , 'imports' ) ;
101
+ }
102
+
103
+ export function visitNgModuleExports (
104
+ sourceFile : ts . SourceFile ,
105
+ callback : (
106
+ exportNode : ts . PropertyAssignment ,
107
+ elementExpressions : ts . NodeArray < ts . Expression >
108
+ ) => void
109
+ ) {
110
+ visitNgModuleProperty ( sourceFile , callback , 'exports' ) ;
111
+ }
112
+
113
+ function visitNgModuleProperty (
114
+ sourceFile : ts . SourceFile ,
115
+ callback : (
116
+ nodes : ts . PropertyAssignment ,
117
+ elementExpressions : ts . NodeArray < ts . Expression >
118
+ ) => void ,
119
+ property : string
120
+ ) {
121
+ visitNgModules ( sourceFile , ( _ , decoratorExpressionNode ) => {
122
+ ts . forEachChild ( decoratorExpressionNode , function findTemplates ( n ) {
123
+ if (
124
+ ts . isPropertyAssignment ( n ) &&
125
+ ts . isIdentifier ( n . name ) &&
126
+ n . name . text === property &&
127
+ ts . isArrayLiteralExpression ( n . initializer )
128
+ ) {
129
+ callback ( n , n . initializer . elements ) ;
130
+ return ;
131
+ }
132
+
133
+ ts . forEachChild ( n , findTemplates ) ;
134
+ } ) ;
135
+ } ) ;
136
+ }
137
+ export function visitComponents (
138
+ sourceFile : ts . SourceFile ,
139
+ callback : (
140
+ classDeclarationNode : ts . ClassDeclaration ,
141
+ decoratorExpressionNode : ts . ObjectLiteralExpression
142
+ ) => void
143
+ ) {
144
+ visitDecorator ( sourceFile , 'Component' , callback ) ;
145
+ }
146
+
147
+ export function visitNgModules (
148
+ sourceFile : ts . SourceFile ,
149
+ callback : (
150
+ classDeclarationNode : ts . ClassDeclaration ,
151
+ decoratorExpressionNode : ts . ObjectLiteralExpression
152
+ ) => void
153
+ ) {
154
+ visitDecorator ( sourceFile , 'NgModule' , callback ) ;
155
+ }
156
+
157
+ export function visitDecorator (
158
+ sourceFile : ts . SourceFile ,
159
+ decoratorName : string ,
160
+ callback : (
161
+ classDeclarationNode : ts . ClassDeclaration ,
162
+ decoratorExpressionNode : ts . ObjectLiteralExpression
163
+ ) => void
164
+ ) {
165
+ ts . forEachChild ( sourceFile , function findClassDeclaration ( node ) {
166
+ if ( ! ts . isClassDeclaration ( node ) ) {
167
+ ts . forEachChild ( node , findClassDeclaration ) ;
168
+ }
169
+
170
+ const classDeclarationNode = node as ts . ClassDeclaration ;
171
+
172
+ if (
173
+ ! classDeclarationNode . decorators ||
174
+ ! classDeclarationNode . decorators . length
175
+ ) {
176
+ return ;
177
+ }
178
+
179
+ const componentDecorator = classDeclarationNode . decorators . find ( d => {
180
+ return (
181
+ ts . isCallExpression ( d . expression ) &&
182
+ ts . isIdentifier ( d . expression . expression ) &&
183
+ d . expression . expression . text === decoratorName
184
+ ) ;
185
+ } ) ;
186
+
187
+ if ( ! componentDecorator ) {
188
+ return ;
189
+ }
190
+
191
+ const { expression } = componentDecorator ;
192
+ if ( ! ts . isCallExpression ( expression ) ) {
193
+ return ;
194
+ }
195
+
196
+ const [ arg ] = expression . arguments ;
197
+ if ( ! ts . isObjectLiteralExpression ( arg ) ) {
198
+ return ;
199
+ }
200
+
201
+ callback ( classDeclarationNode , arg ) ;
202
+ } ) ;
203
+ }
204
+
20
205
function * visit ( directory : DirEntry ) : IterableIterator < ts . SourceFile > {
21
206
for ( const path of directory . subfiles ) {
22
207
if ( path . endsWith ( '.ts' ) && ! path . endsWith ( '.d.ts' ) ) {
@@ -42,31 +227,3 @@ function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
42
227
yield * visit ( directory . dir ( path ) ) ;
43
228
}
44
229
}
45
-
46
- export function visitNgModuleImports (
47
- sourceFile : ts . SourceFile ,
48
- callback : (
49
- importNode : ts . PropertyAssignment ,
50
- elementExpressions : ts . NodeArray < ts . Expression >
51
- ) => void
52
- ) {
53
- ts . forEachChild ( sourceFile , function findDecorator ( node ) {
54
- if ( ! ts . isDecorator ( node ) ) {
55
- ts . forEachChild ( node , findDecorator ) ;
56
- return ;
57
- }
58
-
59
- ts . forEachChild ( node , function findImportsNode ( n ) {
60
- if (
61
- ts . isPropertyAssignment ( n ) &&
62
- ts . isArrayLiteralExpression ( n . initializer ) &&
63
- ts . isIdentifier ( n . name ) &&
64
- n . name . text === 'imports'
65
- ) {
66
- callback ( n , n . initializer . elements ) ;
67
- }
68
-
69
- ts . forEachChild ( n , findImportsNode ) ;
70
- } ) ;
71
- } ) ;
72
- }
0 commit comments