Skip to content

Commit

Permalink
refactor(validation): Use a slightly more explicit api surface to def…
Browse files Browse the repository at this point in the history
…ine validations without the need for explicit lists
  • Loading branch information
Kevin COMBRIAT committed Jan 15, 2021
1 parent 1d1c84c commit e089476
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 29 deletions.
24 changes: 12 additions & 12 deletions example/Validations.res
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ module Label = {
type t = [#required | #email | #equals]
}

let required = {
Description.names: list{#required},
validator: ({label, value}) =>
let required = (
#name(#required),
({Validator.Args.label: label, value}) =>
switch value {
| "" => #error(#error(("required", label)))
| _ => #ok(value)
},
}
)

let emailRegEx = %re("/.+@.+/")

let email = {
Description.names: list{#email},
validator: ({label, value}) =>
let email = (
#name(#email),
({Validator.Args.label: label, value}) =>
if emailRegEx->Js.Re.test_(value) {
#ok(value)
} else {
#error(#error(("email", label)))
},
}
)

let equals = lens => {
Description.names: list{#equals},
validator: ({label, value, values}) =>
let equals = lens => (
#name(#equals),
({Validator.Args.label: label, value, values}) =>
if lens.Optic.Lens.get(values) == value {
#ok(value)
} else {
#error(#error(("equals", label)))
},
}
)
6 changes: 2 additions & 4 deletions src/Formidable.res
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,14 @@ module Make = (ValidationLabel: Type, Error: Type, Values: Values): (

let validationNames =
validations->Option.mapWithDefault([], validations =>
validations->ArrayExtra.flatMap(validation =>
validation->Validations.getNames->List.toArray
)
validations->ArrayExtra.flatMap(Validations.getNames)
)

let hasValidation = name => validationNames->Js.Array2.includes(name)

let validate = React.useCallback1((validationContext, values) =>
validations->Option.mapWithDefault(#valid, validations =>
switch validations->Array.keepMap(((strategy, {validator})) =>
switch validations->Array.keepMap(((strategy, (_, validator))) =>
if Validations.shouldValidate(~context=validationContext, ~strategy) {
switch validator({
Validations.Validator.Args.label: errorLabel->OptionExtra.or(label),
Expand Down
30 changes: 17 additions & 13 deletions src/FormidableValidations.res
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,38 @@ module Validator = {
}

module Description = {
type t<'values, 'value, 'error, 'label> = {
names: list<'label>,
validator: Validator.t<'values, 'value, 'error>,
}
@ocaml.doc(`Only the first "kind" is meant to be used by an application.
The second one is used only internally when composing validations`)
type kind<'label> = [#name('label) | #names(array<'label>)]

let resolveKind = (kind: kind<'label>) =>
switch kind {
| #name(label) => [label]
| #names(labels) => labels
}

type t<'values, 'value, 'error, 'label> = (kind<'label>, Validator.t<'values, 'value, 'error>)
}

type t<'values, 'value, 'error, 'label> = (
Strategy.t,
Description.t<'values, 'value, 'error, 'label>,
)

let compose = (
{Description.names: names, validator},
{Description.names: names', validator: validator'},
) => {
Description.names: names->List.concat(names'),
validator: field =>
let compose = ((names, validator), (names', validator')) => (
names->Description.resolveKind->Js.Array2.concat(names'->Description.resolveKind)->#names,
field =>
switch validator(field) {
| #ok(_) => validator'(field)
| #error(_) as error => error
},
}
)

let getStrategy = ((strategy, _)) => strategy

let getNames = ((_, {Description.names: names})) => names
let getNames = ((_, (names, _))) => names->Description.resolveKind

let getValidator = ((_, {Description.validator: validator})) => validator
let getValidator = ((_, (_, validator))) => validator

@ocaml.doc(`Returns true if a validation should be performed in the given context.
If no context is provided, always returns true`)
Expand Down

0 comments on commit e089476

Please sign in to comment.