seitu
Version:
72 lines (71 loc) • 2.36 kB
JavaScript
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 };