mirror of
https://codeberg.org/MarkusThielker/next-ory.git
synced 2025-04-10 11:58:41 +00:00
NORY-47: refactor dynamic zodSchema generation
This commit is contained in:
parent
bc30c83dcb
commit
9170454ae2
1 changed files with 63 additions and 49 deletions
|
@ -1,22 +1,39 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
// interface for a list of properties
|
export const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||||
|
type Literal = z.infer<typeof literalSchema>;
|
||||||
|
type Json = Literal | { [key: string]: Json } | Json[];
|
||||||
|
export const jsonSchema: z.ZodType<Json> = z.lazy(() =>
|
||||||
|
z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Interface for a list of properties
|
||||||
export interface KratosSchemaProperties {
|
export interface KratosSchemaProperties {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
type: string;
|
type: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
|
||||||
format?: string;
|
format?: string;
|
||||||
title: string;
|
title: string;
|
||||||
minLength?: number;
|
minLength?: number;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
minimum?: number;
|
minimum?: number;
|
||||||
maximum?: number;
|
maximum?: number;
|
||||||
required?: boolean;
|
required: boolean;
|
||||||
description?: string;
|
description?: string;
|
||||||
properties?: KratosSchemaProperties
|
properties?: KratosSchemaProperties;
|
||||||
|
enum?: any[];
|
||||||
|
pattern?: string;
|
||||||
|
items?: KratosSchemaProperties;
|
||||||
|
oneOf?: KratosSchemaProperties[];
|
||||||
|
anyOf?: KratosSchemaProperties[];
|
||||||
|
allOf?: KratosSchemaProperties[];
|
||||||
|
dependencies?: { [key: string]: string[] | KratosSchemaProperties };
|
||||||
|
additionalProperties?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// interface for the kratos identity schema
|
// Interface for the Kratos identity schema
|
||||||
export interface KratosSchema {
|
export interface KratosSchema {
|
||||||
$id: string;
|
$id: string;
|
||||||
$schema: string;
|
$schema: string;
|
||||||
|
@ -32,53 +49,50 @@ export interface KratosSchema {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateZodSchema(properties: KratosSchemaProperties) {
|
export function kratosSchemaToZod(schema: KratosSchema): z.ZodObject<any> {
|
||||||
|
|
||||||
const zodSchema = z.object({});
|
// Function to recursively convert Kratos properties to Zod types
|
||||||
|
function convertProperties(properties: KratosSchemaProperties): { [key: string]: z.ZodTypeAny } {
|
||||||
|
const zodProps: { [key: string]: z.ZodTypeAny } = {};
|
||||||
|
for (const key in properties) {
|
||||||
|
const prop = properties[key];
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(properties)) {
|
let zodType;
|
||||||
let zodType;
|
switch (prop.type) {
|
||||||
switch (value.type) {
|
case 'string':
|
||||||
case 'string':
|
zodType = z.string();
|
||||||
zodType = z.string();
|
if (prop.format === 'email') zodType = zodType.email();
|
||||||
if (value.format === 'email') {
|
if (prop.minLength) zodType = zodType.min(prop.minLength);
|
||||||
zodType = z.string().email();
|
if (prop.maxLength) zodType = zodType.max(prop.maxLength);
|
||||||
}
|
if (prop.pattern) zodType = zodType.regex(new RegExp(prop.pattern));
|
||||||
if (value.minLength) {
|
break;
|
||||||
zodType = zodType.min(value.minLength);
|
case 'number':
|
||||||
}
|
case 'integer':
|
||||||
if (value.maxLength) {
|
zodType = z.number();
|
||||||
zodType = zodType.max(value.maxLength);
|
if (prop.minimum) zodType = zodType.min(prop.minimum);
|
||||||
}
|
if (prop.maximum) zodType = zodType.max(prop.maximum);
|
||||||
break;
|
break;
|
||||||
case 'integer':
|
case 'boolean':
|
||||||
case 'number':
|
zodType = z.boolean();
|
||||||
zodType = z.number();
|
break;
|
||||||
if (value.minimum) {
|
case 'object':
|
||||||
zodType = zodType.min(value.minimum);
|
zodType = z.object(convertProperties(prop.properties || {}));
|
||||||
}
|
break;
|
||||||
if (value.maximum) {
|
case 'array':
|
||||||
zodType = zodType.max(value.maximum);
|
zodType = z.array(
|
||||||
}
|
prop.items ? kratosSchemaToZod({ properties: { item: prop.items } } as any).shape.item : z.any(),
|
||||||
break;
|
);
|
||||||
case 'boolean':
|
break;
|
||||||
zodType = z.boolean();
|
default:
|
||||||
break;
|
zodType = z.any(); // Fallback to any for unknown types
|
||||||
case 'object':
|
}
|
||||||
const schemaCopy = structuredClone(schema);
|
|
||||||
schemaCopy.properties.traits.properties = value.properties!;
|
if (prop.enum) zodType = zodType.refine((val) => prop.enum!.includes(val));
|
||||||
zodType = generateZodSchema(schemaCopy);
|
|
||||||
break;
|
zodProps[key] = zodType;
|
||||||
default:
|
|
||||||
zodType = z.any();
|
|
||||||
}
|
}
|
||||||
|
return zodProps;
|
||||||
if (!value.required) {
|
|
||||||
zodType = zodType.nullable();
|
|
||||||
}
|
|
||||||
|
|
||||||
zodSchema.extend({ [key]: zodType });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return zodSchema;
|
return z.object(convertProperties(schema.properties.traits.properties));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue