UNPKG

valia

Version:

A runtime data validator in TypeScript with advanced type inference, built-in validation functions, and seamless integration for server and client environments.

182 lines (145 loc) 4.84 kB
import type { SetableCriteria, FormatTemplate, SetableCriteriaTemplate } from "./formats"; import type { Constructor } from "../types"; import type { SchemaType } from "./types"; import { Schema } from "./schema"; import { Issue } from "../utils"; import { ClassicTypesTemplate, GenericTypesTemplate } from "./formats/types"; export abstract class AbstractPlugin<const T extends SetableCriteria> extends Schema<T> { /** * This method is automatically called before the schema initialization. * * This allows, for example, to subscribe to events that will occur * during the initialization. */ protected abstract beforeInitate(): void; /** * This method is automatically called after the schema initialization. */ protected abstract afterInitate(): void; constructor(...args: ConstructorParameters<SchemaType<T>>) { super(...args); this.beforeInitate(); this.initiate(args[0]); this.afterInitate(); } } function assignProperties( source: Constructor, target: Constructor, transformKey?: (key: string) => string | undefined ) { const srcPrototypeDescriptors = Object.getOwnPropertyDescriptors(source.prototype); const srcDescriptors = Object.getOwnPropertyDescriptors(source); for (const key in srcPrototypeDescriptors) { if (key === "constructor") continue; let newKey = transformKey?.(key) || key; if (newKey in target.prototype) { throw new Error(`Property key conflict in prototype properties.\nConflictual key: '${key}'`); } Object.defineProperty(target.prototype, newKey, srcPrototypeDescriptors[key]); } for (const key in srcDescriptors) { if (["prototype", "length", "name"].includes(key)) continue; let newKey = transformKey?.(key) || key; if (newKey in target) { throw Error(`Property key conflict in static properties.\nConflictual key: '${key}'`); } Object.defineProperty(target, newKey, srcPrototypeDescriptors[key]); } } export function SchemaPlugins<T, U, V, W, X, Y>( plugin_1: new (...args: T[]) => U, plugin_2?: new (...args: V[]) => W, plugin_3?: new (...args: X[]) => Y ) { try { const plugins = [plugin_1, plugin_2, plugin_3]; const beforeInitKeys: string[] = []; const afterInitKeys: string[] = []; const pluggedSchema = class PluggedSchema<T extends SetableCriteria> extends Schema<T> { constructor(criteria: T) { super(criteria); // METHODE CALL BEFORE INITIATION for (const key of beforeInitKeys) { (this[key as keyof typeof this] as () => any)(); } this.initiate(criteria); // METHODE CALL AFTER INITIATION for (const key of afterInitKeys) { (this[key as keyof typeof this] as () => any)(); } } } const transformKey = (key: string) => { if (key === "beforeInitate") { const newKey = "beforeInitate_" + beforeInitKeys.length; beforeInitKeys.push(newKey); return (newKey); } if (key === "afterInitate") { const newKey = "afterInitate_" + afterInitKeys.length; afterInitKeys.push(newKey); return (newKey); } } for (const plugin of plugins) { if (!plugin) break; assignProperties(plugin, pluggedSchema, transformKey); } return (pluggedSchema) as new (...args: T[] & V[] & X[]) => U & W & Y; } catch (err) { if (err instanceof Error) throw new Issue("Schema plugins", err.message); throw err; } } /* export interface ObjectIdSetableCriteria extends SetableCriteriaTemplate<"objectId"> { unique: boolean; } export interface ObjectIdClassicTypes extends ClassicTypesTemplate< ObjectIdSetableCriteria, {} > {} export interface ObjectIdGenericTypes extends GenericTypesTemplate< {}, {} > {} declare module './formats/types' { interface FormatClassicTypes { objectId: ObjectIdClassicTypes; } interface FormatGenericTypes<T extends SetableCriteria> { objectId: T extends ObjectIdSetableCriteria ? ObjectIdGenericTypes : never; } } const ObjectId: FormatTemplate<ObjectIdSetableCriteria> = { defaultCriteria: {}, mounting(queue, path, criteria) { }, checking(queue, path, criteria, value) { return (null); } } class Mongo<T extends SetableCriteria> extends AbstractPlugin<T> { protected beforeInitate(): void { this.managers.formats.set({ objectId: ObjectId }); } protected afterInitate(): void { } constructor(...args: ConstructorParameters<SchemaType<T>>) { super(...args) } } class Maria<T extends SetableCriteria> extends AbstractPlugin<T> { protected beforeInitate(): void { } protected afterInitate(): void { } constructor(...args: ConstructorParameters<SchemaType<T>>) { super(...args) } } const test = SchemaPlugins(Mongo, Maria) const eerer = new test({ type: "struct", struct: { test: { type: "objectId", unique: true }}}) console.log(eerer.evaluate({ test: "df"})) //const lala = new Schema({ type: "struct", struct: { test: { type: 'boolean' }}})*/