@@ -3,6 +3,7 @@ import { quicktype, InputData, JSONSchemaInput, FetchingJSONSchemaStore } from "
3
3
import * as fs from "fs/promises" ;
4
4
import { existsSync as pathExists } from "fs" ;
5
5
import * as path from "path" ;
6
+ import * as ts from "typescript" ;
6
7
7
8
const TYPESCRIPT_HEADER_FILE = `
8
9
/**
@@ -18,7 +19,6 @@ const rootDirFinder = function (): string {
18
19
let level = parts . length - 1 ;
19
20
while ( level > 0 ) {
20
21
const currentPath = parts . slice ( 0 , level ) . join ( "/" ) ;
21
- console . debug ( currentPath ) ;
22
22
if ( pathExists ( `${ currentPath } /package.json` ) ) {
23
23
return path . normalize ( currentPath ) ;
24
24
}
@@ -64,6 +64,71 @@ async function generateTypescript(inputData: InputData): Promise<SerializedRende
64
64
} ) ;
65
65
}
66
66
67
+ async function postProcessOutput ( path2generated : string , outputSpec : Record < string , unknown > ) : Promise < void > {
68
+ const source = ts . createSourceFile (
69
+ path . basename ( path2generated ) ,
70
+ await fs . readFile ( path2generated , { encoding : "utf-8" } ) ,
71
+ ts . ScriptTarget . ES2022
72
+ ) ;
73
+ const exportedName = outputSpec . title ;
74
+ if ( outputSpec . type !== "array" || typeof exportedName !== "string" ) {
75
+ console . log ( " Nothing to do" ) ;
76
+ return ;
77
+ }
78
+ const topLevelNodes = source . getChildAt ( 0 ) . getChildren ( ) ;
79
+ const hasTypeAlias = topLevelNodes . some (
80
+ ( node ) =>
81
+ node . kind === ts . SyntaxKind . TypeAliasDeclaration &&
82
+ ( node as ts . TypeAliasDeclaration ) . name . escapedText === exportedName
83
+ ) ;
84
+ if ( hasTypeAlias ) {
85
+ return ;
86
+ }
87
+
88
+ const interfaceDeclaration = topLevelNodes . find ( ( node ) : node is ts . InterfaceDeclaration => {
89
+ if ( node . kind === ts . SyntaxKind . InterfaceDeclaration ) {
90
+ return ( node as ts . InterfaceDeclaration ) . name . getText ( source ) === exportedName ;
91
+ }
92
+ return false ;
93
+ } ) ;
94
+ if ( ! interfaceDeclaration ) {
95
+ console . log ( " Nothing to do" ) ;
96
+ return ;
97
+ }
98
+
99
+ console . log ( " Inserting top-level array type alias..." ) ;
100
+
101
+ const updatedInterface = ts . factory . updateInterfaceDeclaration (
102
+ interfaceDeclaration ,
103
+ interfaceDeclaration . modifiers ,
104
+ ts . factory . createIdentifier ( interfaceDeclaration . name . getText ( source ) + "Element" ) ,
105
+ interfaceDeclaration . typeParameters ,
106
+ interfaceDeclaration . heritageClauses ,
107
+ interfaceDeclaration . members
108
+ ) ;
109
+ const arrayDeclaration = ts . factory . createTypeAliasDeclaration (
110
+ [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
111
+ exportedName ,
112
+ undefined ,
113
+ ts . factory . createArrayTypeNode ( ts . factory . createTypeReferenceNode ( updatedInterface . name ) )
114
+ ) ;
115
+
116
+ const printer = ts . createPrinter ( ) ;
117
+
118
+ const newNodes = ts . factory . createNodeArray ( [
119
+ ...topLevelNodes . filter ( ( node ) => node !== interfaceDeclaration ) ,
120
+ arrayDeclaration ,
121
+ updatedInterface ,
122
+ ] ) ;
123
+
124
+ fs . writeFile ( path2generated , printer . printList ( ts . ListFormat . MultiLine , newNodes , source ) , {
125
+ flag : "w+" ,
126
+ encoding : "utf-8" ,
127
+ } ) ;
128
+
129
+ return ;
130
+ }
131
+
67
132
async function main ( ) {
68
133
const rootDir = rootDirFinder ( ) ;
69
134
const tasksDir = path . join ( rootDir , "src" , "tasks" ) ;
@@ -96,6 +161,11 @@ async function main() {
96
161
encoding : "utf-8" ,
97
162
} ) ;
98
163
}
164
+
165
+ const outputSpec = JSON . parse ( await fs . readFile ( `${ taskSpecDir } /output.json` , { encoding : "utf-8" } ) ) ;
166
+
167
+ console . log ( " 🩹 Post-processing the generated code" ) ;
168
+ await postProcessOutput ( `${ dirPath } /inference.ts` , outputSpec ) ;
99
169
}
100
170
console . debug ( "✅ All done!" ) ;
101
171
}
0 commit comments