RuleEdits¶
Namespace Nfty.Core.Editing in assembly Nfty.Core.
Authoring for a recipe's incompatibility rules: add, replace, remove. Pure — every method returns a NEW RecipeManifest and mutates nothing, the same shape LayerDepth and CookBookEdits use, so a caller can hold the previous manifest for undo without defensive copying.
Until this existed a rule could not be created or edited anywhere in the product — not in the GUI, not in the CLI. Every creation path wrote an empty rule list, and the only way a recipe got a rule was hand-editing the manifest JSON inside the archive.
A rule is addressed by INDEX, not by an id, because the manifest has no rule id and adding a required one would be a real schema migration for a field that buys nothing at generation time. The index is the position in RecipeManifest.Rules, which is stable for as long as the caller holds one manifest — which is exactly how long an edit lasts.
Methods¶
Add(RecipeManifest, IncompatibilityRule)¶
Appends a rule.
Parameters
recipe(RecipeManifest) - The recipe to add to.rule(IncompatibilityRule) - The rule. Rejected if degenerate (seeRuleEdits.Validate()) or if the recipe already carries the same one.
Returns. A new manifest with the rule appended.
Exceptions
ArgumentException- The rule is degenerate or a duplicate.
AreSame(IncompatibilityRule, IncompatibilityRule)¶
Whether two rules constrain the same thing. Targets compare as a SET: a rule's targets are evaluated as a conjunction, so listing them in a different order is the same rule written twice, and duplicate detection that missed that would be no detection at all.
Parameters
a(IncompatibilityRule) - One rule.b(IncompatibilityRule) - The other.
Returns. True when they are the same constraint.
RemoveAt(RecipeManifest, int)¶
Removes the rule at index.
Parameters
recipe(RecipeManifest) - The recipe to edit.index(int) - Zero-based position inRecipeManifest.Rules.
Returns. A new manifest without it. Every later rule shifts down one, which is why a caller holding indexes across a removal must re-read them.
Exceptions
ArgumentOutOfRangeException- No rule at that index.
ReplaceAt(RecipeManifest, int, IncompatibilityRule)¶
Replaces the rule at index.
Parameters
recipe(RecipeManifest) - The recipe to edit.index(int) - Zero-based position inRecipeManifest.Rules.rule(IncompatibilityRule) - The replacement.
Returns. A new manifest with that one rule swapped, every other rule and its position untouched.
Exceptions
ArgumentOutOfRangeException- No rule at that index.ArgumentException- The rule is degenerate, or duplicates a DIFFERENT rule in the same recipe — replacing a rule with itself is allowed, since that is what an edit that changes nothing looks like.
Validate(IncompatibilityRule)¶
Rejects a rule that cannot mean anything. This is the authoring half of a pair: Validator reports the same two shapes on a book that already has them, since before this class existed a rule could only be written by hand and a hand-written one can be anything. Refusing to WRITE one costs nothing; refusing to COOK one is justified because each silently changes the size of the DNA space.
Parameters
rule(IncompatibilityRule) - The rule to check.
Exceptions
ArgumentException- The rule is degenerate.