self-assert
Version:
A small TypeScript library for designing models with built-in validity.
1 lines • 63.7 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/rule/RuleLabel.ts","../src/rule/RulesBroken.ts","../src/rule/Ruleset.ts","../src/rule/RuleEvaluation.ts","../src/rule/Rule.ts","../src/rule/Assertion.ts","../src/rule/Inquiry.ts","../src/rule-requirements/LogicalRequirements.ts","../src/rule-requirements/numbers/NumbersRequirements.ts","../src/rule-requirements/lists/ListsRequirements.ts","../src/rule-requirements/Requirements.ts","../src/draft-assistant/DraftAssistant.ts","../src/draft-assistant/FieldDraftAssistant.ts","../src/draft-assistant/SectionDraftAssistant.ts","../src/draft-assistant/IntegerDraftAssistant.ts","../src/draft-publisher/DraftPublisher.ts"],"sourcesContent":["import type { LabelId, LabeledRule } from \"./types\";\n\n/**\n * JSON representation of a {@link RuleLabel}\n *\n * @category Rule labeling\n */\nexport interface RuleLabelAsJson {\n id: LabelId;\n description: string;\n}\n\nexport class RuleLabel implements LabeledRule {\n static fromJson({ id, description }: RuleLabelAsJson) {\n return new this(id, description);\n }\n\n constructor(protected id: LabelId, protected description: string) {}\n\n isLabeledAs(aBrokenRuleLabel: LabeledRule): boolean {\n return aBrokenRuleLabel.hasLabel(this.id, this.description);\n }\n\n hasLabel(assertionId: LabelId, assertionDescription: string) {\n return this.hasLabelId(assertionId) && this.hasDescription(assertionDescription);\n }\n\n hasLabelId(assertionId: LabelId): boolean {\n return this.id === assertionId;\n }\n\n hasDescription(description: string): boolean {\n return this.description === description;\n }\n\n getId() {\n return this.id;\n }\n\n getDescription(): string {\n return this.description;\n }\n}\n","import { RuleLabel } from \"./RuleLabel\";\n\nimport type { RuleLabelAsJson } from \"./RuleLabel\";\nimport type { LabelId, LabeledRule } from \"./types\";\n\n/**\n * JSON representation of {@link RulesBroken}\n *\n * @category Supporting types\n */\nexport interface RulesBrokenAsJson {\n brokenRules: RuleLabelAsJson[];\n}\n\n/**\n * Provides a way to handle multiple failed rules,\n * by their labels.\n *\n * @see {@link RuleLabel}\n * @category Rules\n */\nexport class RulesBroken extends Error {\n /** @category Creation */\n static fromJson(rulesBrokenAsJson: RulesBrokenAsJson) {\n const brokenRules = rulesBrokenAsJson.brokenRules.map((ruleAsJson) =>\n RuleLabel.fromJson(ruleAsJson)\n );\n\n return new this(brokenRules);\n }\n\n /** @category Creation */\n constructor(protected brokenRules: LabeledRule[]) {\n super();\n }\n\n /** @category Inspection */\n hasRuleBrokenWith(labelId: LabelId, labelDescription: string) {\n return this.brokenRules.some((rule) =>\n rule.hasLabel(labelId, labelDescription)\n );\n }\n\n /** @category Inspection */\n hasOnlyOneRuleBrokenWith(labelId: LabelId, labelDescription: string) {\n return (\n this.brokenRules.length === 1 &&\n this.brokenRules[0].hasLabel(labelId, labelDescription)\n );\n }\n\n /** @category Inspection */\n forEachRuleBroken(closure: (brokenRule: LabeledRule) => void) {\n return this.brokenRules.forEach(closure);\n }\n}\n","import { RulesBroken } from \"./RulesBroken\";\nimport type {\n LabeledRule,\n SelfContainedAssertion,\n SelfContainedAssertions,\n SelfContainedRule,\n SelfContainedRules,\n} from \"./types\";\n\n/**\n * Runs all rules and throws an error if any has failed.\n * The failed rules are included in the error.\n *\n * @category Rules\n */\nexport class Ruleset {\n /**\n * Evaluates all assertions **synchronously** and throws an error if any has failed.\n *\n * @throws {@link RulesBroken} if any rule has failed.\n *\n * @example\n * {@includeCode ../../../../examples/snippets/rules.ts#ruleset-ensureAll}\n */\n static ensureAll(...assertions: SelfContainedAssertions[]): void {\n new this(assertions.flat(), []).ensure();\n }\n\n /**\n * Evaluates all rules **asynchronously** and throws an error if any has failed.\n *\n * @throws {@link RulesBroken} if any rule has failed\n *\n * @example\n * {@includeCode ../../../../examples/snippets/rules.ts#email-unique,ruleset-workOn}\n */\n static workOn(...rules: SelfContainedRules[]): Promise<void> {\n return new this([], rules.flat()).mustHold();\n }\n\n constructor(\n protected assertions: SelfContainedAssertion[],\n protected rules: SelfContainedRule[]\n ) {}\n\n async mustHold(): Promise<void> {\n const brokenRules = await this.brokenRules();\n\n this.throwIfNotEmpty(brokenRules);\n }\n\n ensure(): void {\n const brokenRules = this.failedAssertions();\n\n this.throwIfNotEmpty(brokenRules);\n }\n\n protected failedAssertions(): LabeledRule[] {\n const failed: LabeledRule[] = [];\n this.assertions.forEach((assertion) =>\n assertion.collectFailureInto(failed)\n );\n return failed;\n }\n\n protected async brokenRules(): Promise<LabeledRule[]> {\n const brokenRules: LabeledRule[] = [];\n for (const rule of this.rules) {\n await rule.collectFailureInto(brokenRules);\n }\n return brokenRules;\n }\n\n protected throwIfNotEmpty(brokenRules: LabeledRule[]) {\n if (brokenRules.length > 0) throw new RulesBroken(brokenRules);\n }\n}\n","import type { Rule } from \"./Rule\";\nimport type { CollectableRule, MaybeAsync } from \"./types\";\nimport type { LabeledRule, LabelId } from \"./types\";\n\n/**\n * Represents the evaluation of a rule on a given value.\n *\n * It can also be created using the {@link Rule.evaluateFor} method.\n *\n * @template ValueType The type of value the rule applies to.\n *\n * @example\n * {@includeCode ../../../../examples/snippets/rules.ts#evaluateFor,rule-evaluation}\n *\n * @category Rules\n */\nexport class RuleEvaluation<\n PredicateReturnType extends MaybeAsync<boolean>,\n ValueType\n> implements\n CollectableRule<\n void,\n PredicateReturnType extends boolean ? void : Promise<void>\n >\n{\n constructor(\n protected rule: Rule<PredicateReturnType, ValueType>,\n protected value: ValueType\n ) {}\n\n /**\n * @category Rule evaluation\n * @see {@link Rule.doesHold}\n */\n doesHold() {\n return this.rule.doesHold(this.value);\n }\n\n /**\n * @category Rule evaluation\n * @see {@link Rule.hasFailed}\n */\n hasFailed() {\n return this.rule.hasFailed(this.value);\n }\n\n /**\n * @category Rule evaluation\n * @see {@link Rule.mustHold}\n */\n mustHold() {\n return this.rule.mustHold(this.value);\n }\n\n /**\n * @category Rule evaluation\n * @see {@link Rule.collectFailureInto}\n */\n collectFailureInto(failed: LabeledRule[]) {\n return this.rule.collectFailureInto(failed, this.value);\n }\n\n isLabeledAs(aBrokenRuleLabel: LabeledRule): boolean {\n return this.rule.isLabeledAs(aBrokenRuleLabel);\n }\n\n hasLabel(anId: LabelId, aDescription: string) {\n return this.rule.hasLabel(anId, aDescription);\n }\n\n hasDescription(aDescription: string) {\n return this.rule.hasDescription(aDescription);\n }\n\n hasLabelId(anId: LabelId) {\n return this.rule.hasLabelId(anId);\n }\n\n getId(): LabelId {\n return this.rule.getId();\n }\n\n getDescription() {\n return this.rule.getDescription();\n }\n}\n","import { RuleEvaluation } from \"./RuleEvaluation\";\nimport { RuleLabel } from \"./RuleLabel\";\nimport type {\n LabelId,\n LabeledRule,\n MaybeAsync,\n RuleRequirement,\n} from \"./types\";\n\n/**\n * Represents a validation rule in the problem domain.\n *\n * This is the base class for all rules.\n * - Use {@link Assertion} for rules that can be evaluated **synchronously**.\n * - Use {@link Inquiry} for rules that need to be evaluated **asynchronously**.\n *\n * Rules are identified by a unique identifier (`labelId`) and a human-readable description.\n * These identifiers are meant to be meaningful within the domain,\n * and can be used to route or display validation errors.\n *\n * @template PredicateReturnType The return type of the predicate functions.\n * Specifically, `true` or `Promise<true>`.\n * @template ValueType The type of value this rule applies to.\n *\n * @category Rules\n * @categoryDescription Rule evaluation\n * Related to the definition of business rules and their evaluation.\n * @categoryDescription Rule definition\n * Related to the definition of requirements for business rules.\n */\nexport abstract class Rule<\n PredicateReturnType extends MaybeAsync<boolean>,\n ValueType = any\n> implements LabeledRule\n{\n protected readonly requirements: RuleRequirement<\n PredicateReturnType,\n ValueType\n >[];\n\n protected constructor(protected label: RuleLabel) {\n this.requirements = [];\n }\n\n /**\n * Evaluates the requirements for the given value,\n * and returns whether the rule holds or not.\n *\n * @category Rule evaluation\n */\n abstract doesHold(value: ValueType): PredicateReturnType;\n\n /**\n * Opposite of {@link doesHold}\n *\n * @category Rule evaluation\n */\n abstract hasFailed(value: ValueType): PredicateReturnType;\n\n /**\n * Evaluates the requirements for the given value.\n * If any condition is not met, throws a {@link RulesBroken} exception.\n *\n * @category Rule evaluation\n */\n abstract mustHold(\n value: ValueType\n ): PredicateReturnType extends boolean ? void : Promise<void>;\n\n /**\n * Updates the list of failed assertions with its label\n * if the rule has failed for the given value.\n *\n * @category Rule evaluation\n */\n abstract collectFailureInto(\n failed: LabeledRule[],\n value: ValueType\n ): PredicateReturnType extends boolean ? void : Promise<void>;\n\n /**\n * Adds a necessary requirement for the rule to hold.\n *\n * @example\n * Add a requirement for the rule to hold\n * {@includeCode ../../../../examples/snippets/rules.ts#require}\n *\n *\n * @returns `this` for chaining\n * @category Rule definition\n */\n require(\n aConditionToBeMet: RuleRequirement<PredicateReturnType, ValueType>\n ): this {\n this.requirements.push(aConditionToBeMet);\n return this;\n }\n\n /**\n * Prepares a {@link RuleEvaluation} for the given value.\n *\n * This is the same as `new RuleEvaluation(rule, value)`.\n *\n * @example\n * {@includeCode ../../../../examples/snippets/rules.ts#evaluateFor}\n *\n * @category Rule evaluation\n */\n evaluateFor(aValue: ValueType) {\n return new RuleEvaluation(this, aValue);\n }\n\n isLabeledAs(aBrokenRuleLabel: LabeledRule) {\n return aBrokenRuleLabel.hasLabel(\n this.label.getId(),\n this.label.getDescription()\n );\n }\n\n hasLabel(anId: LabelId, aDescription: string) {\n return this.label.hasLabel(anId, aDescription);\n }\n\n hasDescription(aDescription: string) {\n return this.label.hasDescription(aDescription);\n }\n\n hasLabelId(anId: LabelId) {\n return this.label.hasLabelId(anId);\n }\n\n getId(): LabelId {\n return this.label.getId();\n }\n\n getDescription() {\n return this.label.getDescription();\n }\n}\n","import { RuleLabel, RuleLabelAsJson } from \"./RuleLabel\";\nimport { Ruleset } from \"./Ruleset\";\nimport { Rule } from \"./Rule\";\nimport type {\n CollectableRule,\n LabeledRule,\n LabelId,\n RuleRequirement,\n} from \"./types\";\n\n/**\n * Represents a validation rule in the problem domain.\n *\n * An `Assertion` expresses a condition that must hold for a given value.\n * These rules are defined using one or more predicate functions, added via\n * {@link Rule.require require}. The assertion is considered to \"hold\" when all the conditions evaluate to `true`.\n *\n * @see\n * - {@link Requirements} provides a list of built-in requirements.\n *\n * @template ValueType The type of value this assertion applies to.\n *\n * @example\n * Basic usage\n * {@includeCode ../../../../examples/snippets/rules.ts#assertion-basic-usage}\n *\n * @category Rules\n */\nexport class Assertion<ValueType = any> extends Rule<boolean, ValueType> {\n /** @category Creation */\n static fromJson(assertionAsJson: RuleLabelAsJson) {\n return new this(RuleLabel.fromJson(assertionAsJson));\n }\n\n /** @category Creation */\n static labeled<ValueType = any>(id: LabelId, description: string) {\n const label = new RuleLabel(id, description);\n return new this<ValueType>(label);\n }\n\n /** @internal */\n static requiring(\n anId: LabelId,\n aDescription: string,\n aCondition: () => boolean\n ): Assertion<void>;\n\n /**\n * Creates a new assertion with the given id, description and requirement.\n *\n * If the requirement does not depend on a value (i.e., a function with no parameters),\n * the rule will be typed as `Assertion<void>`.\n *\n * @example\n * Without a value\n * {@includeCode ../../../../examples/snippets/rules.ts#assertion-requiring-void}\n *\n * @example\n * With a value\n * {@includeCode ../../../../examples/snippets/rules.ts#assertion-requiring-value}\n *\n * @category Creation\n */\n static requiring<ValueType = any>(\n anId: LabelId,\n aDescription: string,\n aCondition: (value: ValueType) => boolean\n ): Assertion<ValueType>;\n\n static requiring<ValueType = any>(\n id: LabelId,\n description: string,\n aConditionToBeMet: RuleRequirement<boolean, ValueType>\n ) {\n return this.labeled<ValueType>(id, description).require(aConditionToBeMet);\n }\n\n protected constructor(label: RuleLabel) {\n super(label);\n }\n\n doesHold(value: ValueType): boolean {\n return this.requirements.every((condition) => condition(value));\n }\n\n hasFailed(value: ValueType): boolean {\n return !this.doesHold(value);\n }\n\n mustHold(value: ValueType): void {\n Ruleset.ensureAll(this.evaluateFor(value));\n }\n\n collectFailureInto(failed: LabeledRule[], value: ValueType): void {\n if (this.hasFailed(value)) {\n failed.push(this.label);\n }\n }\n}\n\n/**\n * **Type check only**\n *\n * This dummy class exists solely to ensure at compile time that `Assertion<void>`\n * structurally satisfies the {@link CollectableRule} interface.\n *\n * It is never instantiated or exported.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nclass VoidAssertionIsSelfContained\n extends Assertion<void>\n implements CollectableRule<void, void> {}\n","import { RuleLabel } from \"./RuleLabel\";\nimport { RulesBroken } from \"./RulesBroken\";\nimport { Rule } from \"./Rule\";\nimport { LabeledRule, LabelId } from \"./types\";\n\n/**\n * Represents a rule that needs to be evaluated **asynchronously**.\n *\n * @example\n * {@includeCode ../../../../examples/snippets/rules.ts#inquiry}\n *\n * @category Rules\n */\nexport class Inquiry<ValueType = any> extends Rule<\n Promise<boolean>,\n ValueType\n> {\n /** @category Creation */\n static labeled<ValueType = any>(anId: LabelId, aDescription: string) {\n return new this<ValueType>(new RuleLabel(anId, aDescription));\n }\n\n /** @internal */\n static requiring(\n anId: LabelId,\n aDescription: string,\n aCondition: () => Promise<boolean>\n ): Inquiry<void>;\n /**\n * @see {@link Assertion.requiring}\n * @category Creation\n */\n static requiring<ValueType = any>(\n anId: LabelId,\n aDescription: string,\n aCondition: (value: ValueType) => Promise<boolean>\n ): Inquiry<ValueType>;\n\n static requiring<ValueType = any>(\n anId: LabelId,\n aDescription: string,\n aCondition: (value: ValueType) => Promise<boolean>\n ) {\n return this.labeled<ValueType>(anId, aDescription).require(aCondition);\n }\n\n protected constructor(label: RuleLabel) {\n super(label);\n }\n\n async doesHold(value: ValueType) {\n for (const requirement of this.requirements) {\n if (!(await requirement(value))) {\n return false;\n }\n }\n return true;\n }\n\n async hasFailed(value: ValueType) {\n return !(await this.doesHold(value));\n }\n\n async mustHold(value: ValueType) {\n if (await this.hasFailed(value)) {\n throw new RulesBroken([this.label]);\n }\n }\n\n async collectFailureInto(failed: LabeledRule[], value: ValueType) {\n if (await this.hasFailed(value)) {\n failed.push(this.label);\n }\n }\n}\n","import type { Predicate } from \"./Requirements\";\n\nexport class LogicalRequirement {\n /**\n * Combines multiple conditions using logical AND\n * @function @category Composition\n */\n static and =\n <ValueType>(...conditions: Predicate<ValueType>[]): Predicate<ValueType> =>\n (value) =>\n conditions.every((condition) => condition(value));\n\n /**\n * Combines multiple conditions using logical OR\n * @function @category Composition\n */\n static or =\n <ValueType>(...conditions: Predicate<ValueType>[]): Predicate<ValueType> =>\n (value) =>\n conditions.some((condition) => condition(value));\n\n /**\n * Negates a condition\n * @function @category Composition\n */\n static not =\n <ValueType>(condition: Predicate<ValueType>): Predicate<ValueType> =>\n (value) =>\n !condition(value);\n\n /**\n * Returns a predicate that checks if the value is equal to the expected value.\n * @function @category Comparison\n */\n static identical = <ValueType>(expected: ValueType) => this.isIn(expected);\n\n /**\n * Returns a predicate that checks if the value is not equal to the forbidden value.\n * @function @category Comparison\n */\n static differentFrom = <ValueType>(forbiddenValue: ValueType) => this.not(this.identical(forbiddenValue));\n\n /**\n * Returns a predicate that checks if the value is in the allowed set.\n * @function @category Comparison\n */\n static isIn =\n <ValueType>(...allowedSet: ValueType[]): Predicate<ValueType> =>\n (value) =>\n allowedSet.includes(value);\n\n /**\n * Returns a predicate that checks if the value is not in the forbidden set.\n * @function @category Comparison\n */\n static isNotIn = <ValueType>(...forbiddenSet: ValueType[]) => this.not(this.isIn(...forbiddenSet));\n}\n","import { LogicalRequirement } from \"../LogicalRequirements\";\n\nimport type { Predicate } from \"../Requirements\";\n\nconst { and, or, not, identical } = LogicalRequirement;\n\nexport class NumbersRequirements {\n /**\n * Returns a predicate that is `true` if the value is greater than the given number\n * @function @category Numbers\n */\n static greaterThan =\n (aNumber: number): Predicate<number> =>\n (value) =>\n value > aNumber;\n\n /**\n * Returns a predicate that is `true` if the value is greater than or equal to the given number\n * @function @category Numbers\n */\n static greaterThanOrEqual = (aNumber: number) => or(this.greaterThan(aNumber), identical(aNumber));\n\n /**\n * Returns a predicate that is `true` if the value is less than the given number\n * @function @category Numbers\n */\n static lessThan = (aNumber: number) => not(this.greaterThanOrEqual(aNumber));\n\n /**\n * Returns a predicate that is `true` if the value is less than or equal to the given number\n * @function @category Numbers\n */\n static lessThanOrEqual = (aNumber: number) => not(this.greaterThan(aNumber));\n\n /**\n * Returns a predicate that is `true` if the value is between two numbers (inclusive)\n * @function @category Numbers\n */\n static between = (min: number, max: number) => and(this.greaterThanOrEqual(min), this.lessThanOrEqual(max));\n\n /**\n * Returns a predicate that is `true` if the value is an integer\n * @function @category Numbers\n */\n static isInteger = Number.isInteger;\n\n /**\n * Returns a predicate that is `true` if the value is a float\n * @function @category Numbers\n */\n static isFloat = and(Number.isFinite, not(this.isInteger));\n\n /**\n * Returns a predicate that is `true` if the value is positive\n * @function @category Numbers\n */\n static isPositive = this.greaterThan(0);\n\n /**\n * Returns a predicate that is `true` if the value is negative\n * @function @category Numbers\n */\n static isNegative = this.lessThan(0);\n\n /**\n * Returns a predicate that is `true` if the value is a positive integer\n * @function @category Numbers\n */\n static isPositiveInteger = and(this.isInteger, this.isPositive);\n\n /**\n * Returns a predicate that is `true` if the value is a negative integer\n * @function @category Numbers\n */\n static isNegativeInteger = and(this.isInteger, this.isNegative);\n\n /**\n * Returns a predicate that is `true` if the value is an integer between two numbers (inclusive)\n * @function @category Numbers\n */\n static isIntegerBetween = (min: number, max: number) => and(this.isInteger, this.between(min, max));\n}\n","import { LogicalRequirement } from \"../LogicalRequirements\";\nimport { NumbersRequirements } from \"../numbers/NumbersRequirements\";\nimport type { Predicate } from \"../Requirements\";\n\nconst { identical, not, and } = LogicalRequirement;\n\nexport class ListsRequirements {\n /**\n * Returns a predicate that holds when the list has exactly the given number of elements\n * @function @category Lists\n */\n static hasExactly = (aNumber: number) => (list: ArrayLike<unknown>) => identical(aNumber)(list.length);\n\n /**\n * Returns a predicate that holds when the list has no elements\n * @function @category Lists\n */\n static isEmpty: Predicate<ArrayLike<unknown>> = this.hasExactly(0);\n\n /**\n * Returns a predicate that holds when the list has at least one element\n * @function @category Lists\n */\n static isNotEmpty = not(this.isEmpty);\n\n /**\n * Returns a predicate that holds when the list has more than the given number of elements\n * @function @category Lists\n */\n static hasMoreThan = (aNumber: number) => (list: ArrayLike<unknown>) =>\n NumbersRequirements.greaterThan(aNumber)(list.length);\n\n /**\n * Returns a predicate that holds when the list has at most the given number of elements\n * @function @category Lists\n */\n static hasAtMost = (aNumber: number) => not(this.hasMoreThan(aNumber));\n\n /**\n * Returns a predicate that holds when the list has less than the given number of elements\n * @function @category Lists\n */\n static hasLessThan = (aNumber: number) => and(this.hasAtMost(aNumber), not(this.hasExactly(aNumber)));\n\n /**\n * Returns a predicate that holds when the list has at least the given number of elements\n * @function @category Lists\n */\n static hasAtLeast = (aNumber: number) => not(this.hasLessThan(aNumber));\n\n /**\n * Returns a predicate that holds when the list contains the given element\n * @function @category Lists\n */\n static includes: <ElementType>(element: ElementType) => Predicate<{ includes: Predicate<ElementType> }> =\n (element) => (list) =>\n list.includes(element);\n\n /**\n * Opposite of {@link includes}\n * @function @category Lists\n */\n static doesNotInclude = <ElementType>(element: ElementType) => not(this.includes(element));\n\n /**\n * Returns a predicate that holds when all elements of the list satisfy the given condition\n * @function @category Lists\n */\n static allSatisfy =\n <ElementType>(predicate: Predicate<ElementType>) =>\n (list: Iterable<ElementType>) => {\n for (const element of list) {\n if (!predicate(element)) {\n return false;\n }\n }\n return true;\n };\n\n /**\n * Returns a predicate that holds when any element of the list satisfies the given condition\n * @function @category Lists\n */\n static anySatisfy =\n <ElementType>(predicate: Predicate<ElementType>) =>\n (list: Iterable<ElementType>) => {\n for (const element of list) {\n if (predicate(element)) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Returns a predicate that holds when no element of the list satisfies the given condition.\n * Opposite of {@link anySatisfy}\n * @function @category Lists\n */\n static noneSatisfy = <ElementType>(predicate: Predicate<ElementType>) => not(this.anySatisfy(predicate));\n}\n","/* eslint-disable @typescript-eslint/no-misused-spread */\nimport { ListsRequirements } from \"./lists/ListsRequirements\";\nimport { LogicalRequirement } from \"./LogicalRequirements\";\nimport { NumbersRequirements } from \"./numbers/NumbersRequirements\";\n\nimport type { RuleRequirement } from \"../rule\";\n\n/**\n * @category Supporting types\n */\nexport type Predicate<ValueType> = RuleRequirement<boolean, ValueType>;\n\nconst { not } = LogicalRequirement;\n\nclass StringsRequirements {\n /**\n * A predicate that evaluates to `true` if the string is empty or contains only whitespace characters.\n * @function @category Strings\n * @see {@link isNotBlank}\n */\n static isBlank: Predicate<string> = (value) =>\n ListsRequirements.isEmpty(value.trim());\n\n /**\n * Opposite of {@link isBlank}.\n * @function @category Strings\n */\n static isNotBlank = not(this.isBlank);\n}\n\n/**\n * A collection of common rule requirements.\n *\n * It also provides a way to compose requirements using the `and`, `or` and `not` functions.\n *\n * @namespace\n *\n * @category Rules\n * @categoryDescription Composition\n * Methods for composing requirements. Example:\n * {@includeCode ../../../../examples/snippets/requirements.ts#composition}\n */\nexport const Requirements = {\n /**\n * A predicate that always evaluates to `true`.\n */\n hold: () => true,\n /**\n * A predicate that always evaluates to `false`.\n */\n fail: () => false,\n ...LogicalRequirement,\n ...NumbersRequirements,\n ...ListsRequirements,\n ...StringsRequirements,\n /**\n * @hidden\n * @privateRemarks\n * This is to avoid TypeDoc from showing the prototype in the docs\n */\n prototype: Object.prototype,\n};\n","import type { LabelId, LabeledRule } from \"../rule\";\nimport type { ModelFromContainer, DraftViewer } from \"../types\";\n\n/**\n * Provides an assistant to guide the completion of a model.\n *\n * A `DraftAssistant` encapsulates the logic needed to:\n *\n * - track the current state of a form field or group of fields,\n * - validate the model being built,\n * - handle and route failed assertions,\n * - notify observers (viewers) of changes or validation failures.\n *\n * Assistants can be nested and composed to build complex models.\n *\n * @typeParam Model The type of the model the assistant helps to create.\n * @typeParam ContainerModel The type of the container model the assistant works on.\n *\n * @remarks\n * Originally, this class was named `ModelCreator`. Later, it was renamed to `FormCompletionAssistant`,\n * employing the metaphor of an assistant guiding form completion. This could have led to confusion,\n * since the class has more use cases than just form completion.\n *\n * It can, for example, be used in a backend context to validate an object before persisting it.\n *\n * @category Draft assistants\n */\nexport abstract class DraftAssistant<Model = any, ContainerModel = any> {\n /**\n * See {@link https://github.com/microsoft/TypeScript/issues/3841 #3841} for\n * more information.\n * @hidden\n */\n declare [\"constructor\"]: typeof DraftAssistant;\n\n /**\n * This object is used as a **token** for an invalid model.\n * @internal\n */\n static INVALID_MODEL = new Object();\n\n /**\n * @category Model creation\n */\n static isInvalidModel(potentialModel: unknown) {\n return potentialModel === DraftAssistant.INVALID_MODEL;\n }\n\n /**\n * @returns A default model getter from a container for the top-level assistant.\n * Since there is no container to get the model from, it throws an error.\n */\n static topLevelModelFromContainer<Model = any>(): ModelFromContainer<\n Model,\n unknown\n > {\n return () => {\n throw new Error(\"No container to get model from\");\n };\n }\n\n protected model: Model;\n protected brokenRules!: LabeledRule[];\n protected viewers: DraftViewer<Model>[];\n\n protected constructor(\n protected labelIds: LabelId[],\n protected modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n protected initialModel: Model\n ) {\n this.model = this.initialModel;\n this.viewers = [];\n this.removeBrokenRules();\n }\n\n /**\n * Attempts to create a model. It fails if any of the assertions fail.\n * @see {@link withCreatedModelDo}.\n *\n * @throws {@link RulesBroken} if the model is invalid\n *\n * @category Model creation\n */\n abstract createModel(): Model;\n\n /**\n * Executes a closure depending on whether the model is valid or not after creating it.\n *\n * @template ReturnType - The type of the value returned by the closures.\n * @param validModelClosure - A closure that will be called with the created model\n * if it's valid.\n * @param invalidModelClosure - A closure that will be called if the model is invalid.\n * @returns The return value of the closure that was called.\n *\n * @category Model creation\n */\n withCreatedModelDo<ReturnType>(\n validModelClosure: (model: Model) => ReturnType,\n invalidModelClosure: () => ReturnType\n ) {\n const createdModel = this.createModel();\n if (this.constructor.isInvalidModel(createdModel))\n return invalidModelClosure();\n\n return validModelClosure(createdModel);\n }\n\n /** @category Model creation */\n getModel(): Model {\n return this.model;\n }\n\n /** @category Model creation */\n setModel(newModel: Model): void {\n this.model = newModel;\n this.notifyViewersOnChange(newModel);\n }\n\n /**\n * Resets the model to its initial value.\n * @category Model creation\n */\n resetModel(): void {\n this.model = this.initialModel;\n this.notifyViewersOnChange(this.model);\n }\n\n /**\n * Sets the model from its container.\n * @category Model creation\n */\n setModelFrom(containerModel: ContainerModel) {\n return this.setModel(this.modelFromContainer(containerModel));\n }\n\n /**\n * Adds a viewer to the list of observers.\n * @category Viewers\n */\n accept(aViewer: DraftViewer<Model>) {\n this.viewers.push(aViewer);\n }\n\n /**\n * Removes a viewer from the list of observers.\n * @category Viewers\n */\n removeViewer(aViewer: DraftViewer<never>) {\n this.viewers = this.viewers.filter((viewer) => viewer !== aViewer);\n }\n\n /**\n * @returns The number of viewers currently observing the assistant.\n * @category Viewers\n */\n numberOfViewers() {\n return this.viewers.length;\n }\n\n /**\n * Adds a rule to the list of broken rules.\n * @category Rules\n */\n addBrokenRule(aBrokenRuleLabel: LabeledRule) {\n if (this.hasBrokenRule(aBrokenRuleLabel)) return;\n\n this.brokenRules.push(aBrokenRuleLabel);\n this.forEachViewer((viewer) => viewer.onFailure?.(aBrokenRuleLabel));\n }\n\n /**\n * Adds a list of rules to the list of broken rules.\n * @category Rules\n */\n addBrokenRules(brokenRules: LabeledRule[]) {\n brokenRules.forEach((failure) => {\n this.addBrokenRule(failure);\n });\n }\n\n /**\n * @returns `true` if the list of broken rules is not empty\n * @category Rules\n */\n hasBrokenRules() {\n return this.brokenRules.length > 0;\n }\n\n /**\n * Opposite of {@link hasBrokenRules}.\n * @category Rules\n */\n doesNotHaveBrokenRules() {\n return !this.hasBrokenRules();\n }\n\n /**\n * @returns The descriptions of the broken rules\n * @category Rules\n */\n brokenRulesDescriptions() {\n return this.brokenRules\n .map((brokenRule) => brokenRule.getDescription())\n .filter((description) => description !== \"\");\n }\n\n /**\n * @returns `true` if this assistant handles the given `Assertion`.\n * @category Rules\n */\n handles(aRule: LabeledRule) {\n return this.labelIds.some((labelId) => aRule.hasLabelId(labelId));\n }\n\n /**\n * Adds an assertion id to the list of handled assertions.\n * @category Rules\n */\n addLabelId(aLabelId: LabelId) {\n this.labelIds.push(aLabelId);\n }\n\n /** @category Rules */\n hasBrokenRule(aBrokenRuleLabel: LabeledRule) {\n return this.brokenRules.some((brokenRule) =>\n brokenRule.isLabeledAs(aBrokenRuleLabel)\n );\n }\n\n /**\n * @returns `true` if this assistant has only one failed assertion that\n * is identified as the given `assertionId`.\n *\n * @remarks\n * Used mostly for testing.\n *\n * @category Rules\n */\n hasOnlyOneRuleBrokenIdentifiedAs(assertionId: LabelId) {\n return (\n this.brokenRules.length === 1 &&\n this.brokenRules[0].hasLabelId(assertionId)\n );\n }\n\n /** @category Rules */\n removeBrokenRules() {\n this.brokenRules = [];\n this.forEachViewer((viewer) => viewer.onFailuresReset?.());\n }\n\n protected forEachViewer(action: (viewer: DraftViewer<Model>) => void) {\n this.viewers.forEach(action);\n }\n\n protected notifyViewersOnChange(aModel: Model) {\n this.forEachViewer((viewer) => viewer.onDraftChanged?.(aModel));\n }\n}\n","import { DraftAssistant } from \"./DraftAssistant\";\n\nimport type { ModelFromContainer } from \"../types\";\nimport { Assertion, LabelId, LabeledRule, CollectableRule } from \"../rule\";\n\n/**\n * An assistant designed to manage a single field or a simple\n * piece of data within a larger form or model.\n *\n * @category Draft assistants\n */\nexport class FieldDraftAssistant<ContainerModel = any, Model extends string = string> extends DraftAssistant<\n Model,\n ContainerModel\n> {\n static handling<ContainerModel = any, Model extends string = string>(\n assertionId: LabelId,\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n initialModel = \"\"\n ) {\n return this.handlingAll([assertionId], modelFromContainer, initialModel);\n }\n\n static handlingAll<ContainerModel = any, Model extends string = string>(\n assertionIds: LabelId[],\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n initialModel = \"\"\n ) {\n return this.requiringAll(\n assertionIds.map((id) => Assertion.labeled(id, \"(placeholder)\")),\n modelFromContainer,\n initialModel\n );\n }\n\n static requiring<ContainerModel = any, Model extends string = string>(\n assertion: CollectableRule<Model | void, void>,\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n initialModel = \"\"\n ) {\n return this.requiringAll<ContainerModel, Model>([assertion], modelFromContainer, initialModel);\n }\n\n static requiringAll<ContainerModel = any, Model extends string = string>(\n assertions: CollectableRule<Model | void, void>[],\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n initialModel = \"\"\n ) {\n return new this<ContainerModel, Model>(assertions, modelFromContainer, initialModel as Model);\n }\n\n protected constructor(\n protected assertions: CollectableRule<Model, void>[],\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n initialModel: Model\n ) {\n const ids = assertions.map((assertion) => assertion.getId());\n super(ids, modelFromContainer, initialModel);\n }\n\n createModel() {\n this.removeBrokenRules();\n return this.model;\n }\n\n /**\n * Checks if the current draft verifies all assertions.\n * If not, it adds them to the list of failed assertions.\n */\n review() {\n this.removeBrokenRules();\n const failures: LabeledRule[] = [];\n this.assertions.forEach((assertion) => {\n assertion.collectFailureInto(failures, this.model);\n });\n\n this.addBrokenRules(failures);\n }\n}\n","import { DraftAssistant } from \"./DraftAssistant\";\nimport { RulesBroken } from \"../rule\";\n\nimport type { LabelId, LabeledRule } from \"../rule\";\nimport type { ModelFromContainer, AssistantsIn } from \"../types\";\n\n/**\n * @category Supporting types\n */\nexport type CreationClosure<Model, ComposedModels extends unknown[]> = (\n ...models: ComposedModels\n) => Model;\n\n/**\n * Assists in the creation of complex models by coordinating multiple inner `DraftAssistant`.\n *\n * It uses a {@link CreationClosure} function to combine the models created by its\n * assistants into a single composed model.\n *\n * @template ComposedModels - An array of types representing the types of the models created by the inner assistants,\n * in the same order as the `assistants` array.\n *\n * @category Draft assistants\n */\nexport class SectionDraftAssistant<\n Model = any,\n ContainerModel = any,\n ComposedModels extends unknown[] = any[]\n> extends DraftAssistant<Model, ContainerModel> {\n static with<\n Model = any,\n ContainerModel = any,\n ComposedModels extends unknown[] = any[]\n >(\n assistants: AssistantsIn<ComposedModels, Model>,\n creationClosure: CreationClosure<Model, ComposedModels>,\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n assertionIds: LabelId[]\n ) {\n return new this(\n assistants,\n creationClosure,\n modelFromContainer,\n assertionIds\n );\n }\n\n static topLevelContainerWith<\n Model = any,\n ComposedModels extends unknown[] = any[]\n >(\n assistants: AssistantsIn<ComposedModels, Model>,\n creationClosure: CreationClosure<Model, ComposedModels>,\n assertionIds: LabelId[] = []\n ) {\n return this.with(\n assistants,\n creationClosure,\n this.topLevelModelFromContainer<Model>(),\n assertionIds\n );\n }\n\n constructor(\n protected assistants: AssistantsIn<ComposedModels, Model>,\n protected creationClosure: CreationClosure<Model, ComposedModels>,\n modelFromContainer: ModelFromContainer<Model, ContainerModel>,\n assertionIds: LabelId[]\n ) {\n /** @ts-expect-error See {@link DraftAssistant.INVALID_MODEL} */\n super(assertionIds, modelFromContainer, DraftAssistant.INVALID_MODEL);\n }\n\n createModel() {\n this.removeBrokenRules();\n const models = this.createComposedModels();\n try {\n super.setModel(this.creationClosure(...models));\n } catch (error) {\n super.resetModel();\n this.handleError(error);\n }\n\n return this.model;\n }\n\n setModel(newModel: Model) {\n super.setModel(newModel);\n this.assistants.forEach((assistant) => assistant.setModelFrom(newModel));\n }\n\n resetModel() {\n super.resetModel();\n this.assistants.forEach((assistant) => assistant.resetModel());\n }\n\n /**\n * @category Error handling\n */\n handleError(possibleCreateModelError: unknown) {\n if (possibleCreateModelError instanceof RulesBroken)\n return this.routeBrokenRulesOf(possibleCreateModelError);\n\n throw possibleCreateModelError;\n }\n\n /**\n * @category Error handling\n */\n routeBrokenRulesOf(aRulesBrokenError: RulesBroken) {\n aRulesBrokenError.forEachRuleBroken((brokenRule) =>\n this.routeBrokenRule(brokenRule)\n );\n }\n\n /**\n * @category Error handling\n */\n routeBrokenRule(brokenRule: LabeledRule) {\n if (this.handles(brokenRule)) this.addBrokenRule(brokenRule);\n else this.routeNotHandledByThisBrokenRule(brokenRule);\n }\n\n protected routeNotHandledByThisBrokenRule(brokenRule: LabeledRule) {\n const assistantsHandlingRule = this.assistantsHandling(brokenRule);\n\n if (assistantsHandlingRule.length === 0) this.addBrokenRule(brokenRule);\n else this.addBrokenRuleToAll(assistantsHandlingRule, brokenRule);\n }\n\n protected addBrokenRuleToAll(\n assistantsHandlingAssertion: DraftAssistant<unknown, Model>[],\n brokenRule: LabeledRule\n ) {\n assistantsHandlingAssertion.forEach((assistant) =>\n assistant.addBrokenRule(brokenRule)\n );\n }\n\n protected assistantsHandling(assertion: LabeledRule) {\n return this.assistants.filter((assistant) => assistant.handles(assertion));\n }\n\n protected createComposedModels(): ComposedModels {\n // @ts-expect-error TypeScript can't infer the tuple type directly.\n return this.assistants.map((assistant) => assistant.createModel());\n }\n}\n","import { Assertion, Ruleset, LabelId } from \"../rule\";\nimport { FieldDraftAssistant } from \"./FieldDraftAssistant\";\nimport { SectionDraftAssistant } from \"./SectionDraftAssistant\";\n\nimport type { ModelFromContainer } from \"../types\";\n\n/**\n * Provides an assistant for the completion of an integer field,\n * represented by a string.\n *\n * @category Draft assistants\n */\nexport class IntegerDraftAssistant<ContainerModel = any> extends SectionDraftAssistant<\n number,\n ContainerModel,\n [string]\n> {\n static readonly defaultAssertionDescription = \"Invalid integer\";\n\n static for<ContainerModel>(\n assertionId: LabelId,\n modelFromContainer: ModelFromContainer<number, ContainerModel>\n ): IntegerDraftAssistant<ContainerModel> {\n const assertionIds = assertionId === \"\" ? [] : [assertionId];\n\n /** @ts-expect-error @see {@link https://github.com/microsoft/TypeScript/issues/5863 #5863} */\n return this.with(\n [this.createNumberAssistant()],\n (numberAsString) => this.createInteger(assertionId, numberAsString),\n modelFromContainer,\n assertionIds\n );\n }\n\n static forTopLevel(assertionId: LabelId) {\n return this.for(assertionId, this.topLevelModelFromContainer());\n }\n\n static createInteger(assertionId: LabelId, numberAsString: string) {\n Ruleset.ensureAll(this.createAssertionFor(assertionId, numberAsString));\n\n return Number(numberAsString);\n }\n\n static createNumberAssistant() {\n return FieldDraftAssistant.handling<number>(\"\", (number) => number.toString());\n }\n\n static createAssertionFor(assertionId: LabelId, numberAsString: string) {\n return Assertion.requiring(assertionId, this.defaultAssertionDescription, () =>\n /^[-+]?(\\d+)$/.test(numberAsString)\n );\n }\n\n innerAssistant() {\n return this.assistants[0];\n }\n\n setInnerModel(newModel: string) {\n this.innerAssistant().setModel(newModel);\n }\n\n getInnerModel() {\n return this.innerAssistant().getModel();\n }\n}\n","import { EventEmitter } from \"events\";\n\nimport type { DraftAssistant } from \"../draft-assistant\";\nimport type { DraftViewer } from \"../types\";\nimport type { LabeledRule } from \"../rule\";\n\n/**\n * Events emitted by a {@link DraftPublisher}.\n *\n * This allows consumers to subscribe to:\n * - `draft:updated`: when the draft model changes\n * - `assertions:added`: when a new failed assertion is reported\n * - `assertions:reset`: when all failed assertions are cleared\n *\n * @category Draft assistants\n */\nexport type PublisherEvents<Model = unknown> =\n | { \"draft:updated\": [Model] }\n | { \"assertions:added\": [LabeledRule] }\n | { \"assertions:reset\": [] };\n\n/**\n * Observes changes to a {@link DraftAssistant} by emitting structured events.\n *\n * `DraftPublisher` provides an alternative to the {@link DraftViewer} interface for reacting to changes in a draft.\n * Instead of relying on callbacks, it follows an event-driven approach using `EventEmitter`.\n *\n * This allows consumers to subscribe to {@link PublisherEvents}.\n *\n * This can be especially useful when integrating with frameworks or systems already based on events.\n *\n * @example\n * ```ts\n * const assistant = SectionDraftAssistant.handling(...);\n * const publisher = DraftPublisher.for(assistant);\n *\n * publisher.on(\"draft:updated\", (model) => {\n * console.log(\"Draft changed:\", model);\n * });\n * ```\n *\n * @template Model The type of model the assistant works with.\n *\n * @category Draft assistants\n */\nexport class DraftPublisher<Model = unknown>\n extends EventEmitter<PublisherEvents<Model>>\n implements DraftViewer<Model>\n{\n static for<Model = unknown>(anAssistant: DraftAssistant<Model, never>) {\n const instance = new this<Model>();\n anAssistant.accept(instance);\n return instance;\n }\n\n onDraftChanged(aModel: Model) {\n this.emit(\"draft:updated\", aModel);\n }\n\n onFailure(aFailedAsserion: LabeledRule) {\n this.emit(\"assertions:added\", aFailedAsserion);\n }\n\n onFailuresReset() {\n this.emit(\"assertions:reset\");\n }\n}\n"],"names":["and","not","identical"],"mappings":"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