Rule Cascade
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.

examples/frontend-react/src/TransferForm.tsx
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.

Run it
npm test -w @rules-cascade/core      # runs the hook's tests

The output.

packages/client/test/react.test.ts (what CI checks)
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: {} });
Try it YourselfRuns in your browser with the TypeScript engine. Nothing to install.
Course overview