You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/soma/components/form/standard-schema.ts

85 lines
3.0 KiB

/**
* Standard Schema v1 — minimal inline port of the specification.
*
* <https://standardschema.dev/>
*
* A thin type + helper layer that lets `soma/Form` accept any validation
* library that implements the `"~standard"` interface: Zod, Valibot, ArkType,
* Effect/Schema, Yup (via adapter), etc. No runtime dependency on any specific
* schema library.
*
* The consumer imports their schema from their library of choice and passes
* it to `createForm({ schema })`. Validation is invoked via
* `schema["~standard"].validate(values)`.
*/
// ── Types ────────────────────────────────────────────────────────────────────
export interface StandardSchemaV1<Input = unknown, Output = Input> {
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
}
export namespace StandardSchemaV1 {
export interface Props<Input = unknown, Output = Input> {
/** Version number of the standard. */
readonly version: 1;
/** Vendor name (e.g. `"zod"`, `"valibot"`, `"arktype"`). */
readonly vendor: string;
/** Validates a value. May return a `Promise<Result>` for async schemas. */
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
/** Type metadata — compile-time only, undefined at runtime. */
readonly types?: Types<Input, Output>;
}
export type Result<Output> = SuccessResult<Output> | FailureResult;
export interface SuccessResult<Output> {
readonly value: Output;
readonly issues?: undefined;
}
export interface FailureResult {
readonly issues: ReadonlyArray<Issue>;
}
export interface Issue {
readonly message: string;
readonly path?: ReadonlyArray<PropertyKey | PathSegment>;
}
export interface PathSegment {
readonly key: PropertyKey;
}
export interface Types<Input = unknown, Output = Input> {
readonly input: Input;
readonly output: Output;
}
export type InferInput<S extends StandardSchemaV1> = NonNullable<
S['~standard']['types']
>['input'];
export type InferOutput<S extends StandardSchemaV1> = NonNullable<
S['~standard']['types']
>['output'];
}
// ── Helpers ──────────────────────────────────────────────────────────────────
/** `true` when the value's first segment is a `PathSegment` object. */
function isPathSegment(v: PropertyKey | StandardSchemaV1.PathSegment): v is StandardSchemaV1.PathSegment {
return typeof v === 'object' && v !== null && 'key' in v;
}
/** Normalize an issue's `path` to a string array of keys. */
export function pathKeys(issue: StandardSchemaV1.Issue): string[] {
if (!issue.path) return [];
return issue.path.map((p) => String(isPathSegment(p) ? p.key : p));
}
/** `true` when the validate call returned a Promise. */
export function isPromiseLike<T>(v: T | Promise<T>): v is Promise<T> {
return typeof (v as { then?: unknown })?.then === 'function';
}

Powered by TurnKey Linux.