1
- import path from 'path' ;
1
+ import fs from 'node:fs/promises' ;
2
+ import path from 'node:path' ;
2
3
import type { ESLint as ESLintClass } from 'eslint' ;
3
4
import {
4
5
ClientGenerationResultFile ,
@@ -15,29 +16,77 @@ export async function postprocessFiles({
15
16
outputDirPath : string ;
16
17
} ) : Promise < ClientGenerationResultFile [ ] > {
17
18
if ( enableEslint ) {
18
- // This is an optional dependency, so we require it here to avoid loading it when it's not needed.
19
- // eslint-disable-next-line @typescript-eslint/no-var-requires
20
- const { ESLint} = require ( 'eslint' ) as { ESLint : typeof ESLintClass } ;
21
- const eslint = new ESLint ( {
22
- fix : true
23
- } ) ;
19
+ // TypeScript parser expects files to be present, so we need to create directories for them.
20
+ const directoriesToRemove : string [ ] = [ ] ;
21
+ const directories : Set < string > = new Set ( ) ;
22
+ for ( const file of files ) {
23
+ const directory = path . dirname ( path . resolve ( outputDirPath , file . filename ) ) ;
24
+ directories . add ( directory ) ;
25
+ }
24
26
25
- return Promise . all (
26
- files . map ( async ( file ) => {
27
- const [ result ] = await eslint . lintText ( file . data , {
28
- filePath : path . resolve ( outputDirPath , file . filename )
29
- } ) ;
30
- for ( const message of result . messages ) {
31
- if ( message . fatal ) {
32
- throw new Error ( `Fatal ESLint error in ${ file . filename } : ${ message . message } ` ) ;
27
+ for ( const directory of Array . from ( directories ) ) {
28
+ try {
29
+ await fs . stat ( directory ) ;
30
+ } catch ( _e ) {
31
+ const directoryBits = directory . split ( path . sep ) ;
32
+ let currentDirectory = directoryBits . shift ( ) || '/' ;
33
+ for ( ; ; ) {
34
+ try {
35
+ await fs . stat ( currentDirectory ) ;
36
+ } catch ( e ) {
37
+ await fs . mkdir ( currentDirectory ) ;
38
+ directoriesToRemove . unshift ( currentDirectory ) ;
33
39
}
40
+ const subDirectory = directoryBits . shift ( ) ;
41
+ if ( ! subDirectory ) {
42
+ break ;
43
+ }
44
+ currentDirectory = path . join ( currentDirectory , subDirectory ) ;
34
45
}
35
- return {
36
- ...file ,
37
- data : result . output ?? file . data
38
- } ;
39
- } )
40
- ) ;
46
+ }
47
+ }
48
+
49
+ try {
50
+ // This is an optional dependency, so we require it here to avoid loading it when it's not needed.
51
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
52
+ const { ESLint} = require ( 'eslint' ) as { ESLint : typeof ESLintClass } ;
53
+ const eslint = new ESLint ( {
54
+ fix : true
55
+ } ) ;
56
+
57
+ return await Promise . all (
58
+ files . map ( async ( file ) => {
59
+ const filePath = path . resolve ( outputDirPath , file . filename ) ;
60
+ let fileCreated = false ;
61
+ try {
62
+ try {
63
+ await fs . stat ( filePath ) ;
64
+ } catch ( _e ) {
65
+ await fs . writeFile ( filePath , file . data ) ;
66
+ fileCreated = true ;
67
+ }
68
+ const [ result ] = await eslint . lintText ( file . data , { filePath} ) ;
69
+ for ( const message of result . messages ) {
70
+ if ( message . fatal ) {
71
+ throw new Error ( `Fatal ESLint error in ${ file . filename } : ${ message . message } ` ) ;
72
+ }
73
+ }
74
+ return {
75
+ ...file ,
76
+ data : result . output ?? file . data
77
+ } ;
78
+ } finally {
79
+ if ( fileCreated ) {
80
+ await fs . unlink ( filePath ) ;
81
+ }
82
+ }
83
+ } )
84
+ ) ;
85
+ } finally {
86
+ for ( const directory of directoriesToRemove ) {
87
+ await fs . rmdir ( directory ) ;
88
+ }
89
+ }
41
90
}
42
91
return files ;
43
92
}
0 commit comments