Skip to content

Instantly share code, notes, and snippets.

@johnhaley81
Last active August 20, 2019 19:19
Show Gist options
  • Save johnhaley81/96f5cd04b067ccebd007bdd3e626866f to your computer and use it in GitHub Desktop.
Save johnhaley81/96f5cd04b067ccebd007bdd3e626866f to your computer and use it in GitHub Desktop.
open Relude.Globals;
module ParseError = Decode.ParseError;
module Decode = {
let isValidDate: 'a => bool = [%raw
{|
function isValidDate(date) {
return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
|}
];
module Option = {
include Decode.AsOption;
include Option;
include Option.Infix;
external toDate: Js.Json.t => Js.Date.t = "%identity";
let toDate = maybeDate =>
maybeDate |> isValidDate ? Some(maybeDate |> toDate) : None;
let date = json => date(json) <|> toDate(json);
let intFromString = string >> Option.flatMap(String.toInt);
let intFromNumberOrString = json =>
intFromNumber(json) <|> intFromString(json);
let floatFromString = string >> Option.flatMap(String.toFloat);
let floatFromNumberOrString = json =>
floatFromNumber(json) <|> floatFromString(json);
};
include Decode.AsResult.OfParseError;
module ResultUtil = {
include Result.WithError({
type t = ParseError.failure;
});
type r('a) = Result.t('a, ParseError.failure);
let note = failure =>
BsAbstract.Option.maybe(~f=Result.ok, ~default=failure |> Result.error);
};
module Infix = {
include ResultUtil.Infix;
include Relude.Extensions.Alt.AltInfix(ResultUtil.Alt);
};
include Infix;
external toDate: Js.Json.t => Js.Date.t = "%identity";
let toDate = maybeDate =>
maybeDate |> isValidDate
? maybeDate |> toDate |> Result.ok
: ParseError.Val(`ExpectedValidDate, maybeDate) |> Result.error;
let date = json => date(json) <|> toDate(json);
let intFromString = json =>
json
|> string
|> Result.flatMap(
String.toInt
>> Result.fromOption(ParseError.Val(`ExpectedInt, json)),
);
let intFromNumberOrString = json =>
intFromNumber(json) <|> intFromString(json);
let floatFromString = json =>
json
|> string
|> Result.flatMap(
String.toFloat
>> Result.fromOption(ParseError.Val(`ExpectedInt, json)),
);
let floatFromNumberOrString = json =>
floatFromNumber(json) <|> floatFromString(json);
let ok = Result.ok;
let parseStringToJson = str =>
try (str |> Js.Json.parseExn |> Result.ok) {
| _exn =>
ParseError.Val(`ExpectedValidOption, Js.Json.null) |> Result.error
};
let mapErrorToDebugString = result =>
result |> Result.mapError(ParseError.failureToDebugString);
};
module Encode = {
type encoder('a) = 'a => Js.Json.t;
[@bs.val] external null: Js.Json.t = "";
external string: string => Js.Json.t = "%identity";
external float: float => Js.Json.t = "%identity";
external int: int => Js.Json.t = "%identity";
external dict: Js_dict.t(Js.Json.t) => Js.Json.t = "%identity";
external boolean: bool => Js.Json.t = "%identity";
let char = Char.code >> String.fromCharCode >> string;
let date = Js.Date.toJSONUnsafe >> string;
let optional = encode =>
fun
| None => null
| Some(v) => encode(v);
let withDefault = (d, encode) =>
fun
| None => d
| Some(v) => encode(v);
let object_ = Js.Dict.fromList >> dict;
external jsonArray: array(Js.Json.t) => Js.Json.t = "%identity";
let array = encode => Array.map(encode) >> jsonArray;
let arrayOf = array;
let list = encode => List.map(encode) >> List.toArray >> jsonArray;
let pair = (encodeA, encodeB, (a, b)) =>
jsonArray([|encodeA(a), encodeB(b)|]);
let tuple2 = pair;
let tuple3 = (encodeA, encodeB, encodeC, (a, b, c)) =>
jsonArray([|encodeA(a), encodeB(b), encodeC(c)|]);
let tuple4 = (encodeA, encodeB, encodeC, encodeD, (a, b, c, d)) =>
jsonArray([|encodeA(a), encodeB(b), encodeC(c), encodeD(d)|]);
external stringArray: array(string) => Js.Json.t = "%identity";
external numberArray: array(float) => Js.Json.t = "%identity";
external boolArray: array(bool) => Js.Json.t = "%identity";
let encodeAny = x =>
x
|> Js.Json.stringifyAny
|> Option.flatMap(str =>
try (Some(str |> Js.Json.parseExn)) {
| _exn => None
}
)
|> Option.getOrElse(Js.Json.null);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment