import { normalizeDefs, SchemaDefsOrReferences } from "@noya-app/noya-schemas"; import { Static, TSchema } from "@sinclair/typebox"; import { Errors } from "@sinclair/typebox/errors"; import { Check } from "@sinclair/typebox/value"; import { castValue } from "./valueUtils"; // FormatRegistry.Set("color", () => true); export function checkType( state: S, schema: TSchema | undefined, defs: SchemaDefsOrReferences, { debug = false, }: { debug?: boolean; } = {} ): S { if (!schema) return state; let ok = Check(schema, normalizeDefs(defs), state); if (!ok) { const errors = [...Errors(schema, state)]; // errors without `schema` property const simplerErrors = errors.map((error) => { const { schema, type, ...rest } = error; return { ...rest }; }); if (debug) { console.error("Schema typecheck failed", schema, state); } throw new Error( `State does not match schema:\n${simplerErrors.map((error) => JSON.stringify(error, null, 2)).join("\n")}` ); } return state; } export function checkTypeSafe(...args: Parameters) { const [state, schema, defs] = args; if (!schema) return true; return Check(schema, normalizeDefs(defs), state); } export function createOrCastValue({ schema, value, defs, }: { schema: T; value?: unknown; defs: SchemaDefsOrReferences; }): Static { if (value !== undefined && checkTypeSafe(value, schema, defs)) { return value; } const newValue = castValue(schema, defs, value); checkType(newValue, schema, defs); return newValue; }