UNPKG

verdict-rules

Version:

A small, zero-dependency, async-native rule-evaluation engine. Compose conditions into one explainable pass/fail verdict, with sequential evaluation and real short-circuiting as a guarantee.

214 lines (209 loc) • 7.81 kB
"use strict"; var VerdictRules = (() => { var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); // src/index.ts var index_exports = {}; __export(index_exports, { AndRule: () => AndRule, FunctionRule: () => FunctionRule, OrRule: () => OrRule, RulesEngine: () => RulesEngine, UnknownLookupError: () => UnknownLookupError }); // src/errors.ts var UnknownLookupError = class extends Error { constructor(kind, key) { super( kind === "rule" ? `No rule named '${key}' in this engine` : `No rules in group '${key}' in this engine` ); /** Whether the missing thing was a rule name or a group label. */ __publicField(this, "kind"); /** The name or label that matched nothing. */ __publicField(this, "key"); this.name = "UnknownLookupError"; this.kind = kind; this.key = key; } }; // src/engine.ts var _rules, _byName, _byGroup; var RulesEngine = class { constructor(rules) { __privateAdd(this, _rules); __privateAdd(this, _byName); __privateAdd(this, _byGroup); __privateSet(this, _rules, [...rules]); __privateSet(this, _byName, new Map(rules.map((r) => [r.name, r]))); __privateSet(this, _byGroup, /* @__PURE__ */ new Map()); for (const rule of rules) { if (rule.group === void 0 || rule.group === "") continue; const existing = __privateGet(this, _byGroup).get(rule.group); if (existing === void 0) __privateGet(this, _byGroup).set(rule.group, [rule]); else existing.push(rule); } } /** Every rule name registered here, in registration order. */ get ruleNames() { return [...__privateGet(this, _byName).keys()]; } /** Every group label carried by at least one rule, in first-seen order. */ get groupNames() { return [...__privateGet(this, _byGroup).keys()]; } /** Evaluate every registered rule. Never short-circuits. */ async runAll(context) { const results = []; for (const rule of __privateGet(this, _rules)) { results.push(await rule.evaluate(context)); } return { passed: results.every((r) => r.passed), results }; } /** * Evaluate one rule by name, or return `undefined` if no such rule exists. * * `undefined` means absent, never failed. */ async tryRunNamed(name, context) { const rule = __privateGet(this, _byName).get(name); if (rule === void 0) return void 0; return rule.evaluate(context); } /** * Evaluate exactly one rule, looked up by name. * * @throws {UnknownLookupError} if no rule has this name. */ async runNamed(name, context) { const result = await this.tryRunNamed(name, context); if (result === void 0) { throw new UnknownLookupError("rule", name); } return result; } /** * Evaluate a group, or return `undefined` if no such group exists. * * `undefined` means absent, never vacuously passed. */ async tryRunGroup(group, context) { const rules = __privateGet(this, _byGroup).get(group); if (rules === void 0 || rules.length === 0) return void 0; const results = []; for (const rule of rules) { results.push(await rule.evaluate(context)); } return { passed: results.every((r) => r.passed), results }; } /** * Evaluate every rule sharing a group label. Never short-circuits. * * @throws {UnknownLookupError} if no rule carries this label. */ async runGroup(group, context) { const result = await this.tryRunGroup(group, context); if (result === void 0) { throw new UnknownLookupError("group", group); } return result; } }; _rules = new WeakMap(); _byName = new WeakMap(); _byGroup = new WeakMap(); // src/rule.ts var _predicate; var FunctionRule = class { constructor(name, predicate, group) { __publicField(this, "name"); __publicField(this, "group"); __privateAdd(this, _predicate); this.name = name; this.group = group; __privateSet(this, _predicate, predicate); } /** Runs the wrapped predicate and returns whatever it returns, unchanged. */ evaluate(context) { return __privateGet(this, _predicate).call(this, context); } }; _predicate = new WeakMap(); var _rules2; var AndRule = class { constructor(name, rules, group) { __publicField(this, "name"); __publicField(this, "group"); __privateAdd(this, _rules2); this.name = name; this.group = group; __privateSet(this, _rules2, rules); } async evaluate(context) { const subResults = []; for (const rule of __privateGet(this, _rules2)) { const result = await rule.evaluate(context); subResults.push(result); if (!result.passed) { const detail = result.detail ? `'${rule.name}' failed: ${result.detail}` : `'${rule.name}' failed`; return { ruleName: this.name, passed: false, detail, data: subResults }; } } return { ruleName: this.name, passed: true, data: subResults }; } }; _rules2 = new WeakMap(); var _rules3; var OrRule = class { constructor(name, rules, group) { __publicField(this, "name"); __publicField(this, "group"); __privateAdd(this, _rules3); this.name = name; this.group = group; __privateSet(this, _rules3, rules); } async evaluate(context) { const subResults = []; for (const rule of __privateGet(this, _rules3)) { const result = await rule.evaluate(context); subResults.push(result); if (result.passed) { return { ruleName: this.name, passed: true, data: subResults }; } } return { ruleName: this.name, passed: false, detail: "no sub-rule passed", data: subResults }; } }; _rules3 = new WeakMap(); return __toCommonJS(index_exports); })(); //# sourceMappingURL=verdict-rules.global.js.map