Skip to content

Commit a2e4fbb

Browse files
lsteinclaudePfannkuchensack
authored
fix: patch openapi-typescript enum generation to match OpenAPI schema (invoke-ai#9037)
openapi-typescript computes enum types from `const` usage in discriminated unions rather than from the enum definition itself, dropping values that only appear in some union members (e.g. "anima" from BaseModelType). Add a post-processing step that patches generated string enum types to match the actual OpenAPI schema definitions. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
1 parent 06eff38 commit a2e4fbb

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

invokeai/frontend/web/scripts/typegen.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,37 @@ async function generateTypes(schema) {
3434
},
3535
defaultNonNullable: false,
3636
});
37-
fs.writeFileSync(OUTPUT_FILE, astToString(types));
37+
let output = astToString(types);
38+
39+
// Post-process: openapi-typescript sometimes computes enum types from `const`
40+
// usage in discriminated unions rather than from the enum definition itself,
41+
// dropping values that only appear in some union members. Patch the generated
42+
// output to match the OpenAPI schema's actual enum definitions.
43+
//
44+
// The `schema` parameter is a parsed JSON object when piped from stdin, or
45+
// a URL/Buffer when passed as an argument. We only patch in the JSON case.
46+
if (schema && typeof schema === 'object' && !Buffer.isBuffer(schema)) {
47+
const schemas = schema.components?.schemas;
48+
if (schemas) {
49+
// Collect all string enum types and their expected values from the OpenAPI schema
50+
for (const [typeName, typeDef] of Object.entries(schemas)) {
51+
if (typeDef && typeDef.type === 'string' && Array.isArray(typeDef.enum)) {
52+
const expectedUnion = typeDef.enum.map((v) => `"${v}"`).join(' | ');
53+
// Match the type definition line. These appear as:
54+
// `TypeName: "val1" | "val2" | ...;`
55+
// Use word boundary to avoid matching types that contain this
56+
// type name as a substring (e.g. ModelType vs BaseModelType).
57+
const regex = new RegExp(`(\\b${typeName}: )"[^;]+(;)`);
58+
const match = output.match(regex);
59+
if (match) {
60+
output = output.replace(regex, `$1${expectedUnion}$2`);
61+
}
62+
}
63+
}
64+
}
65+
}
66+
67+
fs.writeFileSync(OUTPUT_FILE, output);
3868
process.stdout.write(`\nOK!\r\n`);
3969
}
4070

0 commit comments

Comments
 (0)