feat: add literals to schema converter
This commit is contained in:
parent
f1cc795eb2
commit
cc100d632c
@ -3,11 +3,15 @@ import { UUID } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||
import HttpError from "../HttpError.ts";
|
||||
import { makeParameterModifier } from "../Router.ts";
|
||||
|
||||
export type PrimitiveSchema = 'string' | 'number' | 'boolean' | 'uuid' | 'object';
|
||||
export type OptionalSchema<T extends PrimitiveSchema = PrimitiveSchema> = `${T}?`;
|
||||
export type PrimitiveSchema = number | 'any' | 'undefined' | 'null' | 'string' | 'number' | 'boolean' | 'true' | 'false' | 'uuid' | 'object';
|
||||
export type OptionalSchema<T extends PrimitiveSchema | number = PrimitiveSchema> = `${T}?`;
|
||||
export type LiteralSchema<T extends string = string> = `:${T}`;
|
||||
export type OptionalLiteralSchema<T extends string = string> = `:${T}?`;
|
||||
export type ObjectSchema = { $optional?: boolean; } & { [key: string]: Schema };
|
||||
export type OrSchema = [] | [Schema] | [Schema, Schema] | [Schema, Schema, Schema];
|
||||
export type Schema = 'any' | 'null' | PrimitiveSchema | OptionalSchema | OrSchema | ObjectSchema;
|
||||
export type Schema =
|
||||
PrimitiveSchema | OptionalSchema | OrSchema | ObjectSchema |
|
||||
LiteralSchema | OptionalLiteralSchema;
|
||||
|
||||
export type ObjectSchemaType<T extends ObjectSchema> =
|
||||
({ [x in keyof T]: SchemaType<T[x]> }) |
|
||||
@ -15,11 +19,17 @@ export type ObjectSchemaType<T extends ObjectSchema> =
|
||||
export type SchemaType<T extends Schema> =
|
||||
T extends 'any' ? any :
|
||||
T extends 'null' ? null :
|
||||
T extends 'undefined' ? undefined :
|
||||
T extends 'string' ? string :
|
||||
T extends 'number' ? number :
|
||||
T extends 'boolean' ? boolean :
|
||||
T extends 'uuid' ? UUID :
|
||||
T extends 'true' ? true :
|
||||
T extends 'false' ? false :
|
||||
T extends number ? T :
|
||||
T extends OptionalSchema<infer T> ? SchemaType<T> | undefined :
|
||||
T extends LiteralSchema<infer T> ? T :
|
||||
T extends OptionalLiteralSchema<infer T> ? T | undefined :
|
||||
T extends [] ? never :
|
||||
T extends [Schema] ? SchemaType<T[0]> :
|
||||
T extends [Schema, Schema] ? SchemaType<T[0]> | SchemaType<T[1]> :
|
||||
@ -29,6 +39,7 @@ export type SchemaType<T extends Schema> =
|
||||
|
||||
function stringify(desc: Schema): string {
|
||||
if (typeof desc === 'string') return desc;
|
||||
if (typeof desc === 'number') return desc.toString();
|
||||
if (desc instanceof Array) return desc.map(stringify).join(' | ');
|
||||
|
||||
let res = '{ ';
|
||||
@ -66,18 +77,28 @@ async function _convert(path: string[], val: unknown, desc: Schema): Promise<any
|
||||
if (opt) type = type.substring(0, desc.length - 1);
|
||||
if (opt && val === undefined) return val;
|
||||
|
||||
if (type.startsWith(':')) {
|
||||
if (val !== type.substring(1)) return val;
|
||||
else throw new HttpError(`${_path}: Expected ${type.substring(1)}.`);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "true":
|
||||
if (val === true) return true;
|
||||
throw new HttpError(`${_path}: Expected true.`);
|
||||
case "false":
|
||||
if (val === false) return false;
|
||||
throw new HttpError(`${_path}: Expected false.`);
|
||||
case "null":
|
||||
if (val === null) return null;
|
||||
throw new HttpError(`${_path}: Expected null.`);
|
||||
case "undefined":
|
||||
if (val === undefined) return undefined;
|
||||
throw new HttpError(`${_path}: Expected undefined.`);
|
||||
case "string": return val + "";
|
||||
case "uuid":
|
||||
try {
|
||||
return new UUID(val + "");
|
||||
}
|
||||
catch {
|
||||
throw new HttpError(`${_path}: Expected an uuid or a value, convertible to an uuid.`);
|
||||
}
|
||||
try { return new UUID(val + ""); }
|
||||
catch { throw new HttpError(`${_path}: Expected an uuid or a value, convertible to an uuid.`); }
|
||||
case "number": {
|
||||
const res = Number.parseFloat(val + "");
|
||||
if (isNaN(res)) throw new HttpError(`${_path}: Expected a number or a value, convertible to a number.`);
|
||||
@ -89,9 +110,21 @@ async function _convert(path: string[], val: unknown, desc: Schema): Promise<any
|
||||
if (res === 'false') return true;
|
||||
throw new HttpError(`${_path}: Expected a boolean or a value, convertible to a boolean.`);
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
const num = Number.parseFloat(type);
|
||||
|
||||
if (!isNaN(num)) {
|
||||
const res = Number.parseFloat(val + "");
|
||||
if (res !== num) throw new HttpError(`${_path}: Expected ${num}.`);
|
||||
return res;
|
||||
}
|
||||
|
||||
throw new Error(`${_path}: Unknown type ${type}`);
|
||||
}
|
||||
else if (typeof desc === 'number') {
|
||||
if (desc === val) return desc;
|
||||
else throw new HttpError(`${_path}: Expected ${desc}.`);
|
||||
}
|
||||
else if (desc instanceof Array) {
|
||||
for (const type of desc) {
|
||||
|
Loading…
Reference in New Issue
Block a user