On this pageFunctions
FieldValidation
/**
* Returns true when every `(state, rules)` pair in the input is
* acceptable per `isValid`. Use for form-level submit gates.
*/
(pairs: readonly Array<readonly [
{
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
},
Readonly<{
isEmpty: (value: string) => boolean
requiredMessage: Option<RuleMessage>
rules: readonly Array<Rule>
}>
]>): boolean/**
* Returns true when any state in the input has tag `Invalid`. Use for
* "this step/section has errors" affordances, independent of rules.
*/
(states: readonly Array<{
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
}>): boolean/** Creates a `Rule` that checks if a string is a valid email format. */
(message: RuleMessage): Rule/** Creates a `Rule` that checks if a string ends with a specified suffix. */
(
suffix: string,
message?: RuleMessage
): Rule/** Creates a `Rule` that checks if a string exactly matches an expected value. */
(
expected: string,
message?: RuleMessage
): Rule/** Creates a `Rule` that checks if a string contains a specified substring. */
(
substring: string,
message?: RuleMessage
): Rule/**
* Returns true when the state's tag is `Invalid`. Tag-only predicate;
* unlike `!isValid(rules)(state)`, this does not treat `NotValidated`
* or `Validating` as errors. Use for "has the user seen a rule failure
* on this field?" affordances like red borders or per-step error
* indicators.
*/
(state: {
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
}): boolean/**
* Returns true when the rules mark the field as required. Useful for
* rendering affordances like a `*` next to required field labels.
*/
(rules: Rules): boolean/**
* Returns true when the field's current state is acceptable given its
* rules. For required fields, only `Valid` returns `true`. For optional
* fields, `Valid` or `NotValidated` both return `true`. `Invalid` and
* `Validating` always return `false`.
*
* The name is distinct from the `Valid` tag on purpose: `isValid`
* answers "is this state an acceptable result?", which for an optional
* field is broader than `_tag === 'Valid'`. For pattern-matching on the
* state itself, check the `_tag` directly.
*/
(rules: Rules): (state: {
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
}) => boolean/** Creates a `Rule` that checks if a string does not exceed a maximum length. */
(
max: number,
message?: RuleMessage
): Rule/** Creates a `Rule` that checks if a string meets a minimum length. */
(
min: number,
message?: RuleMessage
): Rule/** Creates a `Rule` that checks if a string is one of a specified set of allowed values. */
(
values: readonly Array<string>,
message?: RuleMessage
): Rule/** Creates a `Rule` that checks if a string matches a regular expression. */
(
regex: RegExp,
message: RuleMessage
): Rule/** Creates a `Rule` that checks if a string begins with a specified prefix. */
(
prefix: string,
message?: RuleMessage
): Rule/**
* Creates a `Rule` that checks if a string is a valid URL format.
*
* By default the URL must include an `http://` or `https://` protocol.
* Pass `{ requireProtocol: false }` to accept bare domains.
*/
(options: Readonly<{
message: RuleMessage
requireProtocol: boolean
}>): Rule/**
* Validates a new value and returns the next field state.
*
* For required fields, an empty value produces `Invalid` with the
* required message. For optional fields, an empty value produces
* `NotValidated`. Non-empty values run through the field's rules;
* the first failure becomes `Invalid`, otherwise the result is `Valid`.
*/
(rules: Rules): (value: string) => {
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
}/**
* Like `validate` but collects every failing rule into the
* `Invalid` state's errors array instead of stopping at the first.
*/
(rules: Rules): (value: string) => {
_tag: "NotValidated"
value: string
} | {
_tag: "Validating"
value: string
} | {
_tag: "Valid"
value: string
} | {
_tag: "Invalid"
errors: readonly [string, string]
value: string
}/** Options accepted by `makeRules`. */
type MakeRulesOptions = Readonly<{
isEmpty: (value: string) => boolean
required: RuleMessage
rules: ReadonlyArray<Rule>
}>/** A tuple of a predicate and error message used for field validation. */
type Rule = readonly [Predicate.Predicate<string>, RuleMessage]/** An error message for a rule: either a static string, or a function that receives the invalid value. */
type RuleMessage = string | (value: string) => string/**
* A field's validation rules: the required message (if any), the list of rules,
* and an empty predicate. Produced by `makeRules`; consumed by the module's
* operations (`validate`, `validateAll`, `isValid`, `isRequired`, `allValid`).
* The fields are accessible but treating them as stable is discouraged.
* Prefer the operations so internal shape changes don't break callers.
*/
type Rules = Readonly<{
isEmpty: (value: string) => boolean
requiredMessage: Option.Option<RuleMessage>
rules: ReadonlyArray<Rule>
}>/** The four-state union that represents a field's value in the Model. */
const Field: Union<readonly [
CallableTaggedStruct<"NotValidated", {
value: String
}>,
CallableTaggedStruct<"Validating", {
value: String
}>,
CallableTaggedStruct<"Valid", {
value: String
}>,
CallableTaggedStruct<"Invalid", {
errors: NonEmptyArray<String>
value: String
}>
]>/** The `Invalid` state: one or more rules failed. Carries a non-empty `errors` array. */
const Invalid: CallableTaggedStruct<"Invalid", {
errors: NonEmptyArray<String>
value: String
}>/** The `NotValidated` state: user hasn't interacted yet. */
const NotValidated: CallableTaggedStruct<"NotValidated", {
value: String
}>/** The `Valid` state: every rule passed. */
const Valid: CallableTaggedStruct<"Valid", {
value: String
}>