1
+ import * as fs from 'fs' ;
2
+ import * as vscode from 'vscode' ;
3
+ import * as path from 'path' ;
4
+ import { ArrayUtils , Config , FileSystemUtils } from '@src' ;
5
+
6
+ export interface INgModule {
7
+ imports : string [ ] ;
8
+ exports : string [ ] ;
9
+ declarations : string [ ] ;
10
+ entryComponents : string [ ] ;
11
+ providers : string [ ] ;
12
+ bootstrap : string [ ] ;
13
+ }
14
+
15
+ export class NgModule implements INgModule {
16
+ constructor ( private data : INgModule ) {
17
+ this . imports = data . imports ;
18
+ this . exports = data . exports ;
19
+ this . declarations = data . declarations ;
20
+ this . entryComponents = data . entryComponents ;
21
+ this . providers = data . providers ;
22
+ this . bootstrap = data . bootstrap ;
23
+ }
24
+ public imports : string [ ] = [ ] ;
25
+ public exports : string [ ] = [ ] ;
26
+ public declarations : string [ ] = [ ] ;
27
+ public entryComponents : string [ ] = [ ] ;
28
+ public providers : string [ ] = [ ] ;
29
+ public bootstrap : string [ ] = [ ] ;
30
+ public filename : string = '' ;
31
+ public moduleName : string = '' ;
32
+ public moduleContents : string = '' ;
33
+ public moduleStats ( ) : number [ ] {
34
+ return [
35
+ this . declarations === undefined ? 0 : ArrayUtils . arrayLength ( this . declarations ) ,
36
+ this . imports === undefined ? 0 : ArrayUtils . arrayLength ( this . imports ) ,
37
+ this . exports === undefined ? 0 : ArrayUtils . arrayLength ( this . exports ) ,
38
+ this . bootstrap === undefined ? 0 : ArrayUtils . arrayLength ( this . bootstrap ) ,
39
+ this . providers === undefined ? 0 : ArrayUtils . arrayLength ( this . providers ) ,
40
+ this . entryComponents === undefined ? 0 : ArrayUtils . arrayLength ( this . entryComponents ) ,
41
+ ] ;
42
+ }
43
+ }
44
+
45
+ export class ModulesToMarkdown {
46
+ private config = new Config ( ) ;
47
+ public static get commandName ( ) : string { return 'modulesToMarkdown' ; }
48
+
49
+ public execute ( ) {
50
+ const fsUtils = new FileSystemUtils ( ) ;
51
+ var workspaceDirectory : string = fsUtils . getWorkspaceFolder ( ) ;
52
+ const filenames = fsUtils . listFiles ( workspaceDirectory , this . config . excludeDirectories , this . isTypescriptFile ) ;
53
+ let markdownContent = '# Modules\n\n' ;
54
+ const errors : string [ ] = [ ] ;
55
+ const modules : NgModule [ ] = [ ] ;
56
+ filenames . sort ( ArrayUtils . sortStrings ) . forEach ( filename => {
57
+ const module = this . readModule ( filename , errors ) ;
58
+ if ( module !== undefined ) {
59
+ modules . push ( module ) ;
60
+ }
61
+ } ) ;
62
+ markdownContent = markdownContent +
63
+ '## Modules in workspace\n\n' +
64
+ '| Module | Declarations | Imports | Exports | Bootstrap | Providers | Entry points |\n' +
65
+ '| ---| --- | --- | --- | --- | --- | --- |\n' ;
66
+ let modulesMarkdown : string = '' ;
67
+ modules . forEach ( module => {
68
+ markdownContent = markdownContent + '| ' + module . moduleName + ' | ' + module . moduleStats ( ) . join ( ' | ' ) + ' |\n' ;
69
+ modulesMarkdown = modulesMarkdown + this . generateModuleMarkdown ( module ) ;
70
+ } ) ;
71
+ markdownContent = markdownContent + '\n' + modulesMarkdown ;
72
+ if ( errors . length > 0 ) {
73
+ this . showErrors ( errors ) ;
74
+ }
75
+ fsUtils . writeFileAndOpen ( path . join ( workspaceDirectory , this . config . modulesToMarkdownFilename ) , markdownContent ) ;
76
+ }
77
+
78
+ private isTypescriptFile ( filename : string ) : boolean {
79
+ return filename . endsWith ( '.ts' ) && ! filename . endsWith ( 'index.ts' ) ;
80
+ }
81
+
82
+ private readModule ( filename : string , errors : string [ ] ) : NgModule | undefined {
83
+ const fileContents = fs . readFileSync ( filename ) ;
84
+ const regex : RegExp = / @ N g M o d u l e \s * \( \s * ( \{ .+ ?\} ) \s * \) \s * e x p o r t \s + c l a s s \s + ( \w + ) \s * \{ / ims;
85
+ var match = regex . exec ( fileContents . toString ( ) ) ;
86
+ if ( match !== null ) {
87
+ const moduleName = match [ 2 ] ;
88
+ const moduleContents = this . convertNgModuleToParsableJson ( match [ 1 ] ) ;
89
+ try {
90
+ const module : NgModule = new NgModule ( JSON . parse ( moduleContents ) ) ;
91
+ module . filename = filename ;
92
+ module . moduleName = moduleName ;
93
+ module . moduleContents = moduleContents ;
94
+ return module ;
95
+ } catch ( ex ) {
96
+ errors . push ( `ModuleName: ${ moduleName } \nFilename: ${ filename } \nException: ${ ex } \n${ match [ 1 ] } \n` ) ;
97
+ return undefined ;
98
+ }
99
+ }
100
+ }
101
+
102
+ private convertNgModuleToParsableJson ( moduleContents : string ) : string {
103
+ moduleContents = moduleContents . replace ( / \s * ?\/ \/ .* $ / igm, ( ) => '' ) ; // Remove comments
104
+ moduleContents = moduleContents . replace ( / \{ \s * p r o v i d e : \s * ( .+ ?) \s * , \s * u s e \w + : \s * ( .+ ?) \s * ( , \s .* ?) * \s * ?\} [ \s \} ] * / igms, ( str , provided , provider ) => `"${ provided . replace ( / [ ' " ] / gms, '' ) } provided by ${ provider . replace ( / [ \{ \} ' ] / igms, '' ) . replace ( ':' , '=' ) } "` ) ; // format providers ;
105
+ moduleContents = moduleContents . replace ( "'" , "\"" ) ; // Single quotes to double-quotes
106
+ moduleContents = moduleContents . replace ( / \s * ?( \w + ) [ , \r \n ] \s * ?/ igms, ( str , identifier ) => `"${ identifier } ",` ) ; // quotes around array items
107
+ moduleContents = moduleContents . replace ( / ( \w + \. \w + \( \) ) [ , \r \n ] / igms, ( str , identifier ) => `"${ identifier } ",` ) ; // quotes around array items
108
+ moduleContents = moduleContents . replace ( / \[ \s * ( [ \w _ \( \) \. ] + ?) \s * \] / igms, ( str , identifier ) => `"${ identifier } "` ) ; // quotes around array items
109
+ moduleContents = moduleContents . replace ( / ( \w + \. \w + \( ) .* ?( \) ) [ , \r \n ] / igms, ( str , identifier , idEnd ) => `"${ identifier } ...${ idEnd } ",` ) ; // quotes around array items
110
+ moduleContents = moduleContents . replace ( / ( " \s * ) , ( \s + \] ) / igms, ( str , quote , arrayEnd ) => quote + arrayEnd ) ; // Remove illegal empty array ending
111
+ moduleContents = moduleContents . replace ( / ( \w + ) \s * : / g, ( str , identifier ) => `"${ identifier } ":` ) ; // quotes around identifiers
112
+ return moduleContents ;
113
+ }
114
+
115
+ private generateModuleMarkdown ( module : NgModule ) : string {
116
+ let markdown = `## ${ module . moduleName } \n\n` ;
117
+ markdown = markdown +
118
+ 'Filename: ' + module . filename + '\n\n' +
119
+ '| Section | Classes, service, modules |\n' +
120
+ '| ---- |:-----------|\n' +
121
+ '| Declarations | ' + ArrayUtils . arrayToMarkdown ( module . declarations ) + ' |\n' +
122
+ '| Imports | ' + ArrayUtils . arrayToMarkdown ( module . imports ) + ' |\n' +
123
+ '| Exports | ' + ArrayUtils . arrayToMarkdown ( module . exports ) + ' |\n' +
124
+ '| Bootstrap | ' + ArrayUtils . arrayToMarkdown ( module . bootstrap ) + ' |\n' +
125
+ '| Providers | ' + ArrayUtils . arrayToMarkdown ( module . providers ) + ' |\n' +
126
+ '| Entry components | ' + ArrayUtils . arrayToMarkdown ( module . entryComponents ) + ' |\n' +
127
+ '\n' ;
128
+
129
+ return markdown ;
130
+ }
131
+
132
+ private showErrors ( errors : string [ ] ) {
133
+ const angularToolsOutput = vscode . window . createOutputChannel ( this . config . angularToolsOutputChannel ) ;
134
+ angularToolsOutput . clear ( ) ;
135
+ angularToolsOutput . appendLine ( `Parsing of ${ errors . length > 1 ? 'some' : 'one' } of the modules failed.\n` ) ;
136
+ angularToolsOutput . appendLine ( 'Below is a list of the errors.' ) ;
137
+ angularToolsOutput . appendLine ( errors . join ( '\n' ) ) ;
138
+ angularToolsOutput . show ( ) ;
139
+ }
140
+ }
0 commit comments