Files
bknd/app/src/core/object/schema/index.ts
T

84 lines
2.2 KiB
TypeScript

import * as s from "jsonv-ts";
export { validator as jsc, type Options } from "jsonv-ts/hono";
export { describeRoute, schemaToSpec, openAPISpecs } from "jsonv-ts/hono";
export { secret } from "./secret";
export { s };
export const stripMark = <O extends object>(o: O): O => o;
export const mark = <O extends object>(o: O): O => o;
export const stringIdentifier = s.string({
pattern: "^[a-zA-Z_][a-zA-Z0-9_]*$",
minLength: 2,
maxLength: 150,
});
export class InvalidSchemaError extends Error {
constructor(
public schema: s.Schema,
public value: unknown,
public errors: s.ErrorDetail[] = [],
) {
super(
`Invalid schema given for ${JSON.stringify(value, null, 2)}\n\n` +
`Error: ${JSON.stringify(errors[0], null, 2)}`,
);
}
first() {
return this.errors[0]!;
}
firstToString() {
const first = this.first();
return `${first.error} at ${first.instanceLocation}`;
}
}
export type ParseOptions = {
withDefaults?: boolean;
withExtendedDefaults?: boolean;
coerce?: boolean;
clone?: boolean;
skipMark?: boolean; // @todo: do something with this
forceParse?: boolean; // @todo: do something with this
onError?: (errors: s.ErrorDetail[]) => void;
};
export const cloneSchema = <S extends s.Schema>(schema: S): S => {
const json = schema.toJSON();
return s.fromSchema(json) as S;
};
export function parse<S extends s.Schema, Options extends ParseOptions = ParseOptions>(
_schema: S,
v: unknown,
opts?: Options,
): Options extends { coerce: true } ? s.StaticCoerced<S> : s.Static<S> {
const schema = (opts?.clone ? cloneSchema(_schema as any) : _schema) as s.Schema;
let value = opts?.coerce !== false ? schema.coerce(v) : v;
if (opts?.withDefaults !== false) {
value = schema.template(value, {
withOptional: true,
withExtendedOptional: opts?.withExtendedDefaults ?? false,
});
}
const result = _schema.validate(value, {
shortCircuit: true,
ignoreUnsupported: true,
});
if (!result.valid) {
if (opts?.onError) {
opts.onError(result.errors);
} else {
throw new InvalidSchemaError(schema, v, result.errors);
}
}
return value as any;
}