UNPKG

seitu

Version:
72 lines (71 loc) • 2.36 kB
import { createReadableSubscription } from "./core/subscription/index.mjs"; import { createStore } from "./core/store/index.mjs"; //#region src/internal/validate.ts function validateSync(schema, value, label) { const result = schema["~standard"].validate(value); if (result instanceof Promise) throw new TypeError(`[${label}] Validation schema should not return a Promise.`); return result; } function validateSchema(schema, value, options) { const result = validateSync(schema, value, options.label); if (!result.issues) return result.value; let issues = result.issues; if (options.onError) { const corrected = options.onError({ defaultValue: options.defaultValue, issues: [...result.issues], value, key: options.key }); if (corrected === void 0) return options.defaultValue; const validated = validateSync(schema, corrected, options.label); if (!validated.issues) return validated.value; issues = validated.issues; } console.warn(`[${options.label}] Returned value invalid, returned default value instead`, JSON.stringify(issues, null, 2)); return options.defaultValue; } //#endregion //#region src/core/schema-store/index.ts /** * Reactive store validated on read. Invalid values fall back to `defaultValue`. * Validation is memoized on the raw state reference. * * @example * ```ts twoslash * import { createSchemaStore } from 'seitu' * import * as z from 'zod' * * const store = createSchemaStore({ * schema: z.object({ count: z.number(), name: z.string() }), * defaultValue: { count: 0, name: '' }, * }) * store.get() * store.set({ count: 1, name: 'alice' }) * store.subscribe(console.log) * ``` */ function createSchemaStore(options) { const store = createStore(options.defaultValue); let lastInput = Symbol("seitu.unset"); let lastOutput; const get = () => { const raw = store.get(); if (raw === lastInput) return lastOutput; lastOutput = validateSchema(options.schema, raw, { defaultValue: options.defaultValue, label: "createSchemaStore", onError: options.onValidationError }); lastInput = raw; return lastOutput; }; return { ...createReadableSubscription(get, store.subscribe, store["~"].notify), set: (value) => { store.set(typeof value === "function" ? value(get()) : value); } }; } //#endregion export { validateSchema as n, validateSync as r, createSchemaStore as t };