33// https://github.com/angular/angular-cli/blob/d202480a1707be6575b2c8cf0383cfe6db44413c/packages/schematics/angular/utility/ng-ast-utils.ts
44// https://github.com/NativeScript/nativescript-schematics/blob/438b9e3ef613389980bfa9d071e28ca1f32ab04f/src/ast-utils.ts
55
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" ;
88import {
99 StandardTransform ,
1010 TransformOperation ,
@@ -13,20 +13,16 @@ import {
1313 ReplaceNodeOperation ,
1414 makeTransform
1515} 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" ;
1919
2020export function nsReplaceLazyLoader ( getNgCompiler : ( ) => AngularCompilerPlugin ) : ts . TransformerFactory < ts . SourceFile > {
2121 const getTypeChecker = ( ) => getNgCompiler ( ) . typeChecker ;
2222
2323 const standardTransform : StandardTransform = function ( sourceFile : ts . SourceFile ) {
2424 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 ( ) ) ;
3026 const sourceFilePath = join ( dirname ( sourceFile . fileName ) , basename ( sourceFile . fileName , extname ( sourceFile . fileName ) ) ) ;
3127 if ( ! entryModule || sourceFilePath !== entryModule . path ) {
3228 return ops ;
@@ -50,7 +46,7 @@ export function addArrayPropertyValueToNgModule(
5046 newPropertyValueMatch : string ,
5147 newPropertyValue : string
5248) : TransformOperation [ ] {
53- const ngModuleConfigNodesInFile = getDecoratorMetadata ( sourceFile , ' NgModule' , ' @angular/core' ) ;
49+ const ngModuleConfigNodesInFile = getDecoratorMetadata ( sourceFile , " NgModule" , " @angular/core" ) ;
5450 let ngModuleConfigNode : any = ngModuleConfigNodesInFile && ngModuleConfigNodesInFile [ 0 ] ;
5551 if ( ! ngModuleConfigNode ) {
5652 return null ;
@@ -63,23 +59,24 @@ export function addArrayPropertyValueToNgModule(
6359 }
6460
6561 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 ;
6764 // cases like @NgModule (myCoolConfig)
6865 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 ( ) ) ;
7067 } ) ;
7168 // will be undefined when the object is imported from another file
7269 const configObjectDeclaration = ( configObjectDeclarationNodes && configObjectDeclarationNodes [ 0 ] ) ;
7370
74- const configObjectName = ngModuleConfigNode . escapedText . trim ( ) ;
71+ const configObjectName = ( < string > ngModuleConfigIndentifierNode . escapedText ) . trim ( ) ;
7572 const configObjectSetupCode = getConfigObjectSetupCode ( configObjectName , targetPropertyName , newPropertyValueMatch , newPropertyValue ) ;
7673 const configObjectSetupNode = ts . createIdentifier ( configObjectSetupCode ) ;
7774
7875 return [
7976 new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ,
8077 new AddNodeOperation ( sourceFile , configObjectDeclaration || lastImport , undefined , configObjectSetupNode )
8178 ] ;
82- } else if ( ngModuleConfigNode . kind == ts . SyntaxKind . ObjectLiteralExpression ) {
79+ } else if ( ngModuleConfigNode . kind === ts . SyntaxKind . ObjectLiteralExpression ) {
8380 // cases like @NgModule ({ bootstrap: ... })
8481 const ngModuleConfigObjectNode = ngModuleConfigNode as ts . ObjectLiteralExpression ;
8582 const matchingProperties : ts . ObjectLiteralElement [ ] = getObjectPropertyMatches ( ngModuleConfigObjectNode , sourceFile , targetPropertyName ) ;
@@ -88,8 +85,8 @@ export function addArrayPropertyValueToNgModule(
8885 return null ;
8986 }
9087
91- if ( matchingProperties . length == 0 ) {
92- if ( ngModuleConfigObjectNode . properties . length == 0 ) {
88+ if ( matchingProperties . length === 0 ) {
89+ if ( ngModuleConfigObjectNode . properties . length === 0 ) {
9390 // empty object @NgModule ({ })
9491 return null ;
9592 }
@@ -100,7 +97,8 @@ export function addArrayPropertyValueToNgModule(
10097
10198 return [
10299 new AddNodeOperation ( sourceFile , lastConfigObjPropertyNode , undefined , newTargetPropertyNode ) ,
103- new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode ) ] ;
100+ new AddNodeOperation ( sourceFile , lastImport , undefined , ngLazyLoaderNode )
101+ ] ;
104102
105103 }
106104
@@ -125,113 +123,34 @@ export function addArrayPropertyValueToNgModule(
125123 const lastPropertyValueNode = targetPropertyValues [ targetPropertyValues . length - 1 ] ;
126124 const newPropertyValueNode = ts . createIdentifier ( `${ newPropertyValue } ` ) ;
127125
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+ ] ;
130130 } else {
131131 // empty array @NgModule ({ targetProperty: [ ] })
132132 const newTargetPropertyValuesNode = ts . createIdentifier ( `[${ newPropertyValue } ]` ) ;
133133
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+ ] ;
226138 }
227-
228- return { } ;
229- } else {
230- // This is of the form `import 'path';`. Nothing to do.
231- return { } ;
232139 }
233140}
234141
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+ // }
235154export function getConfigObjectSetupCode ( configObjectName : string , targetPropertyName : string , newPropertyValueMatch : string , newPropertyValue : string ) {
236155 return `
237156if (!${ configObjectName } .${ targetPropertyName } ) {
@@ -298,4 +217,4 @@ var NSLazyModulesLoader_Generated = /** @class */ (function () {
298217 ], NSLazyModulesLoader_Generated);
299218 return NSLazyModulesLoader_Generated;
300219}());
301- ` ;
220+ ` ;
0 commit comments