Table of Contents

Release notes

RuleWright follows semantic versioning. Before 1.0, a minor version may contain a breaking change, and each one is called out here. The complete, detailed history is CHANGELOG.md in the repository.

Unreleased

These are in the source this site documents, and will ship in the next release.

Added

  • Scoped params. params on a rule set (global) or a rule (local, shadowing) names an expression once; { "param": "…" } references it anywhere an expression is valid. References are inlined at load, cycles and unknown names are pointer-addressed validation errors. See Scoped params.
  • Value functions. RegisterValueFunction plus the { "call": …, "operands": […] } expression node: registered C# computations callable from action values, computed left-hand sides and decision-table cells. Unknown names — and wrong operand counts, when the function declares a required count via IRuleValueFunctionMetadata — fail at LoadRuleSet. See Value functions.
  • Custom actions. RegisterAction(name, handler) adds action types beyond the built-in four; the handler's RuleActionContext reads and writes the running outputs on both execution paths, and validation folds registered names into the closed vocabulary (RuleSetValidator.Validate and RuleSetParser.Parse gained RuleDocumentOptions overloads). See Custom actions.
  • Failure messages. A rule's failureMessage surfaces on RuleEvaluationResult.Failures when the rule is evaluated and its condition doesn't hold. See Rule sets.
  • Named multi-fact evaluation. RuleFacts.With("customer", c).And("order", o) evaluates several named facts as one, each addressed by its name as the first path segment. See Typed and dictionary facts.
  • Rule-set composition. RuleSet.Merge(sets, name, stopAfterFirstMatch) combines sets at load time, with duplicate rule ids failing loudly. See Build rules in C#.
  • Engine discovery for the new registrations. RegisteredValueFunctions, ValueFunctionCatalog and RegisteredActions, beside the existing function catalog. See Discover the vocabulary.
  • Four new example documents (22–25), and the JSON Schema now describes params, failureMessage and the call/param expression nodes.
  • Case-insensitive JSON facts, opt-in. SystemTextJsonFacts.ToDictionary(element, keyComparer) and NewtonsoftJsonFacts.ToDictionary(token, keyComparer) build every level of a fact with the comparer you give, so StringComparer.OrdinalIgnoreCase lets Order.Total match camelCase JSON. Keys that collide under the comparer throw ArgumentException. The one-argument overloads are unchanged. See Typed and dictionary facts.

Fixed (documentation)

  • The first two examples in the repository's usage.md used facts whose shape didn't match their rules.

0.3.0

The first release since 0.1.1. It includes everything listed for 0.2.0, which was never published.

Important

Breaking: Rulewright is now RuleWright everywhere: package ids, assembly names and namespaces. using Rulewright.Core; becomes using RuleWright.Core;, and because the assembly names changed, you must recompile. Rule documents are unchanged.

Added

  • Collection quantifiers Any, All and None, with "$" for the element itself, and the count expression operator. See Collections.
  • ConditionLeaf.Quantifier(...), ConditionLeaf.ElementCondition, OperatorValueKind.Condition, ConditionOperatorInfo.RequiresElementCondition and ExpressionOperatorCategory.Collection.
  • stopAfterFirstMatch on a rule-set document. See Rule sets.

Fixed

  • count was described as coalesce in traces. Evaluation was never affected.
  • The published JSON Schema rejected stopAfterFirstMatch.

0.2.0 (not published; shipped in 0.3.0)

Breaking changes

  • Unknown properties are errors. A misspelled key such as "actons" used to be ignored, producing a rule that fired and wrote nothing. Documents with extra keys that used to load are now rejected.
  • EvaluationOptions is immutable. Set it with an object initializer. Assigning a property after construction no longer compiles, and EvaluationOptions.Default can't be changed.
  • first decision tables expand differently. Each row's condition is now exactly its cells, and the set gets StopAfterFirstMatch. Behaviour is unchanged, and a 500-row table no longer takes seconds to compile.

Added

  • RuleSkipReason and RuleTrace.SkipReason, separating a disabled rule from one never reached after a match.
  • RuleSet.StopAfterFirstMatch.
  • Traces describe a computed left-hand side as the expression itself.

Fixed

  • In / NotIn agree on both paths when the array contains null (and the validator now rejects one).
  • IsInPast / IsInFuture resolve both sides to UTC, so results no longer depend on the server's time zone.
  • A condition node reused within one tree no longer crashes the load.
  • addToOutput onto a non-numeric value leaves it alone instead of replacing it with null.
  • A document with both decisionTable and rules is a validation error, instead of silently dropping rules.
  • An out-of-range number such as 1e400 is a RuleParseException on every target framework.
  • Malformed operands, regex patterns and function names in rules built in C# are checked at LoadRuleSet.
  • A fact whose static type is object, or which implements only IReadOnlyDictionary<string, object>, now evaluates, through the interpreter.
  • A decision-table MatchesRegex cell with an invalid pattern is a validation error.

0.1.1

The first public packages: the domain model, parsing and validation, the compiled engine, the System.Text.Json and Newtonsoft.Json adapters, the built-in functions, and the RuleWright metapackage.