Skip to content

Commit 077a88f

Browse files
committed
Post-process hack to generate array types
1 parent c1151c0 commit 077a88f

File tree

1 file changed

+71
-1
lines changed

1 file changed

+71
-1
lines changed

packages/tasks/src/scripts/inference-codegen.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { quicktype, InputData, JSONSchemaInput, FetchingJSONSchemaStore } from "
33
import * as fs from "fs/promises";
44
import { existsSync as pathExists } from "fs";
55
import * as path from "path";
6+
import * as ts from "typescript";
67

78
const TYPESCRIPT_HEADER_FILE = `
89
/**
@@ -18,7 +19,6 @@ const rootDirFinder = function (): string {
1819
let level = parts.length - 1;
1920
while (level > 0) {
2021
const currentPath = parts.slice(0, level).join("/");
21-
console.debug(currentPath);
2222
if (pathExists(`${currentPath}/package.json`)) {
2323
return path.normalize(currentPath);
2424
}
@@ -64,6 +64,71 @@ async function generateTypescript(inputData: InputData): Promise<SerializedRende
6464
});
6565
}
6666

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+
67132
async function main() {
68133
const rootDir = rootDirFinder();
69134
const tasksDir = path.join(rootDir, "src", "tasks");
@@ -96,6 +161,11 @@ async function main() {
96161
encoding: "utf-8",
97162
});
98163
}
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);
99169
}
100170
console.debug("✅ All done!");
101171
}

0 commit comments

Comments
 (0)