11import * as ts from 'typescript' ;
2+ import * as fs from 'fs' ;
23import { InsertChange } from './change' ;
34
5+ /**
6+ * Get TS source file based on path.
7+ * @param filePath
8+ * @return source file of ts.SourceFile kind
9+ */
10+ export function getSource ( filePath : string ) : ts . SourceFile {
11+ return ts . createSourceFile ( filePath , fs . readFileSync ( filePath ) . toString ( ) ,
12+ ts . ScriptTarget . ES6 , true ) ;
13+ }
14+
415/**
516* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
617* @param node
718* @param kind
8- * @return all nodes of kind kind , or [] if none is found
19+ * @return all nodes of kind, or [] if none is found
920*/
1021export function findNodes ( node : ts . Node , kind : ts . SyntaxKind ) : ts . Node [ ] {
1122 if ( ! node ) {
@@ -19,6 +30,26 @@ export function findNodes(node: ts.Node, kind: ts.SyntaxKind): ts.Node[] {
1930 foundNodes . concat ( findNodes ( child , kind ) ) , arr ) ;
2031}
2132
33+ /**
34+ * Find all nodes from the AST in the subtree based on text.
35+ * @param node
36+ * @param text
37+ * @return all nodes of text, or [] if none is found
38+ */
39+ export function findNodesByText ( node : ts . Node , text : string ) : ts . Node [ ] {
40+ if ( ! node ) {
41+ return [ ] ;
42+ }
43+ let arr : ts . Node [ ] = [ ] ;
44+ if ( node . getText ( ) === text ) {
45+ arr . push ( node ) ;
46+ }
47+
48+ return node . getChildren ( ) . reduce ( ( foundNodes , child ) => {
49+ return foundNodes . concat ( findNodesByText ( child , text ) ) ;
50+ } , arr ) ;
51+ }
52+
2253/**
2354 * Helper for sorting nodes.
2455 * @return function to sort nodes in increasing order of position in sourceFile
@@ -52,3 +83,40 @@ export function insertAfterLastOccurrence(nodes: ts.Node[], toInsert: string,
5283 let lastItemPosition : number = lastItem ? lastItem . end : fallbackPos ;
5384 return new InsertChange ( file , lastItemPosition , toInsert ) ;
5485}
86+
87+ /**
88+ * Custom function to insert component (component, pipe, directive)
89+ * into NgModule declarations. It also imports the component.
90+ * @param modulePath
91+ * @param classifiedName
92+ * @param importPath
93+ * @return Promise
94+ */
95+ export function importComponent ( modulePath : string , classifiedName : string ,
96+ importPath : string ) : Promise < void > {
97+ let source : ts . SourceFile = this . getSource ( modulePath ) ;
98+
99+ let importNode : ts . Node =
100+ this . findNodesByText ( source , 'import' ) . pop ( ) ;
101+ let iPos : ts . LineAndCharacter =
102+ source . getLineAndCharacterOfPosition ( importNode . getEnd ( ) ) ;
103+ let iLine : number = iPos . line + 1 ;
104+ let iStart : number = source . getPositionOfLineAndCharacter ( iLine , 0 ) ;
105+ let iStr : string = `import { ${ classifiedName } } from ${ importPath } \n` ;
106+ let changeImport : InsertChange = new InsertChange ( modulePath , iStart , iStr ) ;
107+
108+ return changeImport . apply ( ) . then ( ( ) => {
109+ source = this . getSource ( modulePath ) ;
110+ let declarationsNode : ts . Node =
111+ this . findNodesByText ( source , 'declarations' ) . shift ( ) ;
112+ let dPos : ts . LineAndCharacter =
113+ source . getLineAndCharacterOfPosition ( declarationsNode . getEnd ( ) ) ;
114+ let dStart : number =
115+ source . getPositionOfLineAndCharacter ( dPos . line + 1 , - 1 ) ;
116+ let dStr : string = `\n ${ classifiedName } ,` ;
117+ let changeDeclarations : InsertChange = new InsertChange ( modulePath , dStart , dStr ) ;
118+
119+ return changeDeclarations . apply ( ) ;
120+ } ) ;
121+ }
122+
0 commit comments