5
5
* Use of this source code is governed by an MIT-style license that can be
6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
- import { normalize , strings } from '@angular-devkit/core' ;
8
+ import { Path , normalize , strings } from '@angular-devkit/core' ;
9
9
import {
10
10
Rule ,
11
11
SchematicsException ,
@@ -17,17 +17,28 @@ import {
17
17
mergeWith ,
18
18
move ,
19
19
noop ,
20
+ schematic ,
20
21
url ,
21
22
} from '@angular-devkit/schematics' ;
22
23
import * as ts from '../third_party/github.com/Microsoft/TypeScript/lib/typescript' ;
23
- import { addImportToModule } from '../utility/ast-utils' ;
24
+ import { addImportToModule , addRouteDeclarationToModule } from '../utility/ast-utils' ;
24
25
import { InsertChange } from '../utility/change' ;
25
26
import { buildRelativePath , findModuleFromOptions } from '../utility/find-module' ;
26
27
import { applyLintFix } from '../utility/lint-fix' ;
27
28
import { parseName } from '../utility/parse-name' ;
28
29
import { createDefaultPath } from '../utility/workspace' ;
29
- import { Schema as ModuleOptions } from './schema' ;
30
+ import { RoutingScope , Schema as ModuleOptions } from './schema' ;
30
31
32
+ function buildRelativeModulePath ( options : ModuleOptions , modulePath : string ) : string {
33
+ const importModulePath = normalize (
34
+ `/${ options . path } /`
35
+ + ( options . flat ? '' : strings . dasherize ( options . name ) + '/' )
36
+ + strings . dasherize ( options . name )
37
+ + '.module' ,
38
+ ) ;
39
+
40
+ return buildRelativePath ( modulePath , importModulePath ) ;
41
+ }
31
42
32
43
function addDeclarationToNgModule ( options : ModuleOptions ) : Rule {
33
44
return ( host : Tree ) => {
@@ -41,16 +52,10 @@ function addDeclarationToNgModule(options: ModuleOptions): Rule {
41
52
if ( text === null ) {
42
53
throw new SchematicsException ( `File ${ modulePath } does not exist.` ) ;
43
54
}
44
- const sourceText = text . toString ( 'utf-8' ) ;
55
+ const sourceText = text . toString ( ) ;
45
56
const source = ts . createSourceFile ( modulePath , sourceText , ts . ScriptTarget . Latest , true ) ;
46
57
47
- const importModulePath = normalize (
48
- `/${ options . path } /`
49
- + ( options . flat ? '' : strings . dasherize ( options . name ) + '/' )
50
- + strings . dasherize ( options . name )
51
- + '.module' ,
52
- ) ;
53
- const relativePath = buildRelativePath ( modulePath , importModulePath ) ;
58
+ const relativePath = buildRelativeModulePath ( options , modulePath ) ;
54
59
const changes = addImportToModule ( source ,
55
60
modulePath ,
56
61
strings . classify ( `${ options . name } Module` ) ,
@@ -68,6 +73,66 @@ function addDeclarationToNgModule(options: ModuleOptions): Rule {
68
73
} ;
69
74
}
70
75
76
+ function addRouteDeclarationToNgModule (
77
+ options : ModuleOptions ,
78
+ routingModulePath : Path | undefined ,
79
+ ) : Rule {
80
+ return ( host : Tree ) => {
81
+ if ( ! options . route ) {
82
+ return host ;
83
+ }
84
+ if ( ! options . module ) {
85
+ throw new Error ( 'Module option required when creating a lazy loaded routing module.' ) ;
86
+ }
87
+
88
+ let path : string ;
89
+ if ( routingModulePath ) {
90
+ path = routingModulePath ;
91
+ } else {
92
+ path = options . module ;
93
+ }
94
+
95
+ const text = host . read ( path ) ;
96
+ if ( ! text ) {
97
+ throw new Error ( `Couldn't find the module nor its routing module.` ) ;
98
+ }
99
+
100
+ const sourceText = text . toString ( ) ;
101
+ const addDeclaration = addRouteDeclarationToModule (
102
+ ts . createSourceFile ( path , sourceText , ts . ScriptTarget . Latest , true ) ,
103
+ path ,
104
+ buildRoute ( options , options . module ) ,
105
+ ) as InsertChange ;
106
+
107
+ const recorder = host . beginUpdate ( path ) ;
108
+ recorder . insertLeft ( addDeclaration . pos , addDeclaration . toAdd ) ;
109
+ host . commitUpdate ( recorder ) ;
110
+
111
+ return host ;
112
+ } ;
113
+ }
114
+
115
+ function getRoutingModulePath ( host : Tree , options : ModuleOptions ) : Path | undefined {
116
+ let path : Path | undefined ;
117
+ const modulePath = options . module as string ;
118
+ const routingModuleName = modulePath . split ( '.' ) [ 0 ] + '-routing' ;
119
+ const { module, ...rest } = options ;
120
+
121
+ try {
122
+ path = findModuleFromOptions ( host , { module : routingModuleName , ...rest } ) ;
123
+ } catch { }
124
+
125
+ return path ;
126
+ }
127
+
128
+ function buildRoute ( options : ModuleOptions , modulePath : string ) {
129
+ const relativeModulePath = buildRelativeModulePath ( options , modulePath ) ;
130
+ const moduleName = `${ strings . classify ( options . name ) } Module` ;
131
+ const loadChildren = `() => import('${ relativeModulePath } ').then(m => m.${ moduleName } )` ;
132
+
133
+ return `{ path: '${ options . route } ', loadChildren: ${ loadChildren } }` ;
134
+ }
135
+
71
136
export default function ( options : ModuleOptions ) : Rule {
72
137
return async ( host : Tree ) => {
73
138
if ( options . path === undefined ) {
@@ -82,19 +147,41 @@ export default function (options: ModuleOptions): Rule {
82
147
options . name = parsedPath . name ;
83
148
options . path = parsedPath . path ;
84
149
150
+ let routingModulePath : Path | undefined ;
151
+ const isLazyLoadedModuleGen = options . route && options . module ;
152
+ if ( isLazyLoadedModuleGen ) {
153
+ options . routingScope = RoutingScope . Child ;
154
+ routingModulePath = getRoutingModulePath ( host , options ) ;
155
+ }
156
+
85
157
const templateSource = apply ( url ( './files' ) , [
86
- options . routing ? noop ( ) : filter ( path => ! path . endsWith ( '-routing.module.ts.template' ) ) ,
158
+ options . routing || isLazyLoadedModuleGen && ! ! routingModulePath
159
+ ? noop ( )
160
+ : filter ( path => ! path . endsWith ( '-routing.module.ts.template' ) ) ,
87
161
applyTemplates ( {
88
162
...strings ,
89
163
'if-flat' : ( s : string ) => options . flat ? '' : s ,
164
+ lazyRoute : isLazyLoadedModuleGen ,
165
+ lazyRouteWithoutRouteModule : isLazyLoadedModuleGen && ! routingModulePath ,
166
+ lazyRouteWithRouteModule : isLazyLoadedModuleGen && routingModulePath ,
90
167
...options ,
91
168
} ) ,
92
169
move ( parsedPath . path ) ,
93
170
] ) ;
171
+ const moduleDasherized = strings . dasherize ( options . name ) ;
172
+ const modulePath =
173
+ `${ ! options . flat ? moduleDasherized + '/' : '' } ${ moduleDasherized } .module.ts` ;
94
174
95
175
return chain ( [
96
- addDeclarationToNgModule ( options ) ,
176
+ ! isLazyLoadedModuleGen ? addDeclarationToNgModule ( options ) : noop ( ) ,
177
+ addRouteDeclarationToNgModule ( options , routingModulePath ) ,
97
178
mergeWith ( templateSource ) ,
179
+ isLazyLoadedModuleGen
180
+ ? schematic ( 'component' , {
181
+ ...options ,
182
+ module : modulePath ,
183
+ } )
184
+ : noop ( ) ,
98
185
options . lintFix ? applyLintFix ( options . path ) : noop ( ) ,
99
186
] ) ;
100
187
} ;
0 commit comments