Skip to content

Commit

Permalink
[@field.async]
Browse files Browse the repository at this point in the history
  • Loading branch information
alex35mil committed Feb 16, 2020
1 parent 5119a4c commit 18d6c5d
Show file tree
Hide file tree
Showing 32 changed files with 3,585 additions and 1,414 deletions.
31 changes: 13 additions & 18 deletions examples/src/LoginForm.re
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,8 @@ module LoginForm = [%form
password: string,
rememberMe: bool,
};
type output = input
];

let initialInput: LoginForm.input = {
email: "",
password: "",
rememberMe: false,
};

let validators: LoginForm.validators = {
email:
Some({
let validators = {
email: {
strategy: OnFirstSuccessOrFirstBlur,
validate: ({email}) => {
let emailRegex = [%bs.re {|/.*@.*\..+/|}];
Expand All @@ -26,25 +16,30 @@ let validators: LoginForm.validators = {
| _ => Ok(email)
};
},
}),
password:
Some({
},
password: {
strategy: OnFirstBlur,
validate: ({password}) =>
switch (password) {
| "" => Error("Password is required")
| _ => Ok(password)
},
}),
rememberMe: None,
},
rememberMe: None,
}
];

let initialInput: LoginForm.input = {
email: "",
password: "",
rememberMe: false,
};

[@react.component]
let make = () => {
let form =
LoginForm.useForm(
~initialInput,
~validators,
~onSubmit=(output, form) => {
Js.log2("Submitted with:", output);
Js.Global.setTimeout(
Expand Down
54 changes: 31 additions & 23 deletions examples/src/SignupForm.re
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
module SignupForm = [%form
type input = {
email: string,
email: [@field.async] string,
password: [@field.deps passwordConfirmation] string,
passwordConfirmation: string,
};
type output = input
];

let initialInput: SignupForm.input = {
email: "",
password: "",
passwordConfirmation: "",
};

let validators: SignupForm.validators = {
email:
Some({
let validators = {
email: {
strategy: OnFirstSuccessOrFirstBlur,
validate: ({email}) => {
let emailRegex = [%bs.re {|/.*@.*\..+/|}];
Expand All @@ -26,9 +16,20 @@ let validators: SignupForm.validators = {
| _ => Ok(email)
};
},
}),
password:
Some({
validateAsync: email =>
Js.Promise.(
email
->Api.validateEmail
->then_(
valid =>
valid
? Ok(email)->resolve
: Error("Email is already taken")->resolve,
_,
)
),
},
password: {
strategy: OnFirstSuccessOrFirstBlur,
validate: ({password}) => {
let minLength = 4;
Expand All @@ -39,9 +40,8 @@ let validators: SignupForm.validators = {
| _ => Ok(password)
};
},
}),
passwordConfirmation:
Some({
},
passwordConfirmation: {
strategy: OnFirstSuccessOrFirstBlur,
validate: ({password, passwordConfirmation}) =>
switch (passwordConfirmation) {
Expand All @@ -50,15 +50,21 @@ let validators: SignupForm.validators = {
Error("Password doesn't match")
| _ => Ok(passwordConfirmation)
},
}),
},
}
];

let initialInput: SignupForm.input = {
email: "",
password: "",
passwordConfirmation: "",
};

[@react.component]
let make = () => {
let form =
SignupForm.useForm(
~initialInput,
~validators,
~onSubmit=(output, form) => {
Js.log2("Submitted with:", output);
Js.Global.setTimeout(
Expand Down Expand Up @@ -94,11 +100,13 @@ let make = () => {
}
/>
{switch (form.emailResult()) {
| Some(Error(message)) =>
| Some(Validating(_)) =>
<div className="form-message"> "Checking..."->React.string </div>
| Some(Result(Error(message))) =>
<div className={Cn.make(["form-message", "failure"])}>
message->React.string
</div>
| Some(Ok(_)) =>
| Some(Result(Ok(_))) =>
<div className={Cn.make(["form-message", "success"])}>
{j||j}->React.string
</div>
Expand Down
73 changes: 60 additions & 13 deletions lib/ppx/AstHelpers.re
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,28 @@ module T = {
(
~name,
~loc,
~typ: FieldSpec.t => core_type,
fields: list(FieldSpec.t),
~typ:
(~validator: FieldValidator.t, ~output_type: FieldType.t) =>
core_type,
scheme: Scheme.t,
) =>
name
|> str(~loc)
|> Type.mk(
~kind=
Ptype_record(
fields
|> List.map((field: FieldSpec.t) =>
Type.field(
field.id |> Field.to_string |> str(~loc),
field |> typ,
)
scheme
|> List.map((entry: Scheme.entry) =>
switch (entry) {
| Field(field) =>
Type.field(
field.name |> str(~loc),
typ(
~validator=field.validator,
~output_type=field.output_type,
),
)
}
),
),
)
Expand Down Expand Up @@ -64,7 +72,9 @@ module E = {
let field = (~of_ as record, ~loc, field: Field.t) =>
Exp.field(
Exp.ident(Lident(record) |> lid(~loc)),
Lident(field |> Field.to_string) |> lid(~loc),
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
);

let field2 = (~of_ as (record1, record2), ~loc, field: Field.t) =>
Expand All @@ -73,25 +83,62 @@ module E = {
Exp.ident(Lident(record1) |> lid(~loc)),
Lident(record2) |> lid(~loc),
),
Lident(field |> Field.to_string) |> lid(~loc),
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
);

let ref_field = (~of_ as record, ~loc, field: Field.t) =>
Exp.field(
record |> ref_(~loc),
Lident(field |> Field.to_string) |> lid(~loc),
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
);

let update_field = (~of_ as record, ~with_ as value, ~loc, field: Field.t) =>
Exp.record(
[(Lident(field |> Field.to_string) |> lid(~loc), value)],
[
(
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
value,
),
],
Some(Exp.ident(Lident(record) |> lid(~loc))),
);

let update_field2 =
(~of_ as (record1, record2), ~with_ as value, ~loc, field: Field.t) =>
Exp.record(
[
(
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
value,
),
],
Some(
Exp.field(
Exp.ident(Lident(record1) |> lid(~loc)),
Lident(record2) |> lid(~loc),
),
),
);

let update_ref_field =
(~of_ as record, ~with_ as value, ~loc, field: Field.t) =>
Exp.record(
[(Lident(field |> Field.to_string) |> lid(~loc), value)],
[
(
switch (field) {
| Field(field) => Lident(field) |> lid(~loc)
},
value,
),
],
Some(record |> ref_(~loc)),
);

Expand Down
Loading

0 comments on commit 18d6c5d

Please sign in to comment.