3
3
// https://github.com/angular/angular-cli/blob/d202480a1707be6575b2c8cf0383cfe6db44413c/packages/schematics/angular/utility/ng-ast-utils.ts
4
4
// https://github.com/NativeScript/nativescript-schematics/blob/438b9e3ef613389980bfa9d071e28ca1f32ab04f/src/ast-utils.ts
5
5
6
- import { dirname , basename , extname , join } from ' path' ;
7
- import * as ts from ' typescript' ;
6
+ import { dirname , basename , extname , join } from " path" ;
7
+ import * as ts from " typescript" ;
8
8
import {
9
9
StandardTransform ,
10
10
TransformOperation ,
@@ -13,20 +13,16 @@ import {
13
13
ReplaceNodeOperation ,
14
14
makeTransform
15
15
} from "@ngtools/webpack/src/transformers" ;
16
- import { workaroundResolve } from ' @ngtools/webpack/src/compiler_host' ;
17
- import { AngularCompilerPlugin } from '@ngtools/webpack' ;
18
- import { findNode , getSourceNodes , getObjectPropertyMatches } from "../utils/ast -utils" ;
16
+ import { AngularCompilerPlugin } from " @ngtools/webpack" ;
17
+ import { findNode , getObjectPropertyMatches , getDecoratorMetadata } from "../utils/ast-utils" ;
18
+ import { getResolvedEntryModule } from "../utils/transformers -utils" ;
19
19
20
20
export function nsReplaceLazyLoader ( getNgCompiler : ( ) => AngularCompilerPlugin ) : ts . TransformerFactory < ts . SourceFile > {
21
21
const getTypeChecker = ( ) => getNgCompiler ( ) . typeChecker ;
22
22
23
23
const standardTransform : StandardTransform = function ( sourceFile : ts . SourceFile ) {
24
24
let ops : TransformOperation [ ] = [ ] ;
25
- const ngCompiler = getNgCompiler ( ) ;
26
-
27
- const entryModule = ngCompiler . entryModule
28
- ? { path : workaroundResolve ( ngCompiler . entryModule . path ) , className : getNgCompiler ( ) . entryModule . className }
29
- : ngCompiler . entryModule ;
25
+ const entryModule = getResolvedEntryModule ( getNgCompiler ( ) ) ;
30
26
const sourceFilePath = join ( dirname ( sourceFile . fileName ) , basename ( sourceFile . fileName , extname ( sourceFile . fileName ) ) ) ;
31
27
if ( ! entryModule || sourceFilePath !== entryModule . path ) {
32
28
return ops ;
@@ -50,7 +46,7 @@ export function addArrayPropertyValueToNgModule(
50
46
newPropertyValueMatch : string ,
51
47
newPropertyValue : string
52
48
) : TransformOperation [ ] {
53
- const ngModuleConfigNodesInFile = getDecoratorMetadata ( sourceFile , ' NgModule' , ' @angular/core' ) ;
49
+ const ngModuleConfigNodesInFile = getDecoratorMetadata ( sourceFile , " NgModule" , " @angular/core" ) ;
54
50
let ngModuleConfigNode : any = ngModuleConfigNodesInFile && ngModuleConfigNodesInFile [ 0 ] ;
55
51
if ( ! ngModuleConfigNode ) {
56
52
return null ;
@@ -63,23 +59,24 @@ export function addArrayPropertyValueToNgModule(
63
59
}
64
60
65
61
const ngLazyLoaderNode = ts . createIdentifier ( NgLazyLoaderCode ) ;
66
- if ( ngModuleConfigNode . kind == ts . SyntaxKind . Identifier ) {
62
+ if ( ngModuleConfigNode . kind === ts . SyntaxKind . Identifier ) {
63
+ const ngModuleConfigIndentifierNode = ngModuleConfigNode as ts . Identifier ;
67
64
// cases like @NgModule (myCoolConfig)
68
65
const configObjectDeclarationNodes = collectDeepNodes < ts . Node > ( sourceFile , ts . SyntaxKind . VariableStatement ) . filter ( imp => {
69
- return findNode ( imp , ts . SyntaxKind . Identifier , ngModuleConfigNode . getText ( ) ) ;
66
+ return findNode ( imp , ts . SyntaxKind . Identifier , ngModuleConfigIndentifierNode . getText ( ) ) ;
70
67
} ) ;
71
68
// will be undefined when the object is imported from another file
72
69
const configObjectDeclaration = ( configObjectDeclarationNodes && configObjectDeclarationNodes [ 0 ] ) ;
73
70
74
- const configObjectName = ngModuleConfigNode . escapedText . trim ( ) ;
71
+ const configObjectName = ( < string > ngModuleConfigIndentifierNode . escapedText ) . trim ( ) ;
75
72
const configObjectSetupCode = getConfigObjectSetupCode ( configObjectName , targetPropertyName , newPropertyValueMatch , newPropertyValue ) ;
76
73
const configObjectSetupNode = ts . createIdentifier ( configObjectSetupCode ) ;
77
74
78
75
return [
79
76
new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ,
80
77
new AddNodeOperation ( sourceFile , configObjectDeclaration || lastImport , undefined , configObjectSetupNode )
81
78
] ;
82
- } else if ( ngModuleConfigNode . kind == ts . SyntaxKind . ObjectLiteralExpression ) {
79
+ } else if ( ngModuleConfigNode . kind === ts . SyntaxKind . ObjectLiteralExpression ) {
83
80
// cases like @NgModule ({ bootstrap: ... })
84
81
const ngModuleConfigObjectNode = ngModuleConfigNode as ts . ObjectLiteralExpression ;
85
82
const matchingProperties : ts . ObjectLiteralElement [ ] = getObjectPropertyMatches ( ngModuleConfigObjectNode , sourceFile , targetPropertyName ) ;
@@ -88,8 +85,8 @@ export function addArrayPropertyValueToNgModule(
88
85
return null ;
89
86
}
90
87
91
- if ( matchingProperties . length == 0 ) {
92
- if ( ngModuleConfigObjectNode . properties . length == 0 ) {
88
+ if ( matchingProperties . length === 0 ) {
89
+ if ( ngModuleConfigObjectNode . properties . length === 0 ) {
93
90
// empty object @NgModule ({ })
94
91
return null ;
95
92
}
@@ -100,7 +97,8 @@ export function addArrayPropertyValueToNgModule(
100
97
101
98
return [
102
99
new AddNodeOperation ( sourceFile , lastConfigObjPropertyNode , undefined , newTargetPropertyNode ) ,
103
- new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ] ;
100
+ new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode )
101
+ ] ;
104
102
105
103
}
106
104
@@ -125,113 +123,34 @@ export function addArrayPropertyValueToNgModule(
125
123
const lastPropertyValueNode = targetPropertyValues [ targetPropertyValues . length - 1 ] ;
126
124
const newPropertyValueNode = ts . createIdentifier ( `${ newPropertyValue } ` ) ;
127
125
128
- return [ new AddNodeOperation ( sourceFile , lastPropertyValueNode , undefined , newPropertyValueNode ) ,
129
- new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ] ;
126
+ return [
127
+ new AddNodeOperation ( sourceFile , lastPropertyValueNode , undefined , newPropertyValueNode ) ,
128
+ new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode )
129
+ ] ;
130
130
} else {
131
131
// empty array @NgModule ({ targetProperty: [ ] })
132
132
const newTargetPropertyValuesNode = ts . createIdentifier ( `[${ newPropertyValue } ]` ) ;
133
133
134
- return [ new ReplaceNodeOperation ( sourceFile , targetPropertyValuesNode , newTargetPropertyValuesNode ) ,
135
- new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ] ;
136
- }
137
- }
138
- }
139
-
140
- function getDecoratorMetadata ( source : ts . SourceFile , identifier : string ,
141
- module : string ) : ts . Node [ ] {
142
- const angularImports : { [ name : string ] : string }
143
- = collectDeepNodes ( source , ts . SyntaxKind . ImportDeclaration )
144
- . map ( ( node : ts . ImportDeclaration ) => _angularImportsFromNode ( node , source ) )
145
- . reduce ( ( acc : { [ name : string ] : string } , current : { [ name : string ] : string } ) => {
146
- for ( const key of Object . keys ( current ) ) {
147
- acc [ key ] = current [ key ] ;
148
- }
149
-
150
- return acc ;
151
- } , { } ) ;
152
-
153
- return getSourceNodes ( source )
154
- . filter ( node => {
155
- return node . kind == ts . SyntaxKind . Decorator
156
- && ( node as ts . Decorator ) . expression . kind == ts . SyntaxKind . CallExpression ;
157
- } )
158
- . map ( node => ( node as ts . Decorator ) . expression as ts . CallExpression )
159
- . filter ( expr => {
160
- if ( expr . expression . kind == ts . SyntaxKind . Identifier ) {
161
- const id = expr . expression as ts . Identifier ;
162
-
163
- return id . getFullText ( source ) == identifier
164
- && angularImports [ id . getFullText ( source ) ] === module ;
165
- } else if ( expr . expression . kind == ts . SyntaxKind . PropertyAccessExpression ) {
166
- // This covers foo.NgModule when importing * as foo.
167
- const paExpr = expr . expression as ts . PropertyAccessExpression ;
168
- // If the left expression is not an identifier, just give up at that point.
169
- if ( paExpr . expression . kind !== ts . SyntaxKind . Identifier ) {
170
- return false ;
171
- }
172
-
173
- const id = paExpr . name . text ;
174
- const moduleId = ( paExpr . expression as ts . Identifier ) . getText ( source ) ;
175
-
176
- return id === identifier && ( angularImports [ moduleId + '.' ] === module ) ;
177
- }
178
-
179
- return false ;
180
- } )
181
- . filter ( expr => expr . arguments [ 0 ]
182
- && ( expr . arguments [ 0 ] . kind == ts . SyntaxKind . ObjectLiteralExpression ||
183
- expr . arguments [ 0 ] . kind == ts . SyntaxKind . Identifier ) )
184
- . map ( expr => expr . arguments [ 0 ] as ts . Node ) ;
185
- }
186
-
187
- function _angularImportsFromNode ( node : ts . ImportDeclaration ,
188
- _sourceFile : ts . SourceFile ) : { [ name : string ] : string } {
189
- const ms = node . moduleSpecifier ;
190
- let modulePath : string ;
191
- switch ( ms . kind ) {
192
- case ts . SyntaxKind . StringLiteral :
193
- modulePath = ( ms as ts . StringLiteral ) . text ;
194
- break ;
195
- default :
196
- return { } ;
197
- }
198
-
199
- if ( ! modulePath . startsWith ( '@angular/' ) ) {
200
- return { } ;
201
- }
202
-
203
- if ( node . importClause ) {
204
- if ( node . importClause . name ) {
205
- // This is of the form `import Name from 'path'`. Ignore.
206
- return { } ;
207
- } else if ( node . importClause . namedBindings ) {
208
- const nb = node . importClause . namedBindings ;
209
- if ( nb . kind == ts . SyntaxKind . NamespaceImport ) {
210
- // This is of the form `import * as name from 'path'`. Return `name.`.
211
- return {
212
- [ ( nb as ts . NamespaceImport ) . name . text + '.' ] : modulePath ,
213
- } ;
214
- } else {
215
- // This is of the form `import {a,b,c} from 'path'`
216
- const namedImports = nb as ts . NamedImports ;
217
-
218
- return namedImports . elements
219
- . map ( ( is : ts . ImportSpecifier ) => is . propertyName ? is . propertyName . text : is . name . text )
220
- . reduce ( ( acc : { [ name : string ] : string } , curr : string ) => {
221
- acc [ curr ] = modulePath ;
222
-
223
- return acc ;
224
- } , { } ) ;
225
- }
134
+ return [
135
+ new ReplaceNodeOperation ( sourceFile , targetPropertyValuesNode , newTargetPropertyValuesNode ) ,
136
+ new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode )
137
+ ] ;
226
138
}
227
-
228
- return { } ;
229
- } else {
230
- // This is of the form `import 'path';`. Nothing to do.
231
- return { } ;
232
139
}
233
140
}
234
141
142
+ // handles cases like @NgModule (myCoolConfig) by returning a code snippet for processing
143
+ // the config object and configuring its {{targetPropertyName}} based on the specified arguments
144
+ // e.g.
145
+ // if (!myCoolConfig.providers) {
146
+ // myCoolConfig.providers = [];
147
+ // }
148
+ // if (Array.isArray(myCoolConfig.providers)) {
149
+ // var wholeWordPropertyRegex = new RegExp("\bNgModuleFactoryLoader\b");
150
+ // if (!myCoolConfig.providers.some(function (property) { return wholeWordPropertyRegex.test(property); })) {
151
+ // myCoolConfig.providers.push({ provide: nsNgCoreImport_Generated.NgModuleFactoryLoader, useClass: NSLazyModulesLoader_Generated });
152
+ // }
153
+ // }
235
154
export function getConfigObjectSetupCode ( configObjectName : string , targetPropertyName : string , newPropertyValueMatch : string , newPropertyValue : string ) {
236
155
return `
237
156
if (!${ configObjectName } .${ targetPropertyName } ) {
@@ -298,4 +217,4 @@ var NSLazyModulesLoader_Generated = /** @class */ (function () {
298
217
], NSLazyModulesLoader_Generated);
299
218
return NSLazyModulesLoader_Generated;
300
219
}());
301
- ` ;
220
+ ` ;
0 commit comments