import { describe, expect, it } from 'vitest'; import { array, lazy, number, object, optional, pipe, serializeSchema, string, walkSchema } from '../core'; import type { Schema } from '../core'; describe('serializeSchema()', () => { it('serializes object schemas into a JSON-friendly tree', () => { const schema = object({ a: string() }); expect(serializeSchema(schema)).toEqual({ kind: 'object', wrappers: [], effects: [], async: false, meta: {}, shape: { kind: 'object', unknownKeys: 'strip', fields: { a: { kind: 'string', wrappers: [], effects: [], async: false, meta: {} } } } }); }); it('truncates recursive schemas without overflowing', () => { type TreeNode = { value: string; children?: TreeNode[]; }; const TreeSchema: Schema = lazy(() => object({ value: string(), children: optional(array(TreeSchema)) }) ); const serialized = serializeSchema(TreeSchema, 1); const children = serialized.shape?.kind === 'object' ? serialized.shape.fields.children : undefined; expect(children?.shape).toEqual({ kind: 'truncated', inner: 'optional' }); }); }); describe('countLeafFields()', () => { it('counts nested object leaves and treats arrays as one slot', async () => { const { countLeafFields } = await import('../core'); expect( countLeafFields( object({ a: string(), b: number(), nested: object({ c: string() }) }) ) ).toBe(3); expect(countLeafFields(array(string()))).toBe(1); }); }); describe('walkSchema()', () => { it('visits the schema tree in pre-order for object fields', () => { const visited: string[] = []; const schema = object({ a: string(), b: pipe(number()) }); walkSchema(schema, (_node, path) => { visited.push(path.length === 0 ? '(root)' : path.join('.')); }); expect(visited).toEqual(['(root)', 'a', 'b']); }); });