11import * as fs from 'fs' ;
22import path = require( 'path' ) ;
33
4- import { Config , FileSystemUtils } from '@src' ;
4+ import { Config , FileSystemUtils , StringUtils } from '@src' ;
55import { Component } from '@model' ;
66
77export class ComponentManager {
88 private static componentRegex = / @ C o m p o n e n t \( { / ig;
9+ private static componentClassNameRegex = / e x p o r t \s + c l a s s \s + ( .* ?) \s + / ims;
910 private static templateUrlRegex = / .* t e m p l a t e U r l : .+ \/ ( .+ ) ' / i;
1011 private static selectorRegex = / .* s e l e c t o r : .+ ' ( .+ ) ' / i;
1112 private static endBracketRegex = / } \) / i;
1213 private static routerOutletRegex = / < r o u t e r - o u t l e t .* ?> .* ?< \/ r o u t e r - o u t l e t > / ims;
1314
15+ private static routesRegex = / : \s * ?R o u t e s \s * ?= \s * ?\[ ( .* ?) \] / ims;
16+ private static loadChildrenRegex = / l o a d C h i l d r e n : .* ?t h e n \s * \( .+ ?= > .+ ?\. ( .+ ?) \) / i;
17+ private static routeComponentRegex = / c o m p o n e n t : \s * ?( \w + ?) \b / ig;
18+ private static childrenRegex = / c h i l d r e n \s * ?: \s * ?\[ ( .* ?) \] / ims;
19+
20+
1421 public static scanWorkspaceForComponents ( directoryPath : string ) : { [ selector : string ] : Component ; } {
15- const fsUtils = new FileSystemUtils ( ) ;
1622 const config = new Config ( ) ;
17- const componentFilenames = fsUtils . listFiles ( directoryPath , config . excludeDirectories , ComponentManager . isComponentFile ) ;
23+ const fsUtils = new FileSystemUtils ( ) ;
24+ const componentOrModuleFilenames = fsUtils . listFiles ( directoryPath , config . excludeDirectories , this . isComponentOrModuleFile ) ;
25+ const componentFilenames = componentOrModuleFilenames . filter ( FileSystemUtils . isComponentFile ) ;
1826 const components = ComponentManager . scanComponents ( componentFilenames ) ;
1927 ComponentManager . enrichComponentsFromComponentTemplates ( components ) ;
28+ const moduleFilenames = componentOrModuleFilenames . filter ( FileSystemUtils . isModuleFile ) ;
29+ ComponentManager . enrichComponentsFromModules ( moduleFilenames , components ) ;
2030 return components ;
2131 }
2232
23- private static isComponentFile ( filename : string ) : boolean {
24- return filename . endsWith ( '.component.ts' ) ;
33+ private static isComponentOrModuleFile ( filename : string ) : boolean {
34+ return FileSystemUtils . isComponentFile ( filename ) || FileSystemUtils . isModuleFile ( filename ) ;
2535 }
2636
2737 private static scanComponents ( componentFilenames : string [ ] ) : { [ selector : string ] : Component ; } {
@@ -55,6 +65,10 @@ export class ComponentManager {
5565 }
5666 }
5767 }
68+ const componentClassNameMatch = this . componentClassNameRegex . exec ( content ) ;
69+ if ( componentClassNameMatch !== null ) {
70+ currentComponent . name = componentClassNameMatch [ 1 ] ;
71+ }
5872 compHash [ currentComponent . selector ] = currentComponent ;
5973 } ) ;
6074 return compHash ;
@@ -91,4 +105,58 @@ export class ComponentManager {
91105 const match = this . routerOutletRegex . exec ( template . toString ( ) ) ;
92106 return match !== null ;
93107 }
108+
109+ private static enrichComponentsFromModules ( moduleFilenames : string [ ] , componentHash : { [ selector : string ] : Component ; } ) {
110+ moduleFilenames . forEach ( ( moduleFilename ) => {
111+ const moduleContent = fs . readFileSync ( moduleFilename ) ;
112+ const match = this . routesRegex . exec ( moduleContent . toString ( ) ) ;
113+ if ( match !== null ) {
114+ let routesBody = match [ 1 ] ;
115+ this . parseRoutesBody ( routesBody , moduleFilename , componentHash ) ;
116+ }
117+ } ) ;
118+ }
119+
120+ private static parseRoutesBody ( routesBody : string , moduleFilename : string , componentDict : { [ selector : string ] : Component ; } ) {
121+ routesBody = StringUtils . removeComments ( routesBody ) ;
122+ const routesBodyParts = routesBody . split ( "," ) ;
123+ // We assume that the routing module has a corresponding module with the same name
124+ // This only works if the routing module is named like 'moduleComponentName'-routing.module.ts
125+ if ( ! FileSystemUtils . isRoutingModuleFile ( moduleFilename ) ) {
126+ return ;
127+ }
128+ const moduleComponentFilename = moduleFilename . replace ( FileSystemUtils . routingModuleFileExtension , FileSystemUtils . componentFileExtension ) ;
129+ const componentDictKey = Object . keys ( componentDict ) . find ( key => componentDict [ key ] . filename . endsWith ( moduleComponentFilename ) ) ;
130+ // if we didn't find the corresponding component we stop because we would not be able to link the components found in the routes to the current module component
131+ if ( componentDictKey === undefined ) {
132+ return ;
133+ }
134+ const moduleComponent = componentDict [ componentDictKey ] ;
135+ routesBodyParts . forEach ( ( routesBodyPart ) => {
136+ const componentMatch = this . routeComponentRegex . exec ( routesBodyPart ) ;
137+ if ( componentMatch !== null ) {
138+ const componentName = componentMatch [ 1 ] ;
139+ const componentSelector = Object . keys ( componentDict ) . find ( key => componentDict [ key ] . name === componentName ) ;
140+ if ( componentSelector !== undefined ) {
141+ const component = componentDict [ componentSelector ] ;
142+ if ( component !== undefined && componentSelector !== moduleComponent . selector ) {
143+ component . componentsRoutingToThis . push ( moduleComponent ) ;
144+ }
145+ }
146+ }
147+ else {
148+ const loadChildrenMatch = this . loadChildrenRegex . exec ( routesBodyPart ) ;
149+ if ( loadChildrenMatch !== null ) {
150+ const moduleName = loadChildrenMatch [ 1 ] ;
151+ console . log ( `${ moduleComponent . name } routing to module ${ moduleName } ` ) ;
152+ }
153+ }
154+ const childrenMatch = this . childrenRegex . exec ( routesBodyPart ) ;
155+ if ( childrenMatch !== null ) {
156+ const childrenRoutesBody = childrenMatch [ 1 ] ;
157+ this . parseRoutesBody ( childrenRoutesBody , moduleFilename , componentDict ) ;
158+ }
159+ } ) ;
160+
161+ }
94162}
0 commit comments