// Generates src/types/api.ts, the TypeScript types of the backend's API, from // its OpenAPI 3.1 description: // // npm run generate:api [-- ] // // The default is the backend's generated file, ../internal/api/openapi/ // swagger.json (run go generate ./... in the repository first); a running // server's http://localhost:9393/api/openapi.json works too. // // swag marks a Go field that can be null (a pointer, or a slice that can be // nil) with the x-nullable extension, which openapi-typescript ignores, so // those properties are rewritten into OpenAPI 3.1's own form first. import { readFile, writeFile } from 'node:fs/promises'; import type { OpenAPI3 } from 'openapi-typescript'; import openapiTS, { astToString } from 'openapi-typescript'; const defaultSource = '../internal/api/openapi/swagger.json'; const output = 'src/types/api.ts'; const header = `// Code generated by npm run generate:api from the backend's OpenAPI // description. DO NOT EDIT: change the Go types or handlers, then // regenerate (see scripts/generateApiTypes.ts). `; type Schema = Record; /** Rewrites every x-nullable property of the description's schemas so it allows null. */ function allowNulls(description: OpenAPI3): void { const schemas = (description.components?.schemas ?? {}) as Record; for (const schema of Object.values(schemas)) { const properties = (schema.properties ?? {}) as Record; for (const [name, property] of Object.entries(properties)) { if (property['x-nullable'] !== true) continue; delete property['x-nullable']; properties[name] = typeof property.type === 'string' && property.type !== 'array' ? { ...property, type: [property.type, 'null'] } : { oneOf: [property, { type: 'null' }] }; } } } async function readDescription(source: string): Promise { const text = /^https?:\/\//.test(source) ? await (await fetch(source)).text() : await readFile(source, 'utf8'); return JSON.parse(text) as OpenAPI3; } const source = process.argv[2] ?? defaultSource; const description = await readDescription(source); allowNulls(description); const types = astToString(await openapiTS(description)); await writeFile(output, header + types); console.log(`Wrote ${output} from ${source}`);