|
|
|
|
import { describe, expect, it } from 'vitest';
|
feat(sium): audit cleanup + 2.0 (coercion, formats, combinators, object utils)
Audit: drop dead SIUM_ERRORS catalogue, no-op try/catch in refine steps, unused isPromiseLike/pathKeys re-export, ignored dateValue/timeValue opts; add a sync fast-path to ~standard.validate so sync schemas no longer force the async branch (+untrack workaround) in form/storage consumers; doc fixes ($lib alias, JSDoc, README).
2.0 (all on the s.* facade): coercion (coerceNumber/Boolean/String); string formats (uuid/slug/datetime/ipv4); numeric (finite/positive/nonnegative/multipleOf); transforms (trim/toLowerCase/toUpperCase) + nullish; combinators tuple/record (+ SchemaKind/SiumShape vocabulary + introspection); object utils pick/omit/partial/extend/merge (+ SiumObjectUtilError). 8 new issue codes with es/en.
398 -> 450 tests, 0 type errors, prettier clean. Updated arts/ diagnostics contract + sium README.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
|
|
|
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<TreeNode, TreeNode> = lazy(() =>
|
|
|
|
|
object({
|
|
|
|
|
value: string(),
|
|
|
|
|
children: optional(array(TreeSchema))
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const serialized = serializeSchema(TreeSchema, 1);
|
feat(sium): audit cleanup + 2.0 (coercion, formats, combinators, object utils)
Audit: drop dead SIUM_ERRORS catalogue, no-op try/catch in refine steps, unused isPromiseLike/pathKeys re-export, ignored dateValue/timeValue opts; add a sync fast-path to ~standard.validate so sync schemas no longer force the async branch (+untrack workaround) in form/storage consumers; doc fixes ($lib alias, JSDoc, README).
2.0 (all on the s.* facade): coercion (coerceNumber/Boolean/String); string formats (uuid/slug/datetime/ipv4); numeric (finite/positive/nonnegative/multipleOf); transforms (trim/toLowerCase/toUpperCase) + nullish; combinators tuple/record (+ SchemaKind/SiumShape vocabulary + introspection); object utils pick/omit/partial/extend/merge (+ SiumObjectUtilError). 8 new issue codes with es/en.
398 -> 450 tests, 0 type errors, prettier clean. Updated arts/ diagnostics contract + sium README.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
|
|
|
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']);
|
|
|
|
|
});
|
|
|
|
|
});
|