### Running Specific Examples Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Commands to execute individual example scripts. ```bash npm run example:checkout npm run example:authorization npm run example:attendance ``` -------------------------------- ### Clone and run locally Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Clone the rulewrite repository and install dependencies to run locally. ```bash git clone https://github.com/your-org/rulewrite.git cd rulewrite npm install ``` -------------------------------- ### Install rulewrite via npm Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Install the rulewrite library as a project dependency using npm. ```bash npm install @daltonr/rulewrite ``` -------------------------------- ### Quick start: Define and compose rules Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Demonstrates defining atomic rules for user attributes and composing them using logical operators. ```typescript import { rule } from '@daltonr/rulewrite'; const isAdult = rule(u => u.age >= 18, 'IsAdult'); const isVerified = rule(u => u.emailVerified, 'IsVerified'); const canRegister = isAdult.and(isVerified); canRegister.isSatisfiedBy(user); // boolean canRegister.evaluate(user); // full evaluation tree ``` -------------------------------- ### Evaluate a rule and get a structured result Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Evaluates a composed rule and returns a detailed tree representing the resolution of each sub-rule. ```typescript const result = canPurchase.evaluate({ customer, product }); result.satisfied // boolean result.label // 'AND' result.children // per-operand results, recursively ``` -------------------------------- ### Building the Project Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Command to compile the project into distributable formats. ```bash npm run build # compile to dist/ (esm + cjs + .d.ts) ``` -------------------------------- ### Build the package Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Compile the rulewrite package for distribution. ```bash npm run build ``` -------------------------------- ### Running Tests Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Commands to execute the project's test suite. ```bash npm test # run all tests once npm run test:watch # run tests in watch mode npm run typecheck # type-check without emitting ``` -------------------------------- ### Project Structure Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Overview of the source code directories and their contents. ```tree src/ index.ts — public API: rule(), all(), any(), Rule, EvaluationResult types.ts — Rule and EvaluationResult interfaces base-rule.ts — BaseRule abstract class + all concrete implementations atomic-rule.ts — AtomicRule: a leaf rule wrapping a predicate lambda operators/ — re-exports from base-rule.ts (AndRule, OrRule, etc.) combinators/ — re-exports from base-rule.ts (SomeOfRule, AllOfRule, etc.) tests/ rule.test.ts — atomic rule basics operators.test.ts — truth table tests for all binary/unary operators combinators.test.ts — on(), someOf, allOf, noneOf tests properties.test.ts — property-based tests using fast-check examples/ checkout.ts — e-commerce checkout policy authorization.ts — document access control attendance.ts — venue attendance rules ``` -------------------------------- ### Write Truth Table Tests for XOR Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Implement example-based tests in `tests/operators.test.ts` to verify the truth table of the XOR operator for all combinations of true and false inputs. ```typescript describe('XOR operator', () => { it('TT → false', () => expect(T.xor(T).isSatisfiedBy(v)).toBe(false)); it('TF → true', () => expect(T.xor(F).isSatisfiedBy(v)).toBe(true)); it('FT → true', () => expect(F.xor(T).isSatisfiedBy(v)).toBe(true)); it('FF → false', () => expect(F.xor(F).isSatisfiedBy(v)).toBe(false)); }); ``` -------------------------------- ### Type-check without building Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Perform type checking on the project without initiating a full build process. ```bash npm run typecheck ``` -------------------------------- ### Project rules into a wider context Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Uses the '.on()' method to adapt a rule defined for one type to operate within a broader context type. ```typescript type OrderContext = { customer: User; product: Product }; const customerIsAdult = isAdult.on((ctx: OrderContext) => ctx.customer); const customerIsVerified = isVerified.on((ctx: OrderContext) => ctx.customer); const canPurchase = customerIsAdult.and(customerIsVerified); canPurchase.isSatisfiedBy({ customer, product }); ``` -------------------------------- ### Run tests in watch mode Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Run tests continuously, re-executing them automatically on file changes. ```bash npm run test:watch ``` -------------------------------- ### Short-Circuiting Behavior for AND Operator Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Demonstrates how the AND operator short-circuits when the left operand is false. ```markdown | Operator | Short-circuits when | |---|---| | AND | left is `false` | returns `false`, right not evaluated | ``` -------------------------------- ### rule(predicate, label) Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Creates an atomic rule. This is the fundamental building block for defining individual business rules. ```APIDOC ## rule(predicate, label) ### Description Creates an atomic rule. This is the fundamental building block for defining individual business rules. ### Signature ```typescript function rule(predicate: (value: T) => boolean, label: string): Rule ``` ### Parameters #### Path Parameters - **predicate** ((value: T) => boolean) - Required - A function that takes a value of type T and returns true if the rule is satisfied, false otherwise. - **label** (string) - Required - A descriptive name for the rule, used in evaluation output. ``` -------------------------------- ### Rule Class Hierarchy Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Abstract and concrete rule classes, showing inheritance and composition capabilities. ```tree Rule (interface, src/types.ts) └── BaseRule (abstract, src/base-rule.ts) ├── AtomicRule — leaf: wraps a predicate lambda ├── AndRule — binary AND with short-circuit ├── OrRule — binary OR with short-circuit ├── NotRule — unary NOT ├── ImpliesRule — A => B (≡ !A || B) ├── PreventsRule — NAND (≡ !(A && B)) ├── AllRules — variadic AND, flat tree ├── AnyRules — variadic OR, flat tree ├── ProjectedRule — lifts Rule into Rule via a selector ├── SomeOfRule — applies Rule across a collection ├── AllOfRule — all items in collection must satisfy Rule └── NoneOfRule — no items in collection may satisfy Rule ``` -------------------------------- ### Short-Circuiting Behavior for OR Operator Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Demonstrates how the OR operator short-circuits when the left operand is true. ```markdown | Operator | Short-circuits when | |---|---| | OR | left is `true` | returns `true`, right not evaluated | ``` -------------------------------- ### Compose rules using logical operators Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Chains multiple rules together using logical operators like 'and', 'or', 'implies', and 'prevents'. ```typescript const eligible = isAdult.and(isVerified).and(isActive); const allowed = isOwner.or(isAdmin); const flagged = hasPendingPayment.prevents(canWithdraw); const policy = containsAlcohol.implies(isAgeVerified); ``` -------------------------------- ### Short-Circuiting Behavior for IMPLIES Operator Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Demonstrates how the IMPLIES operator short-circuits when the antecedent is false. ```markdown | Operator | Short-circuits when | |---|---| | IMPLIES | antecedent is `false` | returns `true`, consequent not evaluated | ``` -------------------------------- ### Short-Circuiting Behavior for PREVENTS Operator Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Demonstrates how the PREVENTS operator short-circuits when the left operand is false. ```markdown | Operator | Short-circuits when | |---|---| | PREVENTS | left is `false` | returns `true`, right not evaluated | ``` -------------------------------- ### Rule Interface Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Defines the methods available on a rule object for composition and evaluation. ```APIDOC ## Rule Interface ### Description Defines the methods available on a rule object for composition and evaluation. ### Interface Definition ```typescript interface Rule { isSatisfiedBy(value: T): boolean; evaluate(value: T): EvaluationResult; and(other: Rule): Rule; or(other: Rule): Rule; not(): Rule; implies(other: Rule): Rule; prevents(other: Rule): Rule; on(selector: (ctx: C) => T): Rule; someOf(selector: (ctx: C) => T[]): Rule; allOf(selector: (ctx: C) => T[]): Rule; noneOf(selector: (ctx: C) => T[]): Rule; } ``` ### Methods #### Evaluation - **isSatisfiedBy**(value: T): boolean - Checks if the rule is satisfied by the given value. - **evaluate**(value: T): EvaluationResult - Returns a structured tree showing how the rule and its sub-rules were resolved. #### Composition - **and**(other: Rule): Rule - Combines the current rule with another rule using a logical AND. - **or**(other: Rule): Rule - Combines the current rule with another rule using a logical OR. - **not**(): Rule - Negates the current rule. - **implies**(other: Rule): Rule - Creates a rule that is satisfied if the current rule is not satisfied, or if the other rule is satisfied (A implies B). - **prevents**(other: Rule): Rule - Creates a rule that is satisfied if both the current rule and the other rule are not satisfied (NAND). #### Projection and Collection - **on**(selector: (ctx: C) => T): Rule - Projects the rule into a wider context type C using a selector function. - **someOf**(selector: (ctx: C) => T[]): Rule - Applies the rule to at least one item in a collection selected from context C. - **allOf**(selector: (ctx: C) => T[]): Rule - Applies the rule to all items in a collection selected from context C. - **noneOf**(selector: (ctx: C) => T[]): Rule - Applies the rule to no items in a collection selected from context C. ``` -------------------------------- ### Implement XorRule Class Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Add the XorRule class to `src/base-rule.ts` to implement the XOR binary operator. This class extends `BaseRule` and defines the logic for `isSatisfiedBy` and `evaluate` methods. ```typescript // ─── XOR ───────────────────────────────────────────────────────────────────── export class XorRule extends BaseRule { constructor(private readonly left: Rule, private readonly right: Rule) { super(); } isSatisfiedBy(value: T): boolean { return this.left.isSatisfiedBy(value) !== this.right.isSatisfiedBy(value); } evaluate(value: T): EvaluationResult { const leftResult = this.left.evaluate(value); const rightResult = this.right.evaluate(value); return { satisfied: leftResult.satisfied !== rightResult.satisfied, label: 'XOR', children: [leftResult, rightResult], }; } } ``` -------------------------------- ### Apply rules across collections Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Uses collection combinators like '.someOf()', '.allOf()', and '.noneOf()' to apply a rule to elements within a collection. ```typescript type Team = { members: User[] }; const anyAdult = isAdult.someOf(t => t.members); const allAdults = isAdult.allOf(t => t.members); const noAdults = isAdult.noneOf(t => t.members); ``` -------------------------------- ### Define a rule directly on the context Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Creates a rule that operates directly on the properties of a wider context type. ```typescript const withinBudget = rule( ctx => ctx.product.price <= ctx.customer.creditLimit, 'WithinBudget' ); ``` -------------------------------- ### Add XOR Method to BaseRule Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Extend `BaseRule` by adding the `xor` method, which creates a new `XorRule` instance. This method allows chaining XOR operations. ```typescript xor(other: Rule): Rule { return new XorRule(this, other); } ``` -------------------------------- ### EvaluationResult Interface Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Represents the result of evaluating a rule, including satisfaction status, label, and children results. ```APIDOC ## EvaluationResult Interface ### Description Represents the result of evaluating a rule, including satisfaction status, label, and children results. ### Interface Definition ```typescript interface EvaluationResult { satisfied: boolean; label: string; children?: EvaluationResult[]; } ``` ### Fields - **satisfied** (boolean) - Indicates whether the rule or sub-rule was satisfied. - **label** (string) - The label of the rule that was evaluated. - **children** (EvaluationResult[]) - Optional. An array of evaluation results for sub-rules, present for composed rules. ``` -------------------------------- ### Write Property Test for XOR Equivalence Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Add a property-based test in `tests/properties.test.ts` to assert that the XOR operator is equivalent to `(A OR B) AND NOT(A AND B)`. This test uses `fast-check` to validate the logical law across various boolean inputs. ```typescript it('XOR ≡ (A OR B) AND NOT(A AND B)', () => { fc.assert(fc.property(fc.boolean(), fc.boolean(), (a, b) => { const [A, B] = [atom(a), atom(b)]; return A.xor(B).isSatisfiedBy(v) === A.or(B).and(A.and(B).not()).isSatisfiedBy(v); })); }); ``` -------------------------------- ### Rule interface definition Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Defines the methods available on a Rule object for evaluation, composition, and projection. ```typescript interface Rule { isSatisfiedBy(value: T): boolean; evaluate(value: T): EvaluationResult; and(other: Rule): Rule; or(other: Rule): Rule; not(): Rule; implies(other: Rule): Rule; prevents(other: Rule): Rule; on(selector: (ctx: C) => T): Rule; someOf(selector: (ctx: C) => T[]): Rule; allOf(selector: (ctx: C) => T[]): Rule; noneOf(selector: (ctx: C) => T[]): Rule; } ``` -------------------------------- ### Define an atomic rule Source: https://github.com/richardadalton/rulewrite/blob/main/README.md Creates a single, named rule based on a predicate function and a descriptive label. ```typescript const isActive = rule(a => a.status === 'active', 'IsActive'); ``` -------------------------------- ### EvaluationResult Interface Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Defines the structure of the result returned by rule evaluation, including satisfaction status and hierarchical children. ```typescript interface EvaluationResult { satisfied: boolean; label: string; children?: EvaluationResult[]; } ``` -------------------------------- ### Add XOR Signature to Rule Interface Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md Update the `Rule` interface in `src/types.ts` by adding the signature for the `xor` method. This ensures type safety for XOR operations. ```typescript xor(other: Rule): Rule; ``` -------------------------------- ### Invariant: evaluate() vs isSatisfiedBy() Source: https://github.com/richardadalton/rulewrite/blob/main/DEVELOPER.md This invariant must hold for all inputs and compositions, including deeply nested ones. Property tests verify this key invariant that every operator must satisfy. ```typescript evaluate(value).satisfied === isSatisfiedBy(value) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.