| import type { ZodType } from 'zod' |
|
|
| type ZodDef = { |
| type: string |
| innerType?: ZodType |
| valueType?: ZodType |
| element?: ZodType |
| options?: ZodType[] |
| entries?: Record<string, string> |
| } |
|
|
| function def(schema: ZodType | undefined): ZodDef | undefined { |
| return (schema as { def?: ZodDef } | undefined)?.def |
| } |
|
|
| function shapeOf( |
| schema: ZodType | undefined, |
| ): Record<string, ZodType> | undefined { |
| return (schema as { shape?: Record<string, ZodType> } | undefined)?.shape |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function sampleCamel(schema: ZodType | undefined, depth = 0): unknown { |
| const d = def(schema) |
| if (!d || depth > 12) { |
| return undefined |
| } |
| switch (d.type) { |
| case 'object': { |
| const out: Record<string, unknown> = {} |
| for (const [k, v] of Object.entries(shapeOf(schema) ?? {})) { |
| const value = sampleCamel(v, depth + 1) |
| if (value !== undefined) { |
| out[k] = value |
| } |
| } |
| return out |
| } |
| case 'optional': |
| case 'nullable': |
| case 'default': |
| return sampleCamel(d.innerType, depth) |
| case 'array': |
| return [sampleCamel(d.element, depth + 1)] |
| case 'record': |
| return { user_key_a: sampleCamel(d.valueType, depth + 1) } |
| case 'union': |
| return sampleCamel(d.options?.[0], depth) |
| case 'literal': |
| return (schema as { value?: unknown }).value |
| case 'enum': |
| |
| |
| |
| |
| return Object.values(d.entries ?? {})[0] |
| case 'string': |
| return 's' |
| case 'int': |
| case 'number': |
| return 1 |
| case 'bigint': |
| return 1n |
| case 'boolean': |
| return true |
| case 'date': |
| return new Date(0) |
| default: |
| return undefined |
| } |
| } |
|
|
| |
| |
| export function sampleSnake(schema: ZodType | undefined, depth = 0): unknown { |
| const value = sampleCamel(schema, depth) |
| return toSnakeKeys(value) |
| } |
|
|
| function toSnakeKeys(value: unknown): unknown { |
| if (value instanceof Date) { |
| |
| return value.toISOString() |
| } |
| if (typeof value === 'bigint') { |
| |
| return Number(value) |
| } |
| if (Array.isArray(value)) { |
| return value.map(toSnakeKeys) |
| } |
| if (value && typeof value === 'object') { |
| const out: Record<string, unknown> = {} |
| for (const [k, v] of Object.entries(value)) { |
| const key = k.startsWith('user_key_') |
| ? k |
| : k.replace(/([A-Z])/g, (_m, c: string) => `_${c.toLowerCase()}`) |
| out[key] = toSnakeKeys(v) |
| } |
| return out |
| } |
| return value |
| } |
|
|
| |
| |
| |
| |
| export function collectFieldKeys( |
| value: unknown, |
| keys: string[] = [], |
| ): string[] { |
| if (Array.isArray(value)) { |
| for (const item of value) { |
| collectFieldKeys(item, keys) |
| } |
| return keys |
| } |
| if (value && typeof value === 'object' && !(value instanceof Date)) { |
| for (const [k, v] of Object.entries(value)) { |
| if (k.startsWith('user_key_')) { |
| |
| |
| |
| |
| |
| collectFieldKeys(v, keys) |
| continue |
| } |
| keys.push(k) |
| collectFieldKeys(v, keys) |
| } |
| } |
| return keys |
| } |
|
|
| |
| export function operationSchemaPairs( |
| schemas: Record<string, unknown>, |
| ): Array<{ base: string; body?: ZodType; response?: ZodType }> { |
| const bases = new Map<string, { body?: ZodType; response?: ZodType }>() |
| for (const [name, schema] of Object.entries(schemas)) { |
| const bodyMatch = name.match(/^(.*)Body$/) |
| const responseMatch = name.match(/^(.*)Response$/) |
| if (bodyMatch) { |
| const entry = bases.get(bodyMatch[1]) ?? {} |
| entry.body = schema as ZodType |
| bases.set(bodyMatch[1], entry) |
| } else if (responseMatch) { |
| const entry = bases.get(responseMatch[1]) ?? {} |
| entry.response = schema as ZodType |
| bases.set(responseMatch[1], entry) |
| } |
| } |
| return [...bases.entries()].map(([base, v]) => ({ base, ...v })) |
| } |
|
|