@@ -5,6 +5,7 @@ import type { CodegenLogger } from "@root/utils/codegen-logger";
55
66export type FileSystemWriterOptions = {
77 outputDir : string ;
8+ inMemoryOnly ?: boolean ;
89 logger ?: CodegenLogger ;
910} ;
1011
@@ -15,13 +16,14 @@ export type WriterOptions = FileSystemWriterOptions & {
1516 generateProfile ?: boolean ;
1617} ;
1718
18- export type PartialBy < T , K extends keyof T > = Omit < T , K > & Partial < Pick < T , K > > ;
19+ type FileBufferInternal = { relPath : string ; absPath : string ; tokens : string [ ] } ;
20+ export type FileBuffer = { relPath : string ; absPath : string ; content : string } ;
1921
2022export abstract class FileSystemWriter < T extends FileSystemWriterOptions = FileSystemWriterOptions > {
2123 opts : T ;
2224 currentDir ?: string ;
23- currentFileDescriptor ?: number ;
24- writtenFilesSet : Set < string > = new Set ( ) ;
25+ currentFile ?: { relPath : string ; descriptor : number } ;
26+ writtenFilesBuffer : Record < string , FileBufferInternal > = { } ;
2527
2628 constructor ( opts : T ) {
2729 this . opts = opts ;
@@ -36,48 +38,76 @@ export abstract class FileSystemWriter<T extends FileSystemWriterOptions = FileS
3638 return this . opts . logger ;
3739 }
3840
41+ onDiskMkDir ( path : string ) {
42+ if ( this . opts . inMemoryOnly ) return ;
43+ if ( ! fs . existsSync ( path ) ) {
44+ fs . mkdirSync ( path , { recursive : true } ) ;
45+ }
46+ }
47+
48+ onDiskOpenFile ( relPath : string ) : number {
49+ if ( this . opts . inMemoryOnly ) return - 1 ;
50+ return fs . openSync ( relPath , "w" ) ;
51+ }
52+
53+ onDiskCloseFile ( descriptor : number ) {
54+ if ( this . opts . inMemoryOnly ) return ;
55+ fs . fsyncSync ( descriptor ) ;
56+ fs . closeSync ( descriptor ) ;
57+ }
58+
59+ onDiskWrite ( descriptor : number , token : string ) {
60+ if ( this . opts . inMemoryOnly ) return ;
61+ fs . writeSync ( descriptor , token ) ;
62+ }
63+
3964 cd ( path : string , gen : ( ) => void ) {
4065 const prev = this . currentDir ;
4166 this . currentDir = path . startsWith ( "/" )
4267 ? Path . join ( this . opts . outputDir , path )
4368 : Path . join ( this . currentDir ?? this . opts . outputDir , path ) ;
44- if ( ! fs . existsSync ( this . currentDir ) ) {
45- fs . mkdirSync ( this . currentDir , { recursive : true } ) ;
46- }
69+ this . onDiskMkDir ( this . currentDir ) ;
4770 this . logger ( ) ?. debug ( `cd '${ this . currentDir } '` ) ;
4871 gen ( ) ;
4972 this . currentDir = prev ;
5073 }
5174
5275 cat ( fn : string , gen : ( ) => void ) {
53- if ( this . currentFileDescriptor ) throw new Error ( "Can't open file in file" ) ;
76+ if ( this . currentFile ) throw new Error ( "Can't open file when another file is open " ) ;
5477 if ( fn . includes ( "/" ) ) throw new Error ( `Change file path separatly: ${ fn } ` ) ;
5578
56- const fullFn = `${ this . currentDir } /${ fn } ` ;
79+ const relPath = Path . normalize ( `${ this . currentDir } /${ fn } ` ) ;
5780 try {
58- this . currentFileDescriptor = fs . openSync ( fullFn , "w" ) ;
59- this . writtenFilesSet . add ( Path . resolve ( Path . normalize ( fullFn ) ) ) ;
60- this . logger ( ) ?. debug ( `cat > '${ fullFn } '` ) ;
81+ const descriptor = this . onDiskOpenFile ( relPath ) ;
82+
83+ this . logger ( ) ?. debug ( `cat > '${ relPath } '` ) ;
84+ this . currentFile = { descriptor, relPath } ;
85+ this . writtenFilesBuffer [ this . currentFile . relPath ] = { relPath, absPath : Path . resolve ( relPath ) , tokens : [ ] } ;
86+
6187 gen ( ) ;
6288 } finally {
63- if ( this . currentFileDescriptor ) {
64- // Force flush all buffered data to disk before closing
65- fs . fsyncSync ( this . currentFileDescriptor ) ;
66- fs . closeSync ( this . currentFileDescriptor ) ;
67- }
68- this . currentFileDescriptor = undefined ;
89+ if ( this . currentFile ) this . onDiskCloseFile ( this . currentFile . descriptor ) ;
90+ this . currentFile = undefined ;
6991 }
7092 }
7193
7294 write ( str : string ) {
73- if ( ! this . currentFileDescriptor ) throw new Error ( "No file opened" ) ;
74- fs . writeSync ( this . currentFileDescriptor , str ) ;
95+ if ( ! this . currentFile ) throw new Error ( "No file opened" ) ;
96+ this . onDiskWrite ( this . currentFile . descriptor , str ) ;
97+
98+ const buf = this . writtenFilesBuffer [ this . currentFile . relPath ] ;
99+ if ( ! buf ) throw new Error ( "No buffer found" ) ;
100+ buf . tokens . push ( str ) ;
75101 }
76102
77103 abstract generate ( _tsIndex : TypeSchemaIndex ) : Promise < void > ;
78104
79- writtenFiles ( ) : string [ ] {
80- return Array . from ( this . writtenFilesSet ) ;
105+ writtenFiles ( ) : FileBuffer [ ] {
106+ return Object . values ( this . writtenFilesBuffer )
107+ . map ( ( { relPath, absPath, tokens } ) => {
108+ return { relPath, absPath, content : tokens . join ( ) } ;
109+ } )
110+ . sort ( ( a , b ) => a . relPath . localeCompare ( b . relPath ) ) ;
81111 }
82112}
83113
0 commit comments