A BuckleScript implementation of the Folktale validation applicative
NOTE: These are not bindings, this a ReasonML implementation of the
Validation
applicative.
I wanted a way to do validations for my server side project.
Not all of the Folktale/Validation functions will be implemented. Here is a list of the currently implemented functions:
All implemented functions are found in src/Validation.re
, They are all
documented with their Folktale style doc strings.
Add the bs-validation package to your project.
yarn add bs-validation
Add bs-validation
to your bsconfig.json
{
"dependencies": [ "bs-validation" ]
}
The library is exposed as a functor which accepts modules that implement the following type interface:
module type Foldable = {
type t('a);
let concat: (t('a), t('a)) => t('a);
};
module type Foldable = sig type 'a t val concat : 'a t -> 'a t -> 'a t end
All of the examples use an array based implementation of the Foldable
type:
module FoldableArray = {
type t('a) = array('a);
let concat = (x, y) => Belt_Array.concat(x, y);
};
module FoldableArray =
struct type 'a t = 'a array
let concat x y = Belt_Array.concat x y end
You import the module into your project by calling the Validation
functor
with your version of the Foldable
type.
module V = Validation.Make_validation(FoldableArray);
module V = Validation.Make_validation(FoldableArray)
Then you can use it to validate all of your things!
let lengthError = "Password must have more than 6 characters.";
let strengthError = "Password must contain a special character.";
let isPasswordLongEnough = (password) =>
String.length(password) > 6
? V.Success(password)
: V.Failure([|lengthError|]);
let isPasswordStrongEnough = (password) => {
let regex = [%bs.re "/[\\W]/"];
Js.Re.test(password, regex)
? V.Success(password)
: V.Failure([|strengthError|])
};
let isPasswordValid = (password) => {
V.Success()
|> V.concat(isPasswordLongEnough(password))
|> V.concat(isPasswordStrongEnough(password))
|> V.map((_) =>password)
};
describe("Folketale password validation example", () => {
test("should return the password", () => {
let password = "rosesarered$andstuff";
switch (isPasswordValid(password)) {
| Failure(f) => { Js.log(f); fail("unexpected_failure") }
| Success(p) => Expect.expect(p) |> Expect.toBe(password)
}
});
test("should return a single item failure", () => {
let password = "rosesarered";
switch (isPasswordValid(password)) {
| Failure(f) => Expect.expect(f) |> Expect.toBeSupersetOf([|strengthError|])
| Success(_) => fail("unexpected_success")
}
});
test("should return 2 items in the failure list", () => {
let password = "foo";
switch (isPasswordValid(password)) {
| Failure(f) => {
Expect.expect(f)
|> Expect.toBeSupersetOf([|lengthError, strengthError|])
}
| Success(_) => fail("unexpected_success")
}
});
});
let lengthError = "Password must have more than 6 characters."
let strengthError = "Password must contain a special character."
let isPasswordLongEnough password =
match (String.length password) > 6 with
| true -> ((V.Success (password))[@explicit_arity ])
| false -> ((V.Failure ([|lengthError|]))[@explicit_arity ])
let isPasswordStrongEnough password =
let regex = [%bs.re "/[\\W]/"] in
match Js.Re.test password regex with
| true -> ((V.Success (password))[@explicit_arity ])
| false -> ((V.Failure ([|strengthError|]))[@explicit_arity ])
let isPasswordValid password =
((((V.Success (()))[@explicit_arity ]) |>
(V.concat (isPasswordLongEnough password)))
|> (V.concat (isPasswordStrongEnough password)))
|> (V.map (fun _ -> password))
let _ =
describe "Folketale password validation example"
(fun () ->
test "should return the password"
(fun () ->
let password = "rosesarered$andstuff" in
match isPasswordValid password with
| ((Failure (f))[@explicit_arity ]) ->
(Js.log f; fail "unexpected_failure")
| ((Success (p))[@explicit_arity ]) ->
(Expect.expect p) |> (Expect.toBe password));
test "should return a single item failure"
(fun () ->
let password = "rosesarered" in
match isPasswordValid password with
| ((Failure (f))[@explicit_arity ]) ->
(Expect.expect f) |>
(Expect.toBeSupersetOf [|strengthError|])
| Success _ -> fail "unexpected_success");
test "should return 2 items in the failure list"
(fun () ->
let password = "foo" in
match isPasswordValid password with
| ((Failure (f))[@explicit_arity ]) ->
(Expect.expect f) |>
(Expect.toBeSupersetOf [|lengthError;strengthError|])
| Success _ -> fail "unexpected_success"))