UNPKG

hey-api-builders

Version:

A custom plugin for @hey-api/openapi-ts that generates mock data builders with a lightweight custom runtime, Zod integration, or static mock generation.

145 lines (130 loc) 6.55 kB
import { collectSchemas, generateWithMethods } from './utils'; import { generateZodSchema } from './zod-generator'; import { generateStaticMockCode } from './static-mock-generator'; import type { BuildersHandler } from './types'; import type { IR } from '@hey-api/openapi-ts'; export const handler: BuildersHandler = ({ plugin }) => { const rawSchemas: Record<string, IR.SchemaObject> = {}; plugin.forEach('schema', (event) => { rawSchemas[event.name] = event.schema; }); const metas = collectSchemas(rawSchemas); const file = plugin.createFile({ id: plugin.name, path: plugin.output }); const config = plugin.config; const generateZod = config.generateZod || false; const useZodForMocks = config.useZodForMocks || false; const useStaticMocks = config.useStaticMocks || false; let out = ''; const needsZodImport = generateZod || useZodForMocks; if (useStaticMocks) { } else if (useZodForMocks) { out += 'import { generateMockFromZodSchema } from "hey-api-builders"\n'; } else { out += 'import { generateMock } from "hey-api-builders"\n'; out += 'import type { BuilderSchema } from "hey-api-builders"\n'; } if (needsZodImport) { out += 'import { z } from "zod"\n'; } out += 'import type * as types from "./types.gen"\n\n'; out += 'type BuilderOptions = {\n'; out += ' useDefault?: boolean;\n'; out += ' useExamples?: boolean;\n'; out += ' alwaysIncludeOptionals?: boolean;\n'; out += ' optionalsProbability?: number | false;\n'; out += ' omitNulls?: boolean;\n'; out += '}\n\n'; if (!useZodForMocks && !useStaticMocks) { const schemaEntries: string[] = []; for (const m of metas) { schemaEntries.push(` ${m.constName}: ${JSON.stringify(m.schema)}`); } out += 'const schemas = {\n' + schemaEntries.join(',\n') + '\n} satisfies Record<string, BuilderSchema>\n\n'; } if (generateZod || useZodForMocks) { const zodSchemaEntries: string[] = []; for (const m of metas) { const zodSchemaString = generateZodSchema(m.schema); zodSchemaEntries.push(` ${m.constName}Zod: ${zodSchemaString}`); } out += 'export const zodSchemas = {\n' + zodSchemaEntries.join(',\n') + '\n}\n\n'; } for (const m of metas) { if (m.isEnum) { out += `export class ${m.typeName}Builder {\n`; out += ` private options: BuilderOptions = {}\n`; out += ` setOptions(o: BuilderOptions): this { this.options = o || {}; return this }\n`; if (useStaticMocks) { const staticMock = generateStaticMockCode(m.schema, m.typeName); out += ` build(): types.${m.typeName} {\n`; out += ` return ${staticMock} as types.${m.typeName};\n`; out += ` }\n`; } else if (useZodForMocks) { out += ` build(): types.${m.typeName} {\n`; out += ` const zodSchemaString = \`${generateZodSchema(m.schema)}\`;\n`; out += ` return generateMockFromZodSchema(zodSchemaString, {}, {\n`; out += ` useDefault: this.options.useDefault,\n`; out += ` useExamples: this.options.useExamples,\n`; out += ` alwaysIncludeOptionals: this.options.alwaysIncludeOptionals,\n`; out += ` optionalsProbability: this.options.optionalsProbability,\n`; out += ` omitNulls: this.options.omitNulls\n`; out += ` }) as types.${m.typeName};\n`; out += ` }\n`; } else { out += ` build(): types.${m.typeName} {\n`; out += ` return generateMock<types.${m.typeName}>(schemas.${m.constName}, {\n`; out += ` useDefaultValue: this.options.useDefault,\n`; out += ` useExamplesValue: this.options.useExamples,\n`; out += ` alwaysFakeOptionals: this.options.alwaysIncludeOptionals,\n`; out += ` optionalsProbability: this.options.optionalsProbability,\n`; out += ` omitNulls: this.options.omitNulls\n`; out += ` })\n`; out += ` }\n`; } out += `}\n\n`; } else { const withMethods = generateWithMethods(m.schema, m.typeName); out += `export class ${m.typeName}Builder {\n`; out += ` private overrides: Partial<types.${m.typeName}> = {}\n`; out += ` private options: BuilderOptions = {}\n`; out += ` setOptions(o: BuilderOptions): this { this.options = o || {}; return this }\n`; if (withMethods) out += withMethods + '\n'; if (useStaticMocks) { const staticMock = generateStaticMockCode(m.schema, m.typeName); out += ` build(): types.${m.typeName} {\n`; out += ` const baseMock = ${staticMock};\n`; out += ` return { ...baseMock, ...this.overrides } as types.${m.typeName};\n`; out += ` }\n`; } else if (useZodForMocks) { out += ` build(): types.${m.typeName} {\n`; out += ` const zodSchemaString = \`${generateZodSchema(m.schema)}\`;\n`; out += ` return generateMockFromZodSchema(zodSchemaString, this.overrides, {\n`; out += ` useDefault: this.options.useDefault,\n`; out += ` useExamples: this.options.useExamples,\n`; out += ` alwaysIncludeOptionals: this.options.alwaysIncludeOptionals,\n`; out += ` optionalsProbability: this.options.optionalsProbability,\n`; out += ` omitNulls: this.options.omitNulls\n`; out += ` }) as types.${m.typeName};\n`; out += ` }\n`; } else { out += ` build(): types.${m.typeName} {\n`; out += ` const mock = generateMock<types.${m.typeName}>(schemas.${m.constName}, {\n`; out += ` useDefaultValue: this.options.useDefault,\n`; out += ` useExamplesValue: this.options.useExamples,\n`; out += ` alwaysFakeOptionals: this.options.alwaysIncludeOptionals,\n`; out += ` optionalsProbability: this.options.optionalsProbability,\n`; out += ` omitNulls: this.options.omitNulls\n`; out += ` })\n`; out += ` for (const k in this.overrides) {\n`; out += ` if (Object.prototype.hasOwnProperty.call(this.overrides, k)) {\n`; out += ` const typedMock = mock as Record<string, unknown>;\n`; out += ` const typedOverrides = this.overrides as Record<string, unknown>;\n`; out += ` typedMock[k] = typedOverrides[k];\n`; out += ` }\n`; out += ` }\n`; out += ` return mock\n`; out += ` }\n`; } out += `}\n\n`; } } file.add(out); };