UNPKG

standard-rule-engine

Version:

A simple rule engine that uses Standard Schema to validate facts

110 lines (106 loc) 4.65 kB
import { StandardSchemaV1 } from '@standard-schema/spec'; interface EngineSingletonBase { context: Record<string, unknown>; globalSchema: StandardSchemaV1 | undefined; helpers: Record<string, Function>; } type Prettify<T> = { [K in keyof T]: T[K]; } & {}; type RecordKey = string | number | symbol; type Reconcile<A extends Object, B extends Object, Override extends boolean = false, Stack extends number[] = []> = Stack["length"] extends 16 ? A : Override extends true ? { [key in keyof A as key extends keyof B ? never : key]: A[key]; } extends infer Collision ? {} extends Collision ? { [key in keyof B]: IsBothObject<A[key], B[key]> extends true ? Reconcile<A[key], B[key], Override, [ 0, ...Stack ]> : B[key]; } : Prettify<Collision & { [key in keyof B]: B[key]; }> : never : { [key in keyof B as key extends keyof A ? never : key]: B[key]; } extends infer Collision ? {} extends Collision ? { [key in keyof A]: IsBothObject<A[key], B[key]> extends true ? Reconcile<A[key], B[key], Override, [ 0, ...Stack ]> : A[key]; } : Prettify<{ [key in keyof A]: A[key]; } & Collision> : never; type IsBothObject<A, B> = A extends Record<RecordKey, unknown> ? B extends Record<RecordKey, unknown> ? IsClass<A> extends false ? IsClass<B> extends false ? true : false : false : false : false; type IsClass<V> = V extends abstract new (...args: any) => any ? true : false; type DeepReadonly<T> = T extends Function ? T : T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>> : T extends object ? { readonly [P in keyof T]: DeepReadonly<T[P]>; } : T; type AnyEngine = Engine<any>; type Rule = { name: string; priority: number; handler: (...args: any[]) => void; schema?: StandardSchemaV1; }; declare class Session<Context extends Record<string, unknown>, Helpers extends Record<string, Function>> { context: Context; private rules; private insertedFacts; private wrappedHelpers; constructor(context: Context, rules: Rule[], helpers?: Helpers); insert(facts: unknown): this; insertMany(facts: unknown[]): this; fire(): this; } declare class Engine<const in out Singleton extends EngineSingletonBase = { context: {}; globalSchema: undefined; helpers: {}; }> { "~types": { Singleton: Singleton; }; private initialContext; private rules; private globalSchema; private helpers; schema<const GlobalFactsSchema extends StandardSchemaV1>(schema: GlobalFactsSchema): Engine<{ context: Singleton["context"]; globalSchema: GlobalFactsSchema; helpers: Singleton["helpers"]; }>; context<const Name extends string | number | symbol, Value>(name: Name, value: Value): Engine<{ context: Reconcile<Singleton["context"], { [key in Name]: Value; }>; globalSchema: Singleton["globalSchema"]; helpers: Singleton["helpers"]; }>; context<IncomingContext extends Record<string, unknown>>(context: IncomingContext): Engine<{ context: Reconcile<Singleton["context"], IncomingContext>; globalSchema: Singleton["globalSchema"]; helpers: Singleton["helpers"]; }>; helper<const Name extends string, Args extends any[], ReturnType>(name: Name, fn: (context: Singleton["context"], ...args: Args) => ReturnType): Engine<{ context: Singleton["context"]; globalSchema: Singleton["globalSchema"]; helpers: Singleton["helpers"] & { [key in Name]: (...args: Args) => ReturnType; }; }>; rule<const RuleName extends string, const FactsSchema extends Singleton["globalSchema"] extends undefined ? StandardSchemaV1 | undefined : Singleton["globalSchema"]>(name: RuleName, handler: (facts: DeepReadonly<FactsSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<FactsSchema> : unknown>, { context, helpers, }: { context: Singleton["context"]; helpers: Singleton["helpers"]; }) => void, meta?: { schema?: FactsSchema; priority?: number; }): Engine<{ context: Singleton["context"]; globalSchema: Singleton["globalSchema"]; helpers: Singleton["helpers"]; }>; use<const NewEngine extends AnyEngine>(instance: NewEngine): Engine<{ context: Singleton["context"] & NewEngine["~types"]["Singleton"]["context"]; globalSchema: Singleton["globalSchema"]; helpers: Singleton["helpers"] & NewEngine["~types"]["Singleton"]["helpers"]; }>; createSession(): Session<Singleton["context"], Singleton["helpers"]>; } export { type AnyEngine, Engine };