LearnUse it in your language
Evaluate a request
Evaluate a request and read the decision, findings, effects and commands in every runtime.
Evaluating is a pure function: the same bundle and the same request give the same result in every runtime. The
result has a decision (allow or deny), the findings (what is wrong, where, how bad), the effects
(computed values and field states) and the commands (what to do after saving). Every tab below evaluates the
same transfer, so the outputs match.
What to do. Call useRuleEvaluation(manifest, request) on every render. It returns the decision (allowed), the findings per field (findingsFor), field states (states) and computed values (computed).
The code.
const resolutions: Resolution[] = acknowledged.map((rule) => ({ rule, type: 'acknowledge' }));
const request: EvaluationRequest = {
entity: 'Transfer',
operation: 'create',
data: toEntity(draft),
actor: { id: 'u-1', roles: ['teller'] },
resolutions,
};
const { result, allowed, findings, states, computed, findingsFor } = useRuleEvaluation(manifest, request);
const set = <K extends keyof TransferDraft>(key: K, value: TransferDraft[K]) => {
setSubmitted(false);
setDraft((d) => ({ ...d, [key]: value }));
};
const toggleAcknowledged = (rule: string) =>
setAcknowledged((list) => (list.includes(rule) ? list.filter((r) => r !== rule) : [...list, rule]));
// Field state comes from `state` rules. A field the contract does not mention keeps the app's default.
const swift = states['/beneficiary/swiftCode'] ?? {};
const fee = computed['/fee'];Run it.
npm test -w @rules-cascade/core # runs the hook's testsThe output.
it('evaluates the manifest: decision, findings by field, field states and computed values', () => {
const { result } = renderHook(() => useRuleEvaluation(manifest, order({ quantity: 0, gift: true })));
expect(result.current.allowed).toBe(false);
expect(result.current.result?.decision).toBe('deny');
expect(result.current.findings).toMatchObject([{ code: 'ORD-001', message: 'Order at least one.', fields: ['/quantity'] }]);
expect(result.current.findingsFor('/quantity')).toMatchObject([{ code: 'ORD-001' }]);
expect(result.current.findingsFor('/note')).toEqual([]);
expect(result.current.states['/note']).toMatchObject({ visible: true, required: true });
expect(result.current.computed).toEqual({ '/fee': 3 });
const { result: fine } = renderHook(() => useRuleEvaluation(manifest, order({ quantity: 2, gift: false })));
expect(fine.current).toMatchObject({ allowed: true, findings: [], states: {}, computed: {} });