1- import type { Path } from '@angular-devkit/core' ;
2- import { join , normalize , strings } from '@angular-devkit/core' ;
3- import type { DirEntry , Rule , Tree } from '@angular-devkit/schematics' ;
1+ import { strings } from '@angular-devkit/core' ;
2+ import type { Rule , Tree } from '@angular-devkit/schematics' ;
43import {
54 SchematicsException ,
65 apply ,
@@ -13,160 +12,15 @@ import {
1312 template ,
1413 url ,
1514} from '@angular-devkit/schematics' ;
16- import type { ModuleOptions } from '@schematics/angular/utility/find-module' ;
17- import { buildRelativePath } from '@schematics/angular/utility/find-module' ;
1815import { parseName } from '@schematics/angular/utility/parse-name' ;
1916import { validateHtmlSelector } from '@schematics/angular/utility/validation' ;
2017import { buildDefaultPath , getWorkspace } from '@schematics/angular/utility/workspace' ;
21- import * as ts from 'typescript' ;
2218
2319import { buildSelector } from '../util' ;
24- import { findNodes } from '../util/ast-util' ;
25- import type { Change } from '../util/change' ;
26- import { InsertChange } from '../util/change' ;
2720
21+ import { addRoute , addRouteToNgModule , findRoutingModuleFromOptions } from './route-utils' ;
2822import type { Schema as PageOptions } from './schema' ;
2923
30- function findRoutingModuleFromOptions ( host : Tree , options : ModuleOptions ) : Path | undefined {
31- // eslint-disable-next-line no-prototype-builtins
32- if ( options . hasOwnProperty ( 'skipImport' ) && options . skipImport ) {
33- return undefined ;
34- }
35-
36- if ( ! options . module ) {
37- const pathToCheck = ( options . path || '' ) + ( options . flat ? '' : '/' + strings . dasherize ( options . name ) ) ;
38-
39- return normalize ( findRoutingModule ( host , pathToCheck ) ) ;
40- } else {
41- const modulePath = normalize ( '/' + options . path + '/' + options . module ) ;
42- const moduleBaseName = normalize ( modulePath ) . split ( '/' ) . pop ( ) ;
43-
44- if ( host . exists ( modulePath ) ) {
45- return normalize ( modulePath ) ;
46- } else if ( host . exists ( modulePath + '.ts' ) ) {
47- return normalize ( modulePath + '.ts' ) ;
48- } else if ( host . exists ( modulePath + '.module.ts' ) ) {
49- return normalize ( modulePath + '.module.ts' ) ;
50- } else if ( host . exists ( modulePath + '/' + moduleBaseName + '.module.ts' ) ) {
51- return normalize ( modulePath + '/' + moduleBaseName + '.module.ts' ) ;
52- } else {
53- throw new Error ( 'Specified module does not exist' ) ;
54- }
55- }
56- }
57-
58- function findRoutingModule ( host : Tree , generateDir : string ) : Path {
59- let dir : DirEntry | null = host . getDir ( '/' + generateDir ) ;
60-
61- const routingModuleRe = / - r o u t i n g \. m o d u l e \. t s / ;
62-
63- while ( dir ) {
64- const matches = dir . subfiles . filter ( ( p ) => routingModuleRe . test ( p ) ) ;
65-
66- if ( matches . length === 1 ) {
67- return join ( dir . path , matches [ 0 ] ) ;
68- } else if ( matches . length > 1 ) {
69- throw new Error (
70- 'More than one module matches. Use skip-import option to skip importing ' +
71- 'the component into the closest module.'
72- ) ;
73- }
74-
75- dir = dir . parent ;
76- }
77-
78- throw new Error ( 'Could not find an NgModule. Use the skip-import ' + 'option to skip importing in NgModule.' ) ;
79- }
80-
81- function addRouteToNgModule ( options : PageOptions ) : Rule {
82- const { module } = options ;
83-
84- if ( ! module ) {
85- throw new SchematicsException ( 'module option is required.' ) ;
86- }
87-
88- return ( host ) => {
89- const text = host . read ( module ) ;
90-
91- if ( ! text ) {
92- throw new SchematicsException ( `File ${ module } does not exist.` ) ;
93- }
94-
95- const sourceText = text . toString ( 'utf8' ) ;
96- const source = ts . createSourceFile ( module , sourceText , ts . ScriptTarget . Latest , true ) ;
97-
98- const pagePath =
99- `/${ options . path } /` +
100- ( options . flat ? '' : `${ strings . dasherize ( options . name ) } /` ) +
101- `${ strings . dasherize ( options . name ) } .module` ;
102-
103- const relativePath = buildRelativePath ( module , pagePath ) ;
104-
105- const routePath = strings . dasherize ( options . routePath ? options . routePath : options . name ) ;
106- const ngModuleName = `${ strings . classify ( options . name ) } PageModule` ;
107- const changes = addRouteToRoutesArray ( source , module , routePath , relativePath , ngModuleName ) ;
108- const recorder = host . beginUpdate ( module ) ;
109-
110- for ( const change of changes ) {
111- if ( change instanceof InsertChange ) {
112- recorder . insertLeft ( change . pos , change . toAdd ) ;
113- }
114- }
115-
116- host . commitUpdate ( recorder ) ;
117-
118- return host ;
119- } ;
120- }
121-
122- function addRouteToRoutesArray (
123- source : ts . SourceFile ,
124- ngModulePath : string ,
125- routePath : string ,
126- routeLoadChildren : string ,
127- ngModuleName : string
128- ) : Change [ ] {
129- const keywords = findNodes ( source , ts . SyntaxKind . VariableStatement ) ;
130-
131- for ( const keyword of keywords ) {
132- if ( ts . isVariableStatement ( keyword ) ) {
133- const [ declaration ] = keyword . declarationList . declarations ;
134-
135- if ( ts . isVariableDeclaration ( declaration ) && declaration . initializer && declaration . name . getText ( ) === 'routes' ) {
136- const node = declaration . initializer . getChildAt ( 1 ) ;
137- const lastRouteNode = node . getLastToken ( ) ;
138-
139- if ( ! lastRouteNode ) {
140- return [ ] ;
141- }
142-
143- const changes : Change [ ] = [ ] ;
144- let trailingCommaFound = false ;
145-
146- if ( lastRouteNode . kind === ts . SyntaxKind . CommaToken ) {
147- trailingCommaFound = true ;
148- } else {
149- changes . push ( new InsertChange ( ngModulePath , lastRouteNode . getEnd ( ) , ',' ) ) ;
150- }
151-
152- changes . push (
153- new InsertChange (
154- ngModulePath ,
155- lastRouteNode . getEnd ( ) + 1 ,
156- ` {\n path: '${ routePath } ',\n loadChildren: () => import('${ routeLoadChildren } ').then( m => m.${ ngModuleName } )\n }${
157- trailingCommaFound ? ',' : ''
158- } \n`
159- )
160- ) ;
161-
162- return changes ;
163- }
164- }
165- }
166-
167- return [ ] ;
168- }
169-
17024export default function ( options : PageOptions ) : Rule {
17125 return async ( host : Tree ) => {
17226 if ( ! options . project ) {
@@ -179,7 +33,9 @@ export default function (options: PageOptions): Rule {
17933 options . path = buildDefaultPath ( project ) ;
18034 }
18135
182- options . module = findRoutingModuleFromOptions ( host , options ) ;
36+ if ( ! options . standalone ) {
37+ options . module = findRoutingModuleFromOptions ( host , options ) ;
38+ }
18339
18440 const parsedPath = parseName ( options . path as string , options . name ) ;
18541 options . name = parsedPath . name ;
@@ -190,6 +46,7 @@ export default function (options: PageOptions): Rule {
19046
19147 const templateSource = apply ( url ( './files' ) , [
19248 options . spec ? noop ( ) : filter ( ( p ) => ! p . endsWith ( '.spec.ts' ) ) ,
49+ options . standalone ? filter ( ( p ) => ! p . endsWith ( 'module.ts' ) ) : noop ( ) ,
19350 template ( {
19451 ...strings ,
19552 'if-flat' : ( s : string ) => ( options . flat ? '' : s ) ,
@@ -198,6 +55,10 @@ export default function (options: PageOptions): Rule {
19855 move ( parsedPath . path ) ,
19956 ] ) ;
20057
201- return chain ( [ branchAndMerge ( chain ( [ addRouteToNgModule ( options ) , mergeWith ( templateSource ) ] ) ) ] ) ;
58+ return chain ( [
59+ branchAndMerge (
60+ chain ( [ options . standalone ? addRoute ( options ) : addRouteToNgModule ( options ) , mergeWith ( templateSource ) ] )
61+ ) ,
62+ ] ) ;
20263 } ;
20364}
0 commit comments