@storecraft/core
Version: 
Core Package for storecraft
105 lines (92 loc) • 2.54 kB
JavaScript
import { z } from 'zod'
/**
 * @param {Object} o 
 * @param {z.ZodTypeAny} zod 
 */
const with_description = (o, zod) => {
  if(zod.description)
    o.description = zod.description;
  return o;
}
/**
 * @template {z.ZodTypeAny} T 
 * @param {T} schema 
 */
export const zod_to_json_schema = (schema) => {
  // make sure schema is not null or undefined
  if (schema === null || schema === undefined) return null;
  // check if schema is nullable or optional
  if (schema instanceof z.ZodNullable || schema instanceof z.ZodOptional) 
    return zod_to_json_schema(schema.unwrap().describe(schema.description));
  if (schema instanceof z.ZodDefault) 
    return zod_to_json_schema(schema.removeDefault().describe(schema.description));
  // check if schema is an array
  if (schema instanceof z.ZodArray) {
    return with_description(
      {
        type: 'array',
        items: zod_to_json_schema(schema.element)
      }, schema
    )
  }
  // check if schema is an object
  if (schema instanceof z.ZodObject) {
    // get key/value pairs from schema
    const entries = Object.entries(schema.shape);
    // loop through key/value pairs
    const obj = {
      "properties": Object.fromEntries(
        entries.map(
          ([key, value]) => {
            // get nested keys
            // const nested = zod_to_json_schema(value);
            return [key, zod_to_json_schema(value)];
          }
        )
      ),
      "type": "object",
      "additionalProperties": false
    }
    const required = entries.filter(
      ([key, value]) => !zod_is_optional(value)
    ).map(
      ([key, value]) => key
    );
    if(required.length > 0)
      obj.required = required;
    // console.log(JSON.stringify({obj}, null, 2));
    return obj
  }
  if (schema instanceof z.ZodNumber) 
    return with_description(
      { type: 'number' }, schema
    );
  if (schema instanceof z.ZodString) 
    return with_description(
      { type: 'string' }, schema
    );
  if (schema instanceof z.ZodEnum) 
    return with_description(
      { 
        type: 'string', 
        enum: schema.options
      }, schema
    );
  // return empty array
  return {
    type: "unsupported"
  };
};
/**
 * @template {z.ZodTypeAny} T 
 * @param {T} schema 
 */
export const zod_is_optional = (schema) => {
  if(schema instanceof z.ZodOptional)
    return true;
  if (schema instanceof z.ZodNullable) 
    return zod_is_optional(schema.unwrap());
  if (schema instanceof z.ZodDefault) 
    return zod_is_optional(schema.removeDefault());
  return false;
}