@@ -2,6 +2,7 @@ import path from 'path';
22import * as ts from 'typescript' ;
33import { Graph , Meta , Node , OptionValues , Relation } from '../models' ;
44import { pipe , piped } from 'remeda' ;
5+ import { mergeGraph } from './utils' ;
56
67export function createGraph (
78 /**
@@ -30,90 +31,23 @@ export function createGraph(
3031 ) ;
3132 options . rootDir = rootDir ;
3233 const program = ts . createProgram ( fileNames , options ) ;
33- const nodes : Node [ ] = [ ] ;
34- const relations : Relation [ ] = [ ] ;
34+
3535 const bindWords_isFileNameMatchSomeWords =
3636 ( array : string [ ] ) => ( filename : string ) =>
3737 array . some ( word => filename . includes ( word ) ) ;
38-
3938 const isMatchSomeExclude = opt . exclude
4039 ? bindWords_isFileNameMatchSomeWords ( opt . exclude )
4140 : ( ) => false ;
4241 const isNotMatchSomeExclude = ( filename : string ) =>
4342 ! isMatchSomeExclude ( filename ) ;
44- function getFilePath ( sourceFile : ts . SourceFile ) {
45- return options . rootDir
46- ? sourceFile . fileName . replace ( options . rootDir + '/' , '' )
47- : sourceFile . fileName ;
48- }
4943
50- program
44+ const graphs = program
5145 . getSourceFiles ( )
52- . filter ( sourceFile => ! sourceFile . fileName . includes ( 'node_modules' ) )
53- . filter ( piped ( getFilePath , removeSlash , isNotMatchSomeExclude ) )
54- . forEach ( sourceFile => {
55- const filePath = pipe ( sourceFile , getFilePath , removeSlash ) ;
56- const fileName = getName ( filePath ) ;
57- const fromNode : Node = {
58- path : filePath ,
59- name : fileName ,
60- changeStatus : 'not_modified' ,
61- } ;
62- nodes . push ( fromNode ) ;
63-
64- ts . forEachChild ( sourceFile , node => {
65- const importPaths : ( string | undefined ) [ ] = [ ] ;
66- function getModuleNameText ( node : ts . Node ) {
67- if ( ts . isImportDeclaration ( node ) ) {
68- importPaths . push ( node . moduleSpecifier ?. getText ( sourceFile ) ) ;
69- } else if ( ts . isCallExpression ( node ) ) {
70- const text = node . getText ( sourceFile ) ;
71- if ( text . includes ( 'require' ) || text . includes ( 'import' ) ) {
72- importPaths . push ( node . arguments [ 0 ] ?. getText ( sourceFile ) ) ;
73- }
74- } else if ( ts . isExportDeclaration ( node ) ) {
75- importPaths . push ( node . moduleSpecifier ?. getText ( sourceFile ) ) ;
76- }
77- ts . forEachChild ( node , getModuleNameText ) ;
78- }
79- getModuleNameText ( node ) ;
46+ . filter ( sourceFile => ! sourceFile . fileName . includes ( 'node_modules' ) ) // node_modules 配下のファイルは除外
47+ . filter ( piped ( getFilePath ( options ) , removeSlash , isNotMatchSomeExclude ) )
48+ . map ( analyzeSoucreFile ( options ) ) ;
8049
81- importPaths . forEach ( moduleNameText => {
82- if ( ! moduleNameText ) return ;
83- const moduleName = moduleNameText . slice ( 1 , moduleNameText . length - 1 ) ; // import 文のクォート及びダブルクォートを除去
84- const moduleFileFullName =
85- ts . resolveModuleName (
86- moduleName ,
87- sourceFile . fileName ,
88- options ,
89- ts . sys ,
90- ) . resolvedModule ?. resolvedFileName ?? '' ;
91- const moduleFilePath = removeSlash (
92- options . rootDir
93- ? moduleFileFullName . replace ( options . rootDir , '' )
94- : moduleFileFullName ,
95- ) ;
96- if ( ! moduleFilePath ) return ;
97- const toNode : Node = {
98- path : moduleFilePath ,
99- name : getName ( moduleFilePath ) ,
100- changeStatus : 'not_modified' ,
101- } ;
102- if ( ! findNode ( nodes , moduleFilePath ) ) {
103- nodes . push ( toNode ) ;
104- }
105- relations . push ( {
106- kind : 'depends_on' ,
107- from : fromNode ,
108- to : toNode ,
109- fullText : node . getChildAt ( 1 , sourceFile ) ?. getText ( sourceFile ) ?? '' ,
110- changeStatus : 'not_modified' ,
111- } ) ;
112- } ) ;
113- } ) ;
114- } ) ;
115-
116- return { graph : { nodes, relations } , meta : { rootDir } } ;
50+ return { graph : mergeGraph ( ...graphs ) , meta : { rootDir } } ;
11751}
11852
11953function getName ( filePath : string ) {
@@ -141,3 +75,93 @@ function findNode(nodes: Node[], filePath: string): Node | undefined {
14175function removeSlash ( pathName : string ) : string {
14276 return pathName . startsWith ( '/' ) ? pathName . replace ( '/' , '' ) : pathName ;
14377}
78+
79+ function getFilePath (
80+ options : ts . CompilerOptions ,
81+ ) : ( sourceFile : ts . SourceFile ) => string {
82+ return ( sourceFile : ts . SourceFile ) =>
83+ options . rootDir
84+ ? sourceFile . fileName . replace ( options . rootDir + '/' , '' )
85+ : sourceFile . fileName ;
86+ }
87+
88+ function analyzeSoucreFile (
89+ options : ts . CompilerOptions ,
90+ ) : ( sourceFile : ts . SourceFile ) => Graph {
91+ return ( sourceFile : ts . SourceFile ) => {
92+ const nodes : Node [ ] = [ ] ;
93+ const relations : Relation [ ] = [ ] ;
94+ const filePath = pipe ( sourceFile , getFilePath ( options ) , removeSlash ) ;
95+ const fileName = getName ( filePath ) ;
96+ const fromNode : Node = {
97+ path : filePath ,
98+ name : fileName ,
99+ changeStatus : 'not_modified' ,
100+ } ;
101+ nodes . push ( fromNode ) ;
102+
103+ ts . forEachChild ( sourceFile , node => {
104+ const importPaths : ( string | undefined ) [ ] = [ ] ;
105+ function getModuleNameText ( node : ts . Node ) {
106+ if ( ts . isImportDeclaration ( node ) ) {
107+ console . log (
108+ 'isImportDeclaration' ,
109+ node . moduleSpecifier ?. getText ( sourceFile ) ,
110+ ) ;
111+ importPaths . push ( node . moduleSpecifier ?. getText ( sourceFile ) ) ;
112+ } else if ( ts . isCallExpression ( node ) ) {
113+ const text = node . getText ( sourceFile ) ;
114+ if ( text . includes ( 'require' ) || text . includes ( 'import' ) ) {
115+ importPaths . push ( node . arguments [ 0 ] ?. getText ( sourceFile ) ) ;
116+ }
117+ } else if ( ts . isExportDeclaration ( node ) ) {
118+ importPaths . push ( node . moduleSpecifier ?. getText ( sourceFile ) ) ;
119+ }
120+ ts . forEachChild ( node , getModuleNameText ) ;
121+ }
122+ getModuleNameText ( node ) ;
123+ console . log ( importPaths ) ;
124+
125+ importPaths . forEach ( moduleNameText => {
126+ if ( ! moduleNameText ) {
127+ console . log ( 'moduleNameText is empty' ) ;
128+ return ;
129+ }
130+ const moduleName = moduleNameText . slice ( 1 , moduleNameText . length - 1 ) ; // import 文のクォート及びダブルクォートを除去
131+ console . log (
132+ 'ts.resolveModuleName(moduleName, sourceFile.fileName, options, ts.sys).resolvedModule?.resolvedFileName = ' ,
133+ ts . resolveModuleName ( moduleName , sourceFile . fileName , options , ts . sys )
134+ . resolvedModule ?. resolvedFileName ,
135+ ) ;
136+ const moduleFileFullName =
137+ ts . resolveModuleName ( moduleName , sourceFile . fileName , options , ts . sys )
138+ . resolvedModule ?. resolvedFileName ?? '' ;
139+ const moduleFilePath = removeSlash (
140+ options . rootDir
141+ ? moduleFileFullName . replace ( options . rootDir , '' )
142+ : moduleFileFullName ,
143+ ) ;
144+ if ( ! moduleFilePath ) {
145+ console . log ( 'moduleFilePath is empty' ) ;
146+ return ;
147+ }
148+ const toNode : Node = {
149+ path : moduleFilePath ,
150+ name : getName ( moduleFilePath ) ,
151+ changeStatus : 'not_modified' ,
152+ } ;
153+ if ( ! findNode ( nodes , moduleFilePath ) ) {
154+ nodes . push ( toNode ) ;
155+ }
156+ relations . push ( {
157+ kind : 'depends_on' ,
158+ from : fromNode ,
159+ to : toNode ,
160+ fullText : node . getChildAt ( 1 , sourceFile ) ?. getText ( sourceFile ) ?? '' ,
161+ changeStatus : 'not_modified' ,
162+ } ) ;
163+ } ) ;
164+ } ) ;
165+ return { nodes, relations } ;
166+ } ;
167+ }
0 commit comments