UNPKG

rescript-schema

Version:

🧬 The fastest parser in the entire JavaScript ecosystem with a focus on small bundle size and top-notch DX

3,931 lines • 112 kB
function some(x) {
  if (x === undefined) {
    return {
      BS_PRIVATE_NESTED_SOME_NONE: 0
    };
  } else if (x !== null && x.BS_PRIVATE_NESTED_SOME_NONE !== undefined) {
    return {
      BS_PRIVATE_NESTED_SOME_NONE: x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0
    };
  } else {
    return x;
  }
}

function valFromOption(x) {
  if (x === null || x.BS_PRIVATE_NESTED_SOME_NONE === undefined) {
    return x;
  }
  let depth = x.BS_PRIVATE_NESTED_SOME_NONE;
  if (depth === 0) {
    return;
  } else {
    return {
      BS_PRIVATE_NESTED_SOME_NONE: depth - 1 | 0
    };
  }
}
/* No side effect */

function get$2(dict, k) {
  if ((k in dict)) {
    return some(dict[k]);
  }
  
}

let unsafeDeleteKey = (function (dict,key){
      delete dict[key];
     });
/* No side effect */

function length(xs) {
  let _x = xs;
  let _acc = 0;
  while (true) {
    let acc = _acc;
    let x = _x;
    if (x === 0) {
      return acc;
    }
    _acc = acc + 1 | 0;
    _x = x.tl;
    continue;
  }}

function fillAux(arr, _i, _x) {
  while (true) {
    let x = _x;
    let i = _i;
    if (x === 0) {
      return;
    }
    arr[i] = x.hd;
    _x = x.tl;
    _i = i + 1 | 0;
    continue;
  }}

function fromArray$1(a) {
  let _i = a.length - 1 | 0;
  let _res = /* [] */0;
  while (true) {
    let res = _res;
    let i = _i;
    if (i < 0) {
      return res;
    }
    _res = {
      hd: a[i],
      tl: res
    };
    _i = i - 1 | 0;
    continue;
  }}

function toArray$1(x) {
  let len = length(x);
  let arr = new Array(len);
  fillAux(arr, 0, x);
  return arr;
}
/* No side effect */

let idMap = {};

function create(str) {
  let v = idMap[str];
  if (v !== undefined) {
    let id = v + 1 | 0;
    idMap[str] = id;
    return str + ("/" + id);
  }
  idMap[str] = 1;
  return str;
}
/* No side effect */

// Generated by ReScript, PLEASE EDIT WITH CARE

let immutableEmpty = {};

function fromString(string) {
  let _idx = 0;
  while (true) {
    let idx = _idx;
    let match = string[idx];
    if (match === undefined) {
      return "\"" + string + "\"";
    }
    if (match === "\"") {
      return JSON.stringify(string);
    }
    _idx = idx + 1 | 0;
    continue;
  }}

function toArray(path) {
  if (path === "") {
    return [];
  } else {
    return JSON.parse(path.split("\"][\"").join("\",\""));
  }
}

function fromLocation(location) {
  return "[" + fromString(location) + "]";
}

function fromArray(array) {
  let len = array.length;
  if (len !== 1) {
    if (len !== 0) {
      return "[" + array.map(fromString).join("][") + "]";
    } else {
      return "";
    }
  } else {
    return "[" + fromString(array[0]) + "]";
  }
}

function concat(path, concatedPath) {
  return path + concatedPath;
}

let symbol = Symbol("rescript-schema");

let itemSymbol = Symbol("item");

let Raised = /* @__PURE__ */create("S_Core-RescriptSchema.Raised");

let globalConfig = {
  r: 0,
  u: "Strip",
  n: false
};

class RescriptSchemaError extends Error {
      constructor(code, flag, path) {
        super();
        this.flag = flag;
        this.code = code;
        this.path = path;
        this.s = symbol;
        this.RE_EXN_ID = Raised;
        this._1 = this;
        this.Error = this;
        this.name = "RescriptSchemaError";
      }
      get message() {
        return message(this);
      }
      get reason() {
        return reason(this);
      }
    }

function getOrRethrow(exn) {
  if ((exn&&exn.s===symbol)) {
    return exn;
  }
  throw exn;
}

function has(acc, flag) {
  return (acc & flag) !== 0;
}

function embed(b, value) {
  let e = b.g.e;
  let l = e.length;
  e[l] = value;
  return "e[" + l + "]";
}

function secondAllocate(v) {
  let b = this;
  b.l = b.l + "," + v;
}

function initialAllocate(v) {
  let b = this;
  b.l = v;
  b.a = secondAllocate;
}

function rootScope(flag) {
  let global = {
    c: "",
    l: "",
    a: initialAllocate,
    v: -1,
    o: flag,
    e: []
  };
  global.g = global;
  return global;
}

function allocateScope(b) {
  ((delete b.a));
  let varsAllocation = b.l;
  if (varsAllocation === "") {
    return b.c;
  } else {
    return "let " + varsAllocation + ";" + b.c;
  }
}

function varWithoutAllocation(global) {
  let newCounter = global.v + 1;
  global.v = newCounter;
  return "v" + newCounter;
}

function _var(_b) {
  return this.i;
}

function _notVar(b) {
  let val = this;
  let v = varWithoutAllocation(b.g);
  let i = val.i;
  if (i === "") {
    val.b.a(v);
  } else if (val.b.a !== (void 0)) {
    val.b.a(v + "=" + i);
  } else {
    b.c = b.c + (v + "=" + i + ";");
    b.g.a(v);
  }
  val.v = _var;
  val.i = v;
  return v;
}

function allocateVal(b) {
  let v = varWithoutAllocation(b.g);
  b.a(v);
  return {
    b: b,
    v: _var,
    i: v,
    a: false
  };
}

function objectJoin(inlinedLocation, value) {
  return inlinedLocation + ":" + value + ",";
}

function arrayJoin(_inlinedLocation, value) {
  return value + ",";
}

function make(b, isArray) {
  return {
    b: b,
    v: _notVar,
    i: "",
    a: false,
    j: isArray ? arrayJoin : objectJoin,
    c: 0,
    p: ""
  };
}

function add(objectVal, inlinedLocation, val) {
  objectVal[inlinedLocation] = val;
  if (val.a) {
    objectVal.p = objectVal.p + val.i + ",";
    objectVal.i = objectVal.i + objectVal.j(inlinedLocation, "a[" + (objectVal.c++) + "]");
  } else {
    objectVal.i = objectVal.i + objectVal.j(inlinedLocation, val.i);
  }
}

function merge(target, subObjectVal) {
  let inlinedLocations = Object.keys(subObjectVal);
  for (let idx = 7, idx_finish = inlinedLocations.length; idx < idx_finish; ++idx) {
    let inlinedLocation = inlinedLocations[idx];
    add(target, inlinedLocation, subObjectVal[inlinedLocation]);
  }
}

function complete(objectVal, isArray) {
  objectVal.i = isArray ? "[" + objectVal.i + "]" : "{" + objectVal.i + "}";
  if (objectVal.c) {
    objectVal.a = true;
    objectVal.i = "Promise.all([" + objectVal.p + "]).then(a=>(" + objectVal.i + "))";
  }
  return objectVal;
}

function addKey(b, input, key, val) {
  return input.v(b) + "[" + key + "]=" + val.i;
}

function set(b, input, val) {
  if (input === val) {
    return "";
  }
  let inputVar = input.v(b);
  let match = input.a;
  if (match) {
    let match$1 = val.a;
    if (!match$1) {
      return inputVar + "=Promise.resolve(" + val.i + ")";
    }
    
  } else {
    let match$2 = val.a;
    if (match$2) {
      input.a = true;
      return inputVar + "=" + val.i;
    }
    
  }
  return inputVar + "=" + val.i;
}

function get(b, targetVal, inlinedLocation) {
  let val = targetVal[inlinedLocation];
  if (val !== undefined) {
    return val;
  } else {
    return {
      b: b,
      v: _notVar,
      i: targetVal.v(b) + ("[" + inlinedLocation + "]"),
      a: false
    };
  }
}

function setInlined(b, input, inlined) {
  return input.v(b) + "=" + inlined;
}

function map(inlinedFn, input) {
  return {
    b: input.b,
    v: _notVar,
    i: inlinedFn + "(" + input.i + ")",
    a: false
  };
}

function transform(b, input, operation) {
  if (!input.a) {
    return operation(b, input);
  }
  let bb = {
    c: "",
    l: "",
    a: initialAllocate,
    g: b.g
  };
  let operationInput = {
    b: b,
    v: _var,
    i: varWithoutAllocation(bb.g),
    a: false
  };
  let operationOutputVal = operation(bb, operationInput);
  let operationCode = allocateScope(bb);
  return {
    b: input.b,
    v: _notVar,
    i: input.i + ".then(" + operationInput.v(b) + "=>{" + operationCode + "return " + operationOutputVal.i + "})",
    a: true
  };
}

function raise(b, code, path) {
  throw new RescriptSchemaError(code, b.g.o, path);
}

function embedSyncOperation(b, input, fn) {
  if (input.a) {
    return {
      b: input.b,
      v: _notVar,
      i: input.i + ".then(" + embed(b, fn) + ")",
      a: true
    };
  } else {
    return map(embed(b, fn), input);
  }
}

function embedAsyncOperation(b, input, fn) {
  if (!(b.g.o & 2)) {
    raise(b, "UnexpectedAsync", "");
  }
  let val = embedSyncOperation(b, input, fn);
  val.a = true;
  return val;
}

function failWithArg(b, path, fn, arg) {
  return embed(b, arg => raise(b, fn(arg), path)) + "(" + arg + ")";
}

function fail(b, message, path) {
  return embed(b, () => raise(b, {
    TAG: "OperationFailed",
    _0: message
  }, path)) + "()";
}

function effectCtx(b, selfSchema, path) {
  return {
    schema: selfSchema,
    fail: (message, customPathOpt) => {
      let customPath = customPathOpt !== undefined ? customPathOpt : "";
      return raise(b, {
        TAG: "OperationFailed",
        _0: message
      }, path + customPath);
    }
  };
}

function registerInvalidJson(b, selfSchema, path) {
  if (b.g.o & 8) {
    return raise(b, {
      TAG: "InvalidJsonSchema",
      _0: selfSchema
    }, path);
  }
  
}

function invalidOperation(b, path, description) {
  return raise(b, {
    TAG: "InvalidOperation",
    description: description
  }, path);
}

function withCatch(b, input, $$catch, appendSafe, fn) {
  let prevCode = b.c;
  b.c = "";
  let errorVar = varWithoutAllocation(b.g);
  let maybeResolveVal = $$catch(b, errorVar);
  let catchCode = "if(" + (errorVar + "&&" + errorVar + ".s===s") + "){" + b.c;
  b.c = "";
  let bb = {
    c: "",
    l: "",
    a: initialAllocate,
    g: b.g
  };
  let fnOutput = fn(bb);
  b.c = b.c + allocateScope(bb);
  let isNoop = fnOutput.i === input.i && b.c === "";
  if (appendSafe !== undefined) {
    appendSafe(b, fnOutput);
  }
  if (isNoop) {
    return fnOutput;
  }
  let isAsync = fnOutput.a;
  let output = input === fnOutput ? input : (
      appendSafe !== undefined ? fnOutput : ({
          b: b,
          v: _notVar,
          i: "",
          a: isAsync
        })
    );
  let catchCode$1 = maybeResolveVal !== undefined ? catchLocation => catchCode + (
      catchLocation === 1 ? "return " + maybeResolveVal.i : set(b, output, maybeResolveVal)
    ) + ("}else{throw " + errorVar + "}") : param => catchCode + "}throw " + errorVar;
  b.c = prevCode + ("try{" + b.c + (
    isAsync ? setInlined(b, output, fnOutput.i + ".catch(" + errorVar + "=>{" + catchCode$1(1) + "})") : set(b, output, fnOutput)
  ) + "}catch(" + errorVar + "){" + catchCode$1(0) + "}");
  return output;
}

function withPathPrepend(b, input, path, maybeDynamicLocationVar, appendSafe, fn) {
  if (path === "" && maybeDynamicLocationVar === undefined) {
    return fn(b, input, path);
  }
  try {
    return withCatch(b, input, (b, errorVar) => {
      b.c = errorVar + ".path=" + fromString(path) + "+" + (
        maybeDynamicLocationVar !== undefined ? "'[\"'+" + maybeDynamicLocationVar + "+'\"]'+" : ""
      ) + errorVar + ".path";
    }, appendSafe, b => fn(b, input, ""));
  } catch (exn) {
    let error = getOrRethrow(exn);
    throw new RescriptSchemaError(error.code, error.flag, path + "[]" + error.path);
  }
}

function typeFilterCode(b, schema, input, path) {
  let inputVar = input.v(b);
  return "if(" + schema.f(b, inputVar) + "){" + failWithArg(b, path, input => ({
    TAG: "InvalidType",
    expected: schema,
    received: input
  }), inputVar) + "}";
}

function parseWithTypeValidation(b, schema, input, path) {
  if (schema.f !== undefined && (b.g.o & 1 || schema.t.TAG === "literal")) {
    b.c = b.c + typeFilterCode(b, schema, input, path);
  }
  return schema.b(b, input, schema, path);
}

function noop(_b, input, param, param$1) {
  return input;
}

function invalidJson(b, input, selfSchema, path) {
  registerInvalidJson(b, selfSchema, path);
  return input;
}

function noopOperation(i) {
  return i;
}

function compile(builder, schema, flag) {
  if (flag & 8 && schema["~r"]().t.TAG === "option") {
    throw new RescriptSchemaError({
      TAG: "InvalidJsonSchema",
      _0: schema
    }, flag, "");
  }
  let b = rootScope(flag);
  let input = {
    b: b,
    v: _var,
    i: "i",
    a: false
  };
  let output = builder(b, input, schema, "");
  schema.i = output.a;
  if (b.l !== "") {
    b.c = "let " + b.l + ";" + b.c;
  }
  if (schema.f !== undefined && (flag & 1 || schema.t.TAG === "literal")) {
    b.c = typeFilterCode(b, schema, input, "") + b.c;
  }
  if (b.c === "" && output === input && !(flag & 22)) {
    return noopOperation;
  }
  let inlinedOutput = flag & 4 ? "void 0" : output.i;
  if (flag & 16) {
    inlinedOutput = "JSON.stringify(" + inlinedOutput + ")";
  }
  if (flag & 2 && !output.a) {
    inlinedOutput = "Promise.resolve(" + inlinedOutput + ")";
  }
  let inlinedFunction = "i=>{" + b.c + "return " + inlinedOutput + "}";
  let ctxVarValue1 = b.g.e;
  return new Function("e", "s", "return " + inlinedFunction)(ctxVarValue1, symbol);
}

function operationFn(s, o) {
  if ((o in s)) {
    return (s[o]);
  }
  let ss = o & 32 ? s["~r"]() : s;
  let f = compile(ss.b, ss, o);
  ((s[o] = f));
  return f;
}

function compile$1(schema, input, output, mode, typeValidationOpt) {
  let typeValidation = typeValidationOpt !== undefined ? typeValidationOpt : true;
  let flag = 0;
  let exit = 0;
  switch (output) {
    case "Output" :
    case "Input" :
      exit = 1;
      break;
    case "Assert" :
      flag = flag | 4;
      break;
    case "Json" :
      flag = flag | 8;
      break;
    case "JsonString" :
      flag = flag | 24;
      break;
  }
  if (exit === 1 && output === input) {
    throw new Error("[rescript-schema] Can't compile operation to converting value to self");
  }
  if (mode !== "Sync") {
    flag = flag | 2;
  }
  if (typeValidation) {
    flag = flag | 1;
  }
  if (input === "Output") {
    flag = flag | 32;
  }
  let fn = operationFn(schema, flag);
  if (input !== "JsonString") {
    return fn;
  }
  let flag$1 = flag;
  return jsonString => {
    try {
      return fn(JSON.parse(jsonString));
    } catch (exn) {
      throw new RescriptSchemaError({
        TAG: "OperationFailed",
        _0: exn.message
      }, flag$1, "");
    }
  };
}

function toSelf() {
  return this;
}

function onlyChild(factory, schema) {
  return function () {
    let reversed = schema["~r"]();
    if (reversed === schema) {
      return this;
    } else {
      return factory(reversed);
    }
  };
}

function value(literal) {
  return literal.value;
}

function isJsonable(literal) {
  return literal.j;
}

function toString(literal) {
  return literal.s;
}

function arrayFilterBuilder(b, inputVar, literal) {
  let items = literal.i;
  return inputVar + "!==" + embed(b, literal.value) + "&&(!Array.isArray(" + inputVar + ")||" + inputVar + ".length!==" + items.length + (
    items.length > 0 ? "||" + items.map((literal, idx) => literal.f(b, inputVar + "[" + idx + "]", literal)).join("||") : ""
  ) + ")";
}

function dictFilterBuilder(b, inputVar, literal) {
  let items = literal.i;
  let fields = Object.keys(items);
  let numberOfFields = fields.length;
  return inputVar + "!==" + embed(b, value) + "&&(typeof " + inputVar + "!==\"object\"||!" + inputVar + "||Object.keys(" + inputVar + ").length!==" + numberOfFields + (
    numberOfFields > 0 ? "||" + fields.map(field => {
        let literal = items[field];
        return literal.f(b, inputVar + "[" + fromString(field) + "]", literal);
      }).join("||") : ""
  ) + ")";
}

function inlinedStrictEqualFilterBuilder(param, inputVar, literal) {
  return inputVar + "!==" + literal.s;
}

function strictEqualFilterBuilder(b, inputVar, literal) {
  return inputVar + "!==" + embed(b, literal.value);
}

let undefined_value = undefined;

let $$undefined = {
  kind: "Undefined",
  value: undefined_value,
  s: "undefined",
  f: inlinedStrictEqualFilterBuilder,
  j: false
};

let null_value = null;

let $$null = {
  kind: "Null",
  value: null_value,
  s: "null",
  f: inlinedStrictEqualFilterBuilder,
  j: true
};

let nan_value = NaN;

function nan_f(param, inputVar, param$1) {
  return "!Number.isNaN(" + inputVar + ")";
}

let nan = {
  kind: "NaN",
  value: nan_value,
  s: "NaN",
  f: nan_f,
  j: false
};

function parseInternal(value) {
  let typeOfValue = typeof value;
  if (typeOfValue === "symbol") {
    return {
      kind: "Symbol",
      value: value,
      s: value.toString(),
      f: strictEqualFilterBuilder,
      j: false
    };
  } else if (typeOfValue === "boolean") {
    return {
      kind: "Boolean",
      value: value,
      s: value ? "true" : "false",
      f: inlinedStrictEqualFilterBuilder,
      j: true
    };
  } else if (typeOfValue === "string") {
    return {
      kind: "String",
      value: value,
      s: fromString(value),
      f: inlinedStrictEqualFilterBuilder,
      j: true
    };
  } else if (typeOfValue === "function") {
    return {
      kind: "Function",
      value: value,
      s: value.toString(),
      f: strictEqualFilterBuilder,
      j: false
    };
  } else if (typeOfValue === "object") {
    if (value === null) {
      return $$null;
    } else if (Array.isArray(value)) {
      let items = [];
      let isJsonable = true;
      let string = "[";
      for (let idx = 0, idx_finish = value.length; idx < idx_finish; ++idx) {
        let itemValue = value[idx];
        let itemLiteral = parseInternal(itemValue);
        if (isJsonable && !itemLiteral.j) {
          isJsonable = false;
        }
        if (idx !== 0) {
          string = string + ", ";
        }
        string = string + itemLiteral.s;
        items.push(itemLiteral);
      }
      return {
        kind: "Array",
        value: value,
        s: string + "]",
        f: arrayFilterBuilder,
        j: isJsonable,
        i: some(items)
      };
    } else if (value.constructor === Object) {
      let items$1 = {};
      let string$1 = "{ ";
      let isJsonable$1 = true;
      let fields = Object.keys(value);
      let numberOfFields = fields.length;
      for (let idx$1 = 0; idx$1 < numberOfFields; ++idx$1) {
        let field = fields[idx$1];
        let itemValue$1 = value[field];
        let itemLiteral$1 = parseInternal(itemValue$1);
        if (isJsonable$1 && !itemLiteral$1.j) {
          isJsonable$1 = false;
        }
        if (idx$1 !== 0) {
          string$1 = string$1 + ", ";
        }
        string$1 = string$1 + (fromString(field) + ": " + itemLiteral$1.s);
        items$1[field] = itemLiteral$1;
      }
      return {
        kind: "Dict",
        value: value,
        s: string$1 + " }",
        f: dictFilterBuilder,
        j: isJsonable$1,
        i: some(items$1)
      };
    } else {
      return {
        kind: "Object",
        value: value,
        s: Object.prototype.toString.call(value),
        f: strictEqualFilterBuilder,
        j: false
      };
    }
  } else if (typeOfValue === "undefined") {
    return $$undefined;
  } else if (typeOfValue === "number") {
    if (Number.isNaN(value)) {
      return nan;
    } else {
      return {
        kind: "Number",
        value: value,
        s: value.toString(),
        f: inlinedStrictEqualFilterBuilder,
        j: true
      };
    }
  } else {
    return {
      kind: "BigInt",
      value: value,
      s: value.toString() + "n",
      f: inlinedStrictEqualFilterBuilder,
      j: false
    };
  }
}

let parse = parseInternal;

function isAsync(schema) {
  let v = schema.i;
  if (v !== 0) {
    return v;
  }
  try {
    let b = rootScope(2);
    let input = {
      b: b,
      v: _var,
      i: "i",
      a: false
    };
    let output = schema.b(b, input, schema, "");
    schema.i = output.a;
    return schema.i;
  } catch (exn) {
    getOrRethrow(exn);
    return false;
  }
}

function reverse(schema) {
  return schema["~r"]();
}

function parseOrThrow(any, schema) {
  return operationFn(schema, 1)(any);
}

function parseJsonStringOrThrow(jsonString, schema) {
  let tmp;
  try {
    tmp = JSON.parse(jsonString);
  } catch (exn) {
    throw new RescriptSchemaError({
      TAG: "OperationFailed",
      _0: exn.message
    }, 1, "");
  }
  return parseOrThrow(tmp, schema);
}

function parseAsyncOrThrow(any, schema) {
  return operationFn(schema, 3)(any);
}

function convertOrThrow(input, schema) {
  return operationFn(schema, 0)(input);
}

function convertToJsonOrThrow(any, schema) {
  return operationFn(schema, 8)(any);
}

function convertToJsonStringOrThrow(input, schema) {
  return operationFn(schema, 24)(input);
}

function convertAsyncOrThrow(any, schema) {
  return operationFn(schema, 2)(any);
}

function reverseConvertOrThrow(value, schema) {
  return operationFn(schema, 32)(value);
}

function reverseConvertToJsonOrThrow(value, schema) {
  return operationFn(schema, 40)(value);
}

function reverseConvertToJsonStringOrThrow(value, schema, spaceOpt) {
  let space = spaceOpt !== undefined ? spaceOpt : 0;
  return JSON.stringify(reverseConvertToJsonOrThrow(value, schema), null, space);
}

function assertOrThrow(any, schema) {
  return operationFn(schema, 5)(any);
}

function wrapExnToFailure(exn) {
  if ((exn&&exn.s===symbol)) {
    return {
      success: false,
      error: exn
    };
  }
  throw exn;
}

function js_safe(fn) {
  try {
    return {
      success: true,
      value: fn()
    };
  } catch (exn) {
    return wrapExnToFailure(exn);
  }
}

function js_safeAsync(fn) {
  try {
    return fn().then(value => ({
      success: true,
      value: value
    }), wrapExnToFailure);
  } catch (exn) {
    return Promise.resolve(wrapExnToFailure(exn));
  }
}

function makeReverseSchema(name, tagged, metadataMap, builder, maybeTypeFilter) {
  return {
    t: tagged,
    n: name,
    "~r": toSelf,
    b: builder,
    f: maybeTypeFilter,
    i: 0,
    m: metadataMap
  };
}

function makeSchema(name, tagged, metadataMap, builder, maybeTypeFilter, reverse) {
  return {
    t: tagged,
    n: name,
    "~r": function () {
      let original = this;
      let reversed = reverse.call(original);
      let reversed$1 = original !== reversed && typeof reversed.t === "string" ? makeReverseSchema(reversed.n, reversed.t, reversed.m, reversed.b, reversed.f) : reversed;
      original["~r"] = () => reversed$1;
      reversed$1["~r"] = () => original;
      return reversed$1;
    },
    b: builder,
    f: maybeTypeFilter,
    i: 0,
    m: metadataMap
  };
}

function make$1(namespace, name) {
  return namespace + ":" + name;
}

let Id = {
  make: make$1
};

let empty = {};

function set$1(map, id, metadata) {
  if (map === empty) {
    return ({[id]:metadata});
  }
  let copy = Object.assign({}, map);
  copy[id] = metadata;
  return copy;
}

function get$1(schema, id) {
  return schema.m[id];
}

function set$2(schema, id, metadata) {
  let metadataMap = set$1(schema.m, id, metadata);
  return makeSchema(schema.n, schema.t, metadataMap, schema.b, schema.f, () => {
    let schema$1 = schema["~r"]();
    return makeReverseSchema(schema$1.n, schema$1.t, metadataMap, schema$1.b, schema$1.f);
  });
}

function primitiveName() {
  return this.t;
}

function makePrimitiveSchema(tagged, builder, maybeTypeFilter) {
  return makeSchema(primitiveName, tagged, empty, builder, maybeTypeFilter, toSelf);
}

function recursive(fn) {
  let r = "r" + globalConfig.r;
  globalConfig.r = globalConfig.r + 1 | 0;
  let placeholder = {
    m: empty,
    t: "unknown",
    n: () => "<recursive>",
    b: (b, input, param, param$1) => transform(b, input, (_b, input) => map(r, input)),
    "~r": () => makeReverseSchema(primitiveName, "unknown", empty, (_b, input, param, param$1) => map(r, input), undefined)
  };
  let schema = fn(placeholder);
  placeholder.f = schema.f;
  placeholder.t = schema.t;
  let initialParseOperationBuilder = schema.b;
  schema.b = (b, input, selfSchema, path) => {
    let inputVar = input.v(b);
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let opOutput = initialParseOperationBuilder(bb, input, selfSchema, "");
    let opBodyCode = allocateScope(bb) + ("return " + opOutput.i);
    b.c = b.c + ("let " + r + "=" + inputVar + "=>{" + opBodyCode + "};");
    return withPathPrepend(b, input, path, undefined, undefined, (b, input, param) => transform(b, input, (_b, input) => {
      let output = map(r, input);
      if (opOutput.a) {
        output.a = true;
        placeholder.b = (b, input, param, param$1) => transform(b, input, (_b, input) => {
          let output = map(r, input);
          output.a = true;
          return output;
        });
      }
      return output;
    }));
  };
  let initialReverse = schema["~r"].bind(schema);
  schema["~r"] = () => {
    let initialReversed = initialReverse();
    let reversed = makeReverseSchema(initialReversed.n, initialReversed.t, initialReversed.m, (b, input, selfSchema, path) => {
      let inputVar = input.v(b);
      let bb = {
        c: "",
        l: "",
        a: initialAllocate,
        g: b.g
      };
      let initialInput = {
        b: bb,
        v: input.v,
        i: input.i,
        a: input.a
      };
      let opOutput = initialReversed.b(bb, initialInput, selfSchema, "");
      let opBodyCode = allocateScope(bb) + ("return " + opOutput.i);
      b.c = b.c + ("let " + r + "=" + inputVar + "=>{" + opBodyCode + "};");
      return withPathPrepend(b, input, path, undefined, undefined, (_b, input, param) => map(r, input));
    }, initialReversed.f);
    reversed["~r"] = () => schema;
    schema["~r"] = () => reversed;
    return reversed;
  };
  return schema;
}

function setName(schema, name) {
  return makeSchema(() => name, schema.t, schema.m, schema.b, schema.f, () => schema["~r"]());
}

function removeTypeValidation(schema) {
  return makeSchema(schema.n, schema.t, schema.m, schema.b, undefined, () => schema["~r"]());
}

function internalRefine(schema, refiner) {
  return makeSchema(schema.n, schema.t, schema.m, (b, input, selfSchema, path) => transform(b, schema.b(b, input, schema, path), (b, input) => {
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let rCode = refiner(bb, input.v(bb), selfSchema, path);
    b.c = b.c + allocateScope(bb) + rCode;
    return input;
  }), schema.f, () => {
    let schema$1 = schema["~r"]();
    return makeReverseSchema(schema$1.n, schema$1.t, schema$1.m, (b, input, selfSchema, path) => {
      let input$1 = transform(b, input, (b, input) => {
        b.c = b.c + refiner(b, input.v(b), selfSchema, path);
        return input;
      });
      return schema$1.b(b, input$1, schema$1, path);
    }, schema$1.f);
  });
}

function refine(schema, refiner) {
  return internalRefine(schema, (b, inputVar, selfSchema, path) => embed(b, refiner(effectCtx(b, selfSchema, path))) + "(" + inputVar + ");");
}

function addRefinement(schema, metadataId, refinement, refiner) {
  let refinements = schema.m[metadataId];
  return internalRefine(set$2(schema, metadataId, refinements !== undefined ? refinements.concat(refinement) : [refinement]), refiner);
}

function transform$1(schema, transformer) {
  return makeSchema(schema.n, schema.t, schema.m, (b, input, selfSchema, path) => {
    let input$1 = schema.b(b, input, schema, path);
    let match = transformer(effectCtx(b, selfSchema, path));
    let parser = match.p;
    if (parser !== undefined) {
      if (match.a !== undefined) {
        return invalidOperation(b, path, "The S.transform doesn't allow parser and asyncParser at the same time. Remove parser in favor of asyncParser");
      } else {
        return embedSyncOperation(b, input$1, parser);
      }
    }
    let asyncParser = match.a;
    if (asyncParser !== undefined) {
      return embedAsyncOperation(b, input$1, asyncParser);
    } else if (match.s !== undefined) {
      return invalidOperation(b, path, "The S.transform parser is missing");
    } else {
      return input$1;
    }
  }, schema.f, () => {
    let schema$1 = schema["~r"]();
    return makeReverseSchema(primitiveName, "unknown", empty, (b, input, selfSchema, path) => {
      let match = transformer(effectCtx(b, selfSchema, path));
      let serializer = match.s;
      if (serializer === undefined) {
        if (match.a !== undefined || match.p !== undefined) {
          return invalidOperation(b, path, "The S.transform serializer is missing");
        } else {
          return schema$1.b(b, input, schema$1, path);
        }
      }
      let input$1 = embedSyncOperation(b, input, serializer);
      return schema$1.b(b, input$1, schema$1, path);
    }, undefined);
  });
}

function custom(name, definer) {
  return makeSchema(() => name, "unknown", empty, (b, input, selfSchema, path) => {
    registerInvalidJson(b, selfSchema, path);
    let match = definer(effectCtx(b, selfSchema, path));
    let parser = match.p;
    if (parser !== undefined) {
      if (match.a !== undefined) {
        return invalidOperation(b, path, "The S.custom doesn't allow parser and asyncParser at the same time. Remove parser in favor of asyncParser");
      } else {
        return embedSyncOperation(b, input, parser);
      }
    }
    let asyncParser = match.a;
    if (asyncParser !== undefined) {
      return embedAsyncOperation(b, input, asyncParser);
    } else if (match.s !== undefined) {
      return invalidOperation(b, path, "The S.custom parser is missing");
    } else {
      return input;
    }
  }, undefined, () => makeReverseSchema(() => name, "unknown", empty, (b, input, selfSchema, path) => {
    registerInvalidJson(b, selfSchema, path);
    let match = definer(effectCtx(b, selfSchema, path));
    let serializer = match.s;
    if (serializer !== undefined) {
      return embedSyncOperation(b, input, serializer);
    } else if (match.a !== undefined || match.p !== undefined) {
      return invalidOperation(b, path, "The S.custom serializer is missing");
    } else {
      return input;
    }
  }, undefined));
}

function literal(value) {
  let literal$1 = parseInternal(value);
  return makeSchema(() => literal$1.s, {
    TAG: "literal",
    _0: literal$1
  }, empty, literal$1.j ? noop : invalidJson, (b, inputVar) => literal$1.f(b, inputVar, literal$1), toSelf);
}

let unit = literal((void 0));

let defaultMetadataId = "rescript-schema:Option.default";

function name() {
  return this.t._0.n() + " | undefined";
}

function $$default(schema) {
  return schema.m[defaultMetadataId];
}

function makeBuilder(isNullInput, isNullOutput) {
  return (b, input, selfSchema, path) => {
    let childSchema = selfSchema.t._0;
    let childSchemaTag = childSchema.t.TAG;
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let itemInput = !(b.g.o & 1) && (childSchema.t === "unknown" || childSchemaTag === "option" || childSchemaTag === "literal" && childSchema.t._0.value === (void 0)) ? ({
        b: bb,
        v: _notVar,
        i: embed(bb, valFromOption) + "(" + input.v(b) + ")",
        a: false
      }) : input;
    let itemOutput = childSchema.b(bb, itemInput, childSchema, path);
    let itemCode = allocateScope(bb);
    let inputLiteral = isNullInput ? "null" : "void 0";
    let ouputLiteral = isNullOutput ? "null" : "void 0";
    let isTransformed = inputLiteral !== ouputLiteral || itemOutput !== input;
    let output = isTransformed ? ({
        b: b,
        v: _notVar,
        i: "",
        a: itemOutput.a
      }) : input;
    if (itemCode !== "" || isTransformed) {
      b.c = b.c + ("if(" + input.v(b) + "!==" + inputLiteral + "){" + itemCode + set(b, output, itemOutput) + "}" + (
        inputLiteral !== ouputLiteral || output.a ? "else{" + set(b, output, {
            b: b,
            v: _notVar,
            i: ouputLiteral,
            a: false
          }) + "}" : ""
      ));
    }
    return output;
  };
}

function maybeTypeFilter(schema, inlinedNoneValue) {
  if (schema.f !== undefined) {
    return (b, inputVar) => inputVar + "!==" + inlinedNoneValue + "&&(" + schema.f(b, inputVar) + ")";
  }
  
}

function factory(schema) {
  return makeSchema(name, {
    TAG: "option",
    _0: schema
  }, empty, makeBuilder(false, false), maybeTypeFilter(schema, "void 0"), onlyChild(factory, schema));
}

function getWithDefault(schema, $$default) {
  return makeSchema(schema.n, schema.t, set$1(schema.m, defaultMetadataId, $$default), (b, input, param, path) => transform(b, schema.b(b, input, schema, path), (b, input) => {
    let inputVar = input.v(b);
    let tmp;
    tmp = $$default.TAG === "Value" ? embed(b, $$default._0) : embed(b, $$default._0) + "()";
    return {
      b: b,
      v: _notVar,
      i: inputVar + "===void 0?" + tmp + ":" + inputVar,
      a: false
    };
  }), schema.f, () => {
    let reversed = schema["~r"]();
    if (reversed.t.TAG === "option") {
      return reversed.t._0;
    } else {
      return reversed;
    }
  });
}

function getOr(schema, defalutValue) {
  return getWithDefault(schema, {
    TAG: "Value",
    _0: defalutValue
  });
}

function getOrWith(schema, defalutCb) {
  return getWithDefault(schema, {
    TAG: "Callback",
    _0: defalutCb
  });
}

function factory$1(schema) {
  return makeSchema(() => schema.n() + " | null", {
    TAG: "null",
    _0: schema
  }, empty, makeBuilder(true, false), maybeTypeFilter(schema, "null"), () => {
    let child = schema["~r"]();
    return makeReverseSchema(name, {
      TAG: "option",
      _0: child
    }, empty, makeBuilder(false, true), maybeTypeFilter(schema, "void 0"));
  });
}

function nullable(schema) {
  return factory(factory$1(schema));
}

function builder(b, input, selfSchema, path) {
  b.c = b.c + failWithArg(b, path, input => ({
    TAG: "InvalidType",
    expected: selfSchema,
    received: input
  }), input.i) + ";";
  return input;
}

let schema = makeSchema(primitiveName, "never", empty, builder, undefined, toSelf);

let metadataId = "rescript-schema:Array.refinements";

function refinements(schema) {
  let m = schema.m[metadataId];
  if (m !== undefined) {
    return m;
  } else {
    return [];
  }
}

function typeFilter(_b, inputVar) {
  return "!Array.isArray(" + inputVar + ")";
}

function name$1() {
  return "array<" + this.t._0.n() + ">";
}

function factory$2(schema) {
  return makeSchema(name$1, {
    TAG: "array",
    _0: schema
  }, empty, (b, input, param, path) => {
    let inputVar = input.v(b);
    let iteratorVar = varWithoutAllocation(b.g);
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let itemInput = {
      b: bb,
      v: _notVar,
      i: inputVar + "[" + iteratorVar + "]",
      a: false
    };
    let itemOutput = withPathPrepend(bb, itemInput, path, iteratorVar, undefined, (b, input, path) => parseWithTypeValidation(b, schema, input, path));
    let itemCode = allocateScope(bb);
    let isTransformed = itemInput !== itemOutput;
    let output = isTransformed ? ({
        b: b,
        v: _notVar,
        i: "new Array(" + inputVar + ".length)",
        a: false
      }) : input;
    if (isTransformed || itemCode !== "") {
      b.c = b.c + ("for(let " + iteratorVar + "=0;" + iteratorVar + "<" + inputVar + ".length;++" + iteratorVar + "){" + itemCode + (
        isTransformed ? addKey(b, output, iteratorVar, itemOutput) : ""
      ) + "}");
    }
    if (itemOutput.a) {
      return {
        b: output.b,
        v: _notVar,
        i: "Promise.all(" + output.i + ")",
        a: true
      };
    } else {
      return output;
    }
  }, typeFilter, onlyChild(factory$2, schema));
}

function typeFilter$1(b, inputVar) {
  let tagged = this.t;
  let code = "typeof " + inputVar + "!==\"object\"||!" + inputVar + (
    tagged.unknownKeys === "Strict" ? "||Array.isArray(" + inputVar + ")" : ""
  );
  let items = tagged.items;
  for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
    let match = items[idx];
    let schema = match.schema;
    if (schema.t.TAG === "literal") {
      code = code + "||" + schema.f(b, inputVar + ("[" + match.inlinedLocation + "]"));
    }
    
  }
  return code;
}

function name$2() {
  let tagged = this.t;
  if (tagged.items.length === 0) {
    return "{}";
  } else {
    return "{ " + tagged.items.map(item => item.location + ": " + item.schema.n() + ";").join(" ") + " }";
  }
}

function setUnknownKeys(schema, unknownKeys, deep) {
  let match = schema.t;
  if (typeof match !== "object") {
    return schema;
  }
  if (match.TAG !== "object") {
    return schema;
  }
  if (match.unknownKeys === unknownKeys) {
    return schema;
  }
  let advanced = match.advanced;
  let items = match.items;
  let tagged;
  if (deep) {
    let newItems = [];
    let newFields = {};
    for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
      let item = items[idx];
      let newSchema = setUnknownKeys(item.schema, unknownKeys, deep);
      let newItem = newSchema === item.schema ? item : ({
          schema: newSchema,
          location: item.location,
          inlinedLocation: item.inlinedLocation
        });
      newFields[item.location] = newItem;
      newItems.push(newItem);
    }
    tagged = {
      TAG: "object",
      items: newItems,
      fields: newFields,
      unknownKeys: unknownKeys,
      advanced: advanced
    };
  } else {
    tagged = {
      TAG: "object",
      items: items,
      fields: match.fields,
      unknownKeys: unknownKeys,
      advanced: advanced
    };
  }
  return {
    t: tagged,
    n: schema.n,
    "~r": schema["~r"],
    b: schema.b,
    f: schema.f,
    i: schema.i,
    m: schema.m
  };
}

function strip(schema) {
  return setUnknownKeys(schema, "Strip", false);
}

function deepStrip(schema) {
  return setUnknownKeys(schema, "Strip", true);
}

function strict(schema) {
  return setUnknownKeys(schema, "Strict", false);
}

function deepStrict(schema) {
  return setUnknownKeys(schema, "Strict", true);
}

function name$3() {
  return "[" + this.t.items.map(item => item.schema.n()).join(", ") + "]";
}

function typeFilter$2(b, inputVar) {
  let items = this.t.items;
  let length = items.length;
  let code = typeFilter(b, inputVar) + ("||" + inputVar + ".length!==" + length);
  for (let idx = 0; idx < length; ++idx) {
    let match = items[idx];
    let schema = match.schema;
    if (schema.t.TAG === "literal") {
      code = code + "||" + schema.f(b, inputVar + ("[" + match.inlinedLocation + "]"));
    }
    
  }
  return code;
}

function typeFilter$3(_b, inputVar) {
  return "typeof " + inputVar + "!==\"object\"||!" + inputVar;
}

function factory$3(schema) {
  return makeSchema(() => "dict<" + schema.n() + ">", {
    TAG: "dict",
    _0: schema
  }, empty, (b, input, param, path) => {
    let inputVar = input.v(b);
    let keyVar = varWithoutAllocation(b.g);
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let itemInput = {
      b: bb,
      v: _notVar,
      i: inputVar + "[" + keyVar + "]",
      a: false
    };
    let itemOutput = withPathPrepend(bb, itemInput, path, keyVar, undefined, (b, input, path) => parseWithTypeValidation(b, schema, input, path));
    let itemCode = allocateScope(bb);
    let isTransformed = itemInput !== itemOutput;
    let output = isTransformed ? ({
        b: b,
        v: _notVar,
        i: "{}",
        a: false
      }) : input;
    if (isTransformed || itemCode !== "") {
      b.c = b.c + ("for(let " + keyVar + " in " + inputVar + "){" + itemCode + (
        isTransformed ? addKey(b, output, keyVar, itemOutput) : ""
      ) + "}");
    }
    if (!itemOutput.a) {
      return output;
    }
    let resolveVar = varWithoutAllocation(b.g);
    let rejectVar = varWithoutAllocation(b.g);
    let asyncParseResultVar = varWithoutAllocation(b.g);
    let counterVar = varWithoutAllocation(b.g);
    let outputVar = output.v(b);
    return {
      b: b,
      v: _notVar,
      i: "new Promise((" + resolveVar + "," + rejectVar + ")=>{let " + counterVar + "=Object.keys(" + outputVar + ").length;for(let " + keyVar + " in " + outputVar + "){" + outputVar + "[" + keyVar + "].then(" + asyncParseResultVar + "=>{" + outputVar + "[" + keyVar + "]=" + asyncParseResultVar + ";if(" + counterVar + "--===1){" + resolveVar + "(" + outputVar + ")}}," + rejectVar + ")}})",
      a: true
    };
  }, typeFilter$3, onlyChild(factory$3, schema));
}

let schema$1 = makeSchema(primitiveName, "unknown", empty, invalidJson, undefined, toSelf);

let metadataId$1 = "rescript-schema:String.refinements";

function refinements$1(schema) {
  let m = schema.m[metadataId$1];
  if (m !== undefined) {
    return m;
  } else {
    return [];
  }
}

let cuidRegex = /^c[^\s-]{8,}$/i;

let uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i;

let emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;

let datetimeRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;

function typeFilter$4(_b, inputVar) {
  return "typeof " + inputVar + "!==\"string\"";
}

let schema$2 = makePrimitiveSchema("string", noop, typeFilter$4);

function factory$4(schema, spaceOpt) {
  let space = spaceOpt !== undefined ? spaceOpt : 0;
  return makeSchema(primitiveName, "string", empty, (b, input, param, path) => {
    let jsonVal = allocateVal(b);
    b.c = b.c + ("try{" + jsonVal.i + "=JSON.parse(" + input.i + ")}catch(t){" + failWithArg(b, path, message => ({
      TAG: "OperationFailed",
      _0: message
    }), "t.message") + "}");
    return parseWithTypeValidation(b, schema, jsonVal, path);
  }, typeFilter$4, () => {
    let reversed = schema["~r"]();
    return makeReverseSchema(reversed.n, reversed.t, reversed.m, (b, input, param, path) => {
      let prevFlag = b.g.o;
      b.g.o = prevFlag | 8;
      if (reversed.t.TAG === "option") {
        raise(b, {
          TAG: "InvalidJsonSchema",
          _0: reversed
        }, "");
      }
      let output = {
        b: b,
        v: _notVar,
        i: "JSON.stringify(" + reversed.b(b, input, reversed, path).i + (
          space > 0 ? ",null," + space : ""
        ) + ")",
        a: false
      };
      b.g.o = prevFlag;
      return output;
    }, reversed.f);
  });
}

function typeFilter$5(_b, inputVar) {
  return "typeof " + inputVar + "!==\"boolean\"";
}

let schema$3 = makePrimitiveSchema("boolean", noop, typeFilter$5);

let metadataId$2 = "rescript-schema:Int.refinements";

function refinements$2(schema) {
  let m = schema.m[metadataId$2];
  if (m !== undefined) {
    return m;
  } else {
    return [];
  }
}

function refinement(inputVar) {
  return inputVar + ">2147483647||" + inputVar + "<-2147483648||" + inputVar + "%1!==0";
}

function typeFilter$6(_b, inputVar) {
  return "typeof " + inputVar + "!==\"number\"||" + refinement(inputVar);
}

let schema$4 = makePrimitiveSchema("int32", noop, typeFilter$6);

let metadataId$3 = "rescript-schema:Float.refinements";

function refinements$3(schema) {
  let m = schema.m[metadataId$3];
  if (m !== undefined) {
    return m;
  } else {
    return [];
  }
}

function typeFilter$7(_b, inputVar) {
  return "typeof " + inputVar + "!==\"number\"" + (
    globalConfig.n ? "" : "||Number.isNaN(" + inputVar + ")"
  );
}

let schema$5 = makePrimitiveSchema("number", noop, typeFilter$7);

function typeFilter$8(_b, inputVar) {
  return "typeof " + inputVar + "!==\"bigint\"";
}

let schema$6 = makePrimitiveSchema("bigint", invalidJson, typeFilter$8);

function parse$1(b, schemas, path, input, output) {
  let isMultiple = schemas.length > 1;
  let loop = (idx, errorCodes) => {
    if (idx === schemas.length) {
      return failWithArg(b, path, internalErrors => ({
        TAG: "InvalidUnion",
        _0: internalErrors
      }), "[" + errorCodes + "]");
    }
    let schema = schemas[idx];
    let parserCode;
    try {
      let bb = {
        c: "",
        l: "",
        a: initialAllocate,
        g: b.g
      };
      let itemOutput = schema.b(bb, input, schema, "");
      if (itemOutput !== input) {
        bb.c = bb.c + set(bb, output, itemOutput);
      }
      parserCode = allocateScope(bb);
    } catch (exn) {
      parserCode = "throw " + embed(b, getOrRethrow(exn));
    }
    if (!isMultiple) {
      return parserCode;
    }
    let errorVar = "e" + idx;
    return "try{" + parserCode + "}catch(" + errorVar + "){" + loop(idx + 1 | 0, errorCodes + errorVar + ",") + "}";
  };
  return loop(0, "");
}

function factory$5(schemas) {
  let len = schemas.length;
  if (len === 1) {
    return schemas[0];
  }
  if (len !== 0) {
    return makeSchema(() => schemas.map(s => s.n()).join(" | "), {
      TAG: "union",
      _0: schemas
    }, empty, (b, input, selfSchema, path) => {
      let schemas = selfSchema.t._0;
      let inputVar = input.v(b);
      let output = {
        b: b,
        v: _notVar,
        i: inputVar,
        a: false
      };
      let byTypeFilter = {};
      let typeFilters = [];
      for (let idx = 0, idx_finish = schemas.length; idx < idx_finish; ++idx) {
        let schema = schemas[idx];
        let typeFilterCode = schema.f !== undefined ? schema.f(b, inputVar) : "";
        let schemas$1 = get$2(byTypeFilter, typeFilterCode);
        if (schemas$1 !== undefined) {
          schemas$1.push(schema);
        } else {
          typeFilters.push(typeFilterCode);
          byTypeFilter[typeFilterCode] = [schema];
        }
      }
      let loopTypeFilters = (_idx, _maybeUnknownParser) => {
        while (true) {
          let maybeUnknownParser = _maybeUnknownParser;
          let idx = _idx;
          if (idx === typeFilters.length) {
            if (maybeUnknownParser !== undefined) {
              return maybeUnknownParser;
            } else {
              return failWithArg(b, path, received => ({
                TAG: "InvalidType",
                expected: selfSchema,
                received: received
              }), inputVar);
            }
          }
          let typeFilterCode = typeFilters[idx];
          let schemas = byTypeFilter[typeFilterCode];
          let parserCode = parse$1(b, schemas, path, input, output);
          if (typeFilterCode === "") {
            _maybeUnknownParser = parserCode;
            _idx = idx + 1 | 0;
            continue;
          }
          let tmp = parserCode === "" ? "" : "}else{" + parserCode;
          return "if(" + typeFilterCode + "){" + loopTypeFilters(idx + 1 | 0, maybeUnknownParser) + tmp + "}";
        }      };
      b.c = b.c + loopTypeFilters(0, undefined);
      if (output.a) {
        return {
          b: b,
          v: _notVar,
          i: "Promise.resolve(" + output.i + ")",
          a: true
        };
      } else {
        return output;
      }
    }, undefined, function () {
      let original = this;
      let schemas = original.t._0;
      return factory$5(schemas.map(s => s["~r"]()));
    });
  }
  throw new Error("[rescript-schema] S.union requires at least one item");
}

function $$enum(values) {
  return factory$5(values.map(literal));
}

function preprocess(schema, transformer) {
  let unionSchemas = schema.t;
  if (typeof unionSchemas === "object" && unionSchemas.TAG === "union") {
    return makeSchema(schema.n, {
      TAG: "union",
      _0: unionSchemas._0.map(unionSchema => preprocess(unionSchema, transformer))
    }, schema.m, schema.b, schema.f, schema["~r"]);
  }
  return makeSchema(schema.n, schema.t, schema.m, (b, input, selfSchema, path) => {
    let match = transformer(effectCtx(b, selfSchema, path));
    let parser = match.p;
    if (parser !== undefined) {
      if (match.a !== undefined) {
        return invalidOperation(b, path, "The S.preprocess doesn't allow parser and asyncParser at the same time. Remove parser in favor of asyncParser");
      } else {
        return parseWithTypeValidation(b, schema, embedSyncOperation(b, input, parser), path);
      }
    }
    let asyncParser = match.a;
    if (asyncParser !== undefined) {
      return transform(b, embedAsyncOperation(b, input, asyncParser), (b, input) => parseWithTypeValidation(b, schema, input, path));
    } else {
      return parseWithTypeValidation(b, schema, input, path);
    }
  }, undefined, () => {
    let reversed = schema["~r"]();
    return makeReverseSchema(primitiveName, reversed.t, empty, (b, input, param, path) => {
      let input$1 = reversed.b(b, input, reversed, path);
      let match = transformer(effectCtx(b, schema, path));
      let serializer = match.s;
      if (serializer !== undefined) {
        return embedSyncOperation(b, input$1, serializer);
      } else {
        return input$1;
      }
    }, undefined);
  });
}

function list(schema) {
  return transform$1(factory$2(schema), param => ({
    p: fromArray$1,
    s: toArray$1
  }));
}

function json(validate) {
  return makeSchema(() => "JSON", {
    TAG: "JSON",
    validated: validate
  }, empty, validate ? (b, input, selfSchema, path) => {
      let parse = (input, pathOpt) => {
        let path$1 = pathOpt !== undefined ? pathOpt : path;
        let match = typeof input;
        if (match === "string" || match === "boolean") {
          return input;
        }
        if (match !== "object") {
          if (match === "number" && !Number.isNaN(input)) {
            return input;
          } else {
            return raise(b, {
              TAG: "InvalidType",
              expected: selfSchema,
              received: input
            }, path$1);
          }
        }
        if (input === null) {
          return input;
        }
        if (Array.isArray(input)) {
          let output = [];
          for (let idx = 0, idx_finish = input.length; idx < idx_finish; ++idx) {
            let inputItem = input[idx];
            let location = idx.toString();
            output.push(parse(inputItem, path$1 + ("[" + fromString(location) + "]")));
          }
          return output;
        }
        let keys = Object.keys(input);
        let output$1 = {};
        for (let idx$1 = 0, idx_finish$1 = keys.length; idx$1 < idx_finish$1; ++idx$1) {
          let key = keys[idx$1];
          let field = input[key];
          output$1[key] = parse(field, path$1 + ("[" + fromString(key) + "]"));
        }
        return output$1;
      };
      return map(embed(b, parse), input);
    } : noop, undefined, function () {
    if (validate) {
      return json(false);
    } else {
      return this;
    }
  });
}

let Catch = {};

function passingTypeFilter(_b, param) {
  return "false";
}

function $$catch(schema, getFallbackValue) {
  return makeSchema(schema.n, schema.t, schema.m, (b, input, selfSchema, path) => {
    let inputVar = input.v(b);
    return withCatch(b, input, (b, errorVar) => ({
      b: b,
      v: _notVar,
      i: embed(b, (input, internalError) => getFallbackValue({
        e: internalError,
        i: input,
        s: selfSchema,
        f: (message, customPathOpt) => {
          let customPath = customPathOpt !== undefined ? customPathOpt : "";
          return raise(b, {
            TAG: "OperationFailed",
            _0: message
          }, path + customPath);
        }
      })) + "(" + inputVar + "," + errorVar + ")",
      a: false
    }), undefined, b => parseWithTypeValidation(b, schema, input, path));
  }, schema.t.TAG === "literal" ? passingTypeFilter : undefined, () => schema["~r"]());
}

let deprecationMetadataId = "rescript-schema:deprecation";

function deprecate(schema, message) {
  return set$2(schema, deprecationMetadataId, message);
}

function deprecation(schema) {
  return schema.m[deprecationMetadataId];
}

let descriptionMetadataId = "rescript-schema:description";

function describe(schema, description) {
  return set$2(schema, descriptionMetadataId, description);
}

function description(schema) {
  return schema.m[descriptionMetadataId];
}

function getFullDitemPath(ditem) {
  switch (ditem.k) {
    case 0 :
      return "[" + ditem.inlinedLocation + "]";
    case 1 :
      return getFullDitemPath(ditem.of) + ditem.p;
    case 2 :
      return ditem.p;
  }
}

function getItemReversed(item) {
  switch (item.k) {
    case 1 :
      let schema = item.schema;
      let location = item.location;
      if (schema !== undefined) {
        return schema["~r"]();
      }
      let targetReversed = getItemReversed(item.of);
      let match = targetReversed.t;
      let maybeReversedItem;
      if (typeof match !== "object") {
        maybeReversedItem = undefined;
      } else {
        switch (match.TAG) {
          case "object" :
            maybeReversedItem = match.fields[location];
            break;
          case "tuple" :
            maybeReversedItem = match.items[location];
            break;
          default:
            maybeReversedItem = undefined;
        }
      }
      if (maybeReversedItem === undefined) {
        let message = "Impossible to reverse the " + item.inlinedLocation + " access of '" + targetReversed.n() + "' schema";
        throw new Error("[rescript-schema] " + message);
      }
      return maybeReversedItem.schema;
    case 0 :
    case 2 :
      return item.schema["~r"]();
  }
}

function definitionToOutput(b, definition, getItemOutput) {
  if (typeof definition !== "object" || definition === null) {
    return {
      b: b,
      v: _var,
      i: embed(b, definition),
      a: false
    };
  }
  let item = definition[itemSymbol];
  if (item !== undefined) {
    return getItemOutput(item);
  }
  let isArray = Array.isArray(definition);
  let keys = Object.keys(definition);
  let objectVal = make(b, isArray);
  for (let idx = 0, idx_finish = keys.length; idx < idx_finish; ++idx) {
    let key = keys[idx];
    add(objectVal, isArray ? "\"" + key + "\"" : fromString(key), definitionToOutput(b, definition[key], getItemOutput));
  }
  return complete(objectVal, isArray);
}

function objectStrictModeCheck(b, input, items, unknownKeys, path) {
  if (!(unknownKeys === "Strict" && b.g.o & 1)) {
    return;
  }
  let key = allocateVal(b);
  let keyVar = key.i;
  b.c = b.c + ("for(" + keyVar + " in " + input.i + "){if(");
  if (items.length !== 0) {
    for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
      let match = items[idx];
      if (idx !== 0) {
        b.c = b.c + "&&";
      }
      b.c = b.c + (keyVar + "!==" + match.inlinedLocation);
    }
  } else {
    b.c = b.c + "true";
  }
  b.c = b.c + ("){" + failWithArg(b, path, exccessFieldName => ({
    TAG: "ExcessField",
    _0: exccessFieldName
  }), keyVar) + "}}");
}

function proxify(item) {
  return new Proxy(immutableEmpty, {
    get: (param, prop) => {
      if (prop === itemSymbol) {
        return item;
      }
      let inlinedLocation = fromString(prop);
      return proxify({
        k: 1,
        inlinedLocation: inlinedLocation,
        location: prop,
        of: item,
        p: "[" + inlinedLocation + "]"
      });
    }
  });
}

function definitionToRitem(definition, path, ritems, ritemsByItemPath) {
  if (typeof definition !== "object" || definition === null) {
    return {
      k: 1,
      p: path,
      s: literal(definition)
    };
  }
  let item = definition[itemSymbol];
  if (item !== undefined) {
    let ritem_2 = getItemReversed(item);
    let ritem = {
      k: 0,
      p: path,
      i: item,
      s: ritem_2
    };
    item.r = ritem;
    ritemsByItemPath[getFullDitemPath(item)] = ritem;
    return ritem;
  }
  if (Array.isArray(definition)) {
    let items = [];
    for (let idx = 0, idx_finish = definition.length; idx < idx_finish; ++idx) {
      let location = idx.toString();
      let inlinedLocation = "\"" + location + "\"";
      let ritem$1 = definitionToRitem(definition[idx], path + ("[" + inlinedLocation + "]"), ritems, ritemsByItemPath);
      ritems.push(ritem$1);
      let item_schema = ritem$1.s;
      let item$1 = {
        schema: item_schema,
        location: location,
        inlinedLocation: inlinedLocation
      };
      items[idx] = item$1;
    }
    return {
      k: 2,
      p: path,
      s: makeReverseSchema(name$3, {
        TAG: "tuple",
        items: items
      }, empty, builder, typeFilter$2),
      a: true
    };
  }
  let fieldNames = Object.keys(definition);
  let fields = {};
  let items$1 = [];
  for (let idx$1 = 0, idx_finish$1 = fieldNames.length; idx$1 < idx_finish$1; ++idx$1) {
    let location$1 = fieldNames[idx$1];
    let inlinedLocation$1 = fromString(location$1);
    let ritem$2 = definitionToRitem(definition[location$1], path + ("[" + inlinedLocation$1 + "]"), ritems, ritemsByItemPath);
    ritems.push(ritem$2);
    let item_schema$1 = ritem$2.s;
    let item$2 = {
      schema: item_schema$1,
      location: location$1,
      inlinedLocation: inlinedLocation$1
    };
    items$1[idx$1] = item$2;
    fields[location$1] = item$2;
  }
  return {
    k: 2,
    p: path,
    s: makeReverseSchema(name$2, {
      TAG: "object",
      items: items$1,
      fields: fields,
      unknownKeys: globalConfig.u,
      advanced: true
    }, empty, builder, typeFilter$1),
    a: false
  };
}

function builder$1(parentB, input, selfSchema, path) {
  let tagged = selfSchema.t;
  let unknownKeys = tagged.unknownKeys;
  let items = tagged.items;
  let isArray = tagged.TAG === "tuple";
  if (parentB.g.o & 64) {
    let objectVal = make(parentB, isArray);
    for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
      let match = items[idx];
      let inlinedLocation = match.inlinedLocation;
      add(objectVal, inlinedLocation, input[inlinedLocation]);
    }
    return complete(objectVal, isArray);
  }
  let b = {
    c: "",
    l: "",
    a: initialAllocate,
    g: parentB.g
  };
  let objectVal$1 = make(b, isArray);
  for (let idx$1 = 0, idx_finish$1 = items.length; idx$1 < idx_finish$1; ++idx$1) {
    let match$1 = items[idx$1];
    let inlinedLocation$1 = match$1.inlinedLocation;
    let schema = match$1.schema;
    let itemPath = "[" + inlinedLocation$1 + "]";
    let itemInput = get(b, input, inlinedLocation$1);
    let path$1 = path + itemPath;
    if (schema.f !== undefined && (
        b.g.o & 1 ? schema.t.TAG !== "literal" : schema.t.TAG === "literal" && (itemInput.v !== _var || itemInput.i[0] !== "e")
      )) {
      b.c = b.c + typeFilterCode(b, schema, itemInput, path$1);
    }
    add(objectVal$1, inlinedLocation$1, schema.b(b, itemInput, schema, path$1));
  }
  objectStrictModeCheck(b, input, items, unknownKeys, path);
  parentB.c = parentB.c + allocateScope(b);
  if ((unknownKeys !== "Strip" || b.g.o & 32) && selfSchema === selfSchema["~r"]()) {
    objectVal$1.v = input.v;
    objectVal$1.i = input.i;
    objectVal$1.a = input.a;
    return objectVal$1;
  } else {
    return complete(objectVal$1, isArray);
  }
}

function nested(fieldName) {
  let parentCtx = this;
  let cacheId = "~" + fieldName;
  let ctx = parentCtx[cacheId];
  if (ctx !== undefined) {
    return valFromOption(ctx);
  }
  let fields = {};
  let items = [];
  let schema = makeSchema(name$2, {
    TAG: "object",
    items: items,
    fields: fields,
    unknownKeys: globalConfig.u,
    advanced: false
  }, empty, builder$1, typeFilter$1, reverse$1);
  let target = parentCtx.f(fieldName, schema)[itemSymbol];
  let field = (fieldName, schema) => {
    let inlinedLocation = fromString(fieldName);
    if (fields[fieldName]) {
      throw new Error("[rescript-schema] " + ("The field " + inlinedLocation + " defined twice"));
    }
    let ditem_2 = schema;
    let ditem_4 = "[" + inlinedLocation + "]";
    let ditem = {
      k: 1,
      inlinedLocation: inlinedLocation,
      location: fieldName,
      schema: ditem_2,
      of: target,
      p: ditem_4
    };
    fields[fieldName] = ditem;
    items.push(ditem);
    return proxify(ditem);
  };
  let tag = (tag$1, asValue) => {
    field(tag$1, literal(asValue));
  };
  let fieldOr = (fieldName, schema, or) => {
    let schema$1 = factory(schema);
    return field(fieldName, getWithDefault(schema$1, {
      TAG: "Value",
      _0: or
    }));
  };
  let flatten = schema => {
    let match = schema.t;
    if (typeof match === "object" && match.TAG === "object") {
      let flattenedItems = match.items;
      if (match.advanced) {
        let message = "Unsupported nested flatten for advanced object schema '" + schema.n() + "'";
        throw new Error("[rescript-schema] " + message);
      }
      let match$1 = schema["~r"]().t;
      let exit = 0;
      if (typeof match$1 !== "object") {
        exit = 2;
      } else {
        if (match$1.TAG === "object" && !match$1.advanced) {
          let result = {};
          for (let idx = 0, idx_finish = flattenedItems.length; idx < idx_finish; ++idx) {
            let item = flattenedItems[idx];
            result[item.location] = field(item.location, item.schema);
          }
          return result;
        }
        exit = 2;
      }
      if (exit === 2) {
        let message$1 = "Unsupported nested flatten for transformed schema '" + schema.n() + "'";
        throw new Error("[rescript-schema] " + message$1);
      }
      
    }
    let message$2 = "The '" + schema.n() + "' schema can't be flattened";
    throw new Error("[rescript-schema] " + message$2);
  };
  let ctx$1 = {
    field: field,
    f: field,
    fieldOr: fieldOr,
    tag: tag,
    nested: nested,
    flatten: flatten
  };
  parentCtx[cacheId] = ctx$1;
  return ctx$1;
}

function reverse$1() {
  let items = this.t.items;
  let reversedFields = {};
  let reversedItems = [];
  let isTransformed = false;
  for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
    let match = items[idx];
    let location = match.location;
    let schema = match.schema;
    let reversed = schema["~r"]();
    let item_inlinedLocation = match.inlinedLocation;
    let item = {
      schema: reversed,
      location: location,
      inlinedLocation: item_inlinedLocation
    };
    reversedFields[location] = item;
    reversedItems.push(item);
    if (schema !== reversed) {
      isTransformed = true;
    }
    
  }
  if (isTransformed) {
    return makeReverseSchema(name$2, {
      TAG: "object",
      items: reversedItems,
      fields: reversedFields,
      unknownKeys: globalConfig.u,
      advanced: false
    }, empty, builder$1, typeFilter$1);
  } else {
    return this;
  }
}

function advancedReverse(definition, to, flattened) {
  return function () {
    let originalSchema = this;
    let ritemsByItemPath = {};
    let ritems = [];
    let ritem = definitionToRitem(definition, "", ritems, ritemsByItemPath);
    let reversed;
    switch (ritem.k) {
      case 0 :
        let reversed$1 = ritem.s;
        reversed = makeReverseSchema(reversed$1.n, reversed$1.t, reversed$1.m, reversed$1.b, reversed$1.f);
        break;
      case 1 :
      case 2 :
        reversed = ritem.s;
        break;
    }
    reversed.b = (b, input, selfSchema, path) => {
      let hasTypeValidation = b.g.o & 1;
      for (let idx = 0, idx_finish = ritems.length; idx < idx_finish; ++idx) {
        let match = ritems[idx];
        switch (match.k) {
          case 0 :
            break;
          case 1 :
            if (!hasTypeValidation) {
              let rpath = match.p;
              let itemInput = {
                b: b,
                v: _notVar,
                i: input.v(b) + rpath,
                a: false
              };
              let path$1 = path + rpath;
              b.c = b.c + typeFilterCode(b, match.s, itemInput, path$1);
            }
            break;
          case 2 :
            if (hasTypeValidation) {
              invalidOperation(b, path, "Type validation mode is not supported");
            }
            break;
        }
      }
      let getRitemInput = ritem => {
        if (ritem.p === "") {
          return input;
        } else {
          return {
            b: b,
            v: _notVar,
            i: input.v(b) + ritem.p,
            a: false
          };
        }
      };
      let reversedToInput = (reversed, originalPath) => {
        let literal = reversed.t;
        let exit = 0;
        if (typeof literal !== "object") {
          exit = 2;
        } else {
          switch (literal.TAG) {
            case "literal" :
              return {
                b: b,
                v: _var,
                i: embed(b, literal._0.value),
                a: false
              };
            case "object" :
            case "tuple" :
              exit = 1;
              break;
            default:
              exit = 2;
          }
        }
        switch (exit) {
          case 1 :
            let items = literal.items;
            let isArray = literal.TAG === "tuple";
            let objectVal = make(b, isArray);
            for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
              let item = items[idx];
              let itemPath = originalPath + ("[" + item.inlinedLocation + "]");
              let ritem = ritemsByItemPath[itemPath];
              let itemInput = ritem !== undefined ? getRitemInput(ritem) : reversedToInput(item.schema, itemPath);
              add(objectVal, item.inlinedLocation, itemInput);
            }
            return complete(objectVal, isArray);
          case 2 :
            let tmp = originalPath === "" ? "Schema isn't registered" : "Schema for " + originalPath + " isn't registered";
            return invalidOperation(b, path, tmp);
        }
      };
      let getItemOutput = (item, itemPath) => {
        let ritem = item.r;
        if (ritem !== undefined) {
          let reversed = ritem.s;
          let itemInput = getRitemInput(ritem);
          let path$2 = path + ritem.p;
          if (ritem.p !== "" && reversed.f !== undefined && (
              hasTypeValidation ? reversed.t.TAG !== "literal" : reversed.t.TAG === "literal"
            )) {
            b.c = b.c + typeFilterCode(b, reversed, itemInput, path$2);
          }
          return reversed.b(b, itemInput, reversed, path$2);
        }
        let reversed$1 = item.schema["~r"]();
        let input = reversedToInput(reversed$1, itemPath);
        let prevFlag = b.g.o;
        b.g.o = (prevFlag | 1) ^ 1;
        let output = reversed$1.b(b, input, reversed$1, path);
        b.g.o = prevFlag;
        return output;
      };
      if (to !== undefined) {
        return getItemOutput(to, "");
      }
      if (selfSchema.t.unknownKeys === "Strict") {
        objectStrictModeCheck(b, input, selfSchema.t.items, "Strict", path);
      }
      let isArray = originalSchema.t.TAG === "tuple";
      let items = originalSchema.t.items;
      let objectVal = make(b, isArray);
      if (flattened !== undefined) {
        for (let idx$1 = 0, idx_finish$1 = flattened.length; idx$1 < idx_finish$1; ++idx$1) {
          merge(objectVal, getItemOutput(flattened[idx$1], ""));
        }
      }
      for (let idx$2 = 0, idx_finish$2 = items.length; idx$2 < idx_finish$2; ++idx$2) {
        let item = items[idx$2];
        if (!objectVal[item.inlinedLocation]) {
          add(objectVal, item.inlinedLocation, getItemOutput(item, "[" + item.inlinedLocation + "]"));
        }
        
      }
      return complete(objectVal, isArray);
    };
    return reversed;
  };
}

function advancedBuilder(definition, flattened) {
  return (parentB, input, selfSchema, path) => {
    let isFlatten = parentB.g.o & 64;
    let outputs = isFlatten ? input : ({});
    let b = {
      c: "",
      l: "",
      a: initialAllocate,
      g: parentB.g
    };
    if (!isFlatten) {
      let tagged = selfSchema.t;
      let unknownKeys = tagged.unknownKeys;
      let items = tagged.items;
      let inputVar = input.v(b);
      for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
        let match = items[idx];
        let inlinedLocation = match.inlinedLocation;
        let schema = match.schema;
        let itemPath = "[" + inlinedLocation + "]";
        let itemInput = {
          b: b,
          v: _notVar,
          i: inputVar + itemPath,
          a: false
        };
        let path$1 = path + itemPath;
        if (schema.f !== undefined && (
            b.g.o & 1 ? schema.t.TAG !== "literal" : schema.t.TAG === "literal"
          )) {
          b.c = b.c + typeFilterCode(b, schema, itemInput, path$1);
        }
        outputs[inlinedLocation] = schema.b(b, itemInput, schema, path$1);
      }
      objectStrictModeCheck(b, input, items, unknownKeys, path);
    }
    if (flattened !== undefined) {
      let prevFlag = b.g.o;
      b.g.o = prevFlag | 64;
      for (let idx$1 = 0, idx_finish$1 = flattened.length; idx$1 < idx_finish$1; ++idx$1) {
        let item = flattened[idx$1];
        let schema$1 = item.schema;
        outputs[item.i] = schema$1.b(b, outputs, schema$1, path);
      }
      b.g.o = prevFlag;
    }
    let getItemOutput = item => {
      switch (item.k) {
        case 0 :
          return outputs[item.inlinedLocation];
        case 1 :
          return get(b, getItemOutput(item.of), item.inlinedLocation);
        case 2 :
          return outputs[item.i];
      }
    };
    let output = definitionToOutput(b, definition, getItemOutput);
    parentB.c = parentB.c + allocateScope(b);
    return output;
  };
}

function shape(schema, definer) {
  let item = {
    k: 2,
    schema: schema,
    p: "",
    i: 0
  };
  let definition = definer(proxify(item));
  return makeSchema(schema.n, schema.t, schema.m, (b, input, param, path) => {
    let itemOutput = schema.b(b, input, schema, path);
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let getItemOutput = item => {
      switch (item.k) {
        case 1 :
          return get(bb, getItemOutput(item.of), item.inlinedLocation);
        case 0 :
        case 2 :
          return itemOutput;
      }
    };
    let output = definitionToOutput(bb, definition, getItemOutput);
    b.c = b.c + allocateScope(bb);
    return output;
  }, schema.f, advancedReverse(definition, item, undefined));
}

function object(definer) {
  let flattened = (void 0);
  let items = [];
  let fields = {};
  let flatten = schema => {
    let match = schema.t;
    if (typeof match === "object" && match.TAG === "object") {
      let flattenedItems = match.items;
      for (let idx = 0, idx_finish = flattenedItems.length; idx < idx_finish; ++idx) {
        let match$1 = flattenedItems[idx];
        let inlinedLocation = match$1.inlinedLocation;
        let location = match$1.location;
        let flattenedSchema = match$1.schema;
        let item = fields[location];
        if (item !== undefined) {
          if (item.schema !== flattenedSchema) {
            throw new Error("[rescript-schema] " + ("The field " + inlinedLocation + " defined twice with incompatible schemas"));
          }
          
        } else {
          let item$1 = {
            k: 0,
            schema: flattenedSchema,
            inlinedLocation: inlinedLocation,
            location: location
          };
          items.push(item$1);
          fields[location] = item$1;
        }
      }
      let f = (flattened || (flattened = []));
      let item_2 = f.length;
      let item$2 = {
        k: 2,
        schema: schema,
        p: "",
        i: item_2
      };
      f.push(item$2);
      return proxify(item$2);
    }
    let message = "The '" + schema.n() + "' schema can't be flattened";
    throw new Error("[rescript-schema] " + message);
  };
  let field = (fieldName, schema) => {
    let inlinedLocation = fromString(fieldName);
    if (fields[fieldName]) {
      throw new Error("[rescript-schema] " + ("The field " + inlinedLocation + " defined twice with incompatible schemas"));
    }
    let ditem = {
      k: 0,
      schema: schema,
      inlinedLocation: inlinedLocation,
      location: fieldName
    };
    fields[fieldName] = ditem;
    items.push(ditem);
    return proxify(ditem);
  };
  let tag = (tag$1, asValue) => {
    field(tag$1, literal(asValue));
  };
  let fieldOr = (fieldName, schema, or) => {
    let schema$1 = factory(schema);
    return field(fieldName, getWithDefault(schema$1, {
      TAG: "Value",
      _0: or
    }));
  };
  let ctx = {
    field: field,
    f: field,
    fieldOr: fieldOr,
    tag: tag,
    nested: nested,
    flatten: flatten
  };
  let definition = definer(ctx);
  return {
    t: {
      TAG: "object",
      items: items,
      fields: fields,
      unknownKeys: globalConfig.u,
      advanced: true
    },
    n: name$2,
    "~r": advancedReverse(definition, undefined, flattened),
    b: advancedBuilder(definition, flattened),
    f: typeFilter$1,
    i: 0,
    m: empty
  };
}

function tuple(definer) {
  let items = [];
  let item = (idx, schema) => {
    let location = idx.toString();
    let inlinedLocation = "\"" + location + "\"";
    if (items[idx]) {
      throw new Error("[rescript-schema] " + ("The item [" + inlinedLocation + "] is defined multiple times"));
    }
    let ditem = {
      k: 0,
      schema: schema,
      inlinedLocation: inlinedLocation,
      location: location
    };
    items[idx] = ditem;
    return proxify(ditem);
  };
  let tag = (idx, asValue) => {
    item(idx, literal(asValue));
  };
  let ctx = {
    item: item,
    tag: tag
  };
  let definition = definer(ctx);
  for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
    if (!items[idx]) {
      let location = idx.toString();
      let inlinedLocation = "\"" + location + "\"";
      let ditem = {
        schema: unit,
        location: location,
        inlinedLocation: inlinedLocation
      };
      items[idx] = ditem;
    }
    
  }
  return makeSchema(name$3, {
    TAG: "tuple",
    items: items
  }, empty, advancedBuilder(definition, undefined), typeFilter$2, advancedReverse(definition, undefined, undefined));
}

function definitionToSchema(definition) {
  if (typeof definition !== "object" || definition === null) {
    return literal(definition);
  }
  if (definition["~r"]) {
    return definition;
  }
  if (Array.isArray(definition)) {
    let reversedItems = [];
    let isTransformed = false;
    for (let idx = 0, idx_finish = definition.length; idx < idx_finish; ++idx) {
      let schema = definitionToSchema(definition[idx]);
      let reversed = schema["~r"]();
      let location = idx.toString();
      let inlinedLocation = "\"" + location + "\"";
      definition[idx] = {
        schema: schema,
        location: location,
        inlinedLocation: inlinedLocation
      };
      reversedItems[idx] = {
        schema: reversed,
        location: location,
        inlinedLocation: inlinedLocation
      };
      if (schema !== reversed) {
        isTransformed = true;
      }
      
    }
    let maybeTypeFilter = typeFilter$2;
    return makeSchema(name$3, {
      TAG: "tuple",
      items: definition
    }, empty, builder$1, maybeTypeFilter, isTransformed ? () => makeReverseSchema(name$3, {
        TAG: "tuple",
        items: reversedItems
      }, empty, builder$1, maybeTypeFilter) : toSelf);
  }
  let fieldNames = Object.keys(definition);
  let length = fieldNames.length;
  let items = [];
  for (let idx$1 = 0; idx$1 < length; ++idx$1) {
    let location$1 = fieldNames[idx$1];
    let inlinedLocation$1 = fromString(location$1);
    let schema$1 = definitionToSchema(definition[location$1]);
    let item = {
      schema: schema$1,
      location: location$1,
      inlinedLocation: inlinedLocation$1
    };
    definition[location$1] = item;
    items[idx$1] = item;
  }
  return makeSchema(name$2, {
    TAG: "object",
    items: items,
    fields: definition,
    unknownKeys: globalConfig.u,
    advanced: false
  }, empty, builder$1, typeFilter$1, reverse$1);
}

function matches(schema) {
  return schema;
}

let ctx = {
  m: matches
};

function factory$6(definer) {
  return definitionToSchema(definer(ctx));
}

function typeFilter$9(b, inputVar) {
  let items = this.t.items;
  let length = items.length;
  let code = typeFilter(b, inputVar) + ("||" + inputVar + ".length!==" + length);
  for (let idx = 0; idx < length; ++idx) {
    let match = items[idx];
    code = code + "||" + match.schema.f(b, inputVar + ("[" + match.inlinedLocation + "]"));
  }
  return code;
}

function unnest(schema) {
  let match = schema.t;
  if (typeof match !== "object") {
    throw new Error("[rescript-schema] S.unnest supports only object schemas.");
  }
  if (match.TAG === "object") {
    let items = match.items;
    if (items.length === 0) {
      throw new Error("[rescript-schema] Invalid empty object for S.unnest schema.");
    }
    return makeSchema(name$3, {
      TAG: "tuple",
      items: items.map((item, idx) => {
        let location = idx.toString();
        return {
          schema: factory$2(item.schema),
          location: location,
          inlinedLocation: "\"" + location + "\""
        };
      })
    }, empty, (b, input, param, path) => {
      let inputVar = input.v(b);
      let iteratorVar = varWithoutAllocation(b.g);
      let bb = {
        c: "",
        l: "",
        a: initialAllocate,
        g: b.g
      };
      let itemInput = make(bb, false);
      let lengthCode = "";
      for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
        let item = items[idx];
        add(itemInput, item.inlinedLocation, {
          b: bb,
          v: _notVar,
          i: inputVar + "[" + idx + "][" + iteratorVar + "]",
          a: false
        });
        lengthCode = lengthCode + (inputVar + "[" + idx + "].length,");
      }
      let output = {
        b: b,
        v: _notVar,
        i: "new Array(Math.max(" + lengthCode + "))",
        a: false
      };
      let outputVar = output.v(b);
      let itemOutput = withPathPrepend(bb, complete(itemInput, false), path, iteratorVar, (bb, itemOutput) => {
        bb.c = bb.c + addKey(bb, output, iteratorVar, itemOutput) + ";";
      }, (b, input, path) => schema.b(b, input, schema, path));
      let itemCode = allocateScope(bb);
      b.c = b.c + ("for(let " + iteratorVar + "=0;" + iteratorVar + "<" + outputVar + ".length;++" + iteratorVar + "){" + itemCode + "}");
      if (itemOutput.a) {
        return {
          b: output.b,
          v: _notVar,
          i: "Promise.all(" + output.i + ")",
          a: true
        };
      } else {
        return output;
      }
    }, typeFilter$9, () => {
      let schema$1 = schema["~r"]();
      return makeReverseSchema(name$1, {
        TAG: "array",
        _0: schema$1
      }, empty, (b, input, param, path) => {
        let inputVar = input.v(b);
        let iteratorVar = varWithoutAllocation(b.g);
        let outputVar = varWithoutAllocation(b.g);
        let bb = {
          c: "",
          l: "",
          a: initialAllocate,
          g: b.g
        };
        let itemInput = {
          b: bb,
          v: _notVar,
          i: inputVar + "[" + iteratorVar + "]",
          a: false
        };
        let itemOutput = withPathPrepend(bb, itemInput, path, iteratorVar, (bb, output) => {
          let initialArraysCode = "";
          let settingCode = "";
          for (let idx = 0, idx_finish = items.length; idx < idx_finish; ++idx) {
            let item = items[idx];
            initialArraysCode = initialArraysCode + ("new Array(" + inputVar + ".length),");
            settingCode = settingCode + (outputVar + "[" + idx + "][" + iteratorVar + "]=" + get(b, output, item.inlinedLocation).i + ";");
          }
          b.a(outputVar + "=[" + initialArraysCode + "]");
          bb.c = bb.c + settingCode;
        }, (b, input, path) => parseWithTypeValidation(b, schema$1, input, path));
        let itemCode = allocateScope(bb);
        b.c = b.c + ("for(let " + iteratorVar + "=0;" + iteratorVar + "<" + inputVar + ".length;++" + iteratorVar + "){" + itemCode + "}");
        if (itemOutput.a) {
          return {
            b: b,
            v: _notVar,
            i: "Promise.all(" + outputVar + ")",
            a: true
          };
        } else {
          return {
            b: b,
            v: _var,
            i: outputVar,
            a: false
          };
        }
      }, typeFilter);
    });
  }
  throw new Error("[rescript-schema] S.unnest supports only object schemas.");
}

let $$class = RescriptSchemaError;

function make$2(prim0, prim1, prim2) {
  return new RescriptSchemaError(prim0, prim1, prim2);
}

function raise$1(error) {
  throw error;
}

function reason(error, nestedLevelOpt) {
  let nestedLevel = nestedLevelOpt !== undefined ? nestedLevelOpt : 0;
  let reason$1 = error.code;
  if (typeof reason$1 !== "object") {
    return "Encountered unexpected async transform or refine. Use ParseAsync operation instead";
  }
  switch (reason$1.TAG) {
    case "OperationFailed" :
      return reason$1._0;
    case "InvalidOperation" :
      return reason$1.description;
    case "InvalidType" :
      return "Expected " + reason$1.expected.n() + ", received " + parseInternal(reason$1.received).s;
    case "ExcessField" :
      return "Encountered disallowed excess key " + fromString(reason$1._0) + " on an object";
    case "InvalidUnion" :
      let lineBreak = "\n" + " ".repeat((nestedLevel << 1));
      let reasonsDict = {};
      reason$1._0.forEach(error => {
        let reason$2 = reason(error, nestedLevel + 1);
        let nonEmptyPath = error.path;
        let location = nonEmptyPath === "" ? "" : "Failed at " + nonEmptyPath + ". ";
        reasonsDict["- " + location + reason$2] = undefined;
      });
      let uniqueReasons = Object.keys(reasonsDict);
      return "Invalid union with following errors" + lineBreak + uniqueReasons.join(lineBreak);
    case "InvalidJsonSchema" :
      return "The '" + reason$1._0.n() + "' schema cannot be converted to JSON";
  }
}

function reason$1(error) {
  return reason(error, undefined);
}

function message(error) {
  let op = error.flag;
  let text = "Failed ";
  if (op & 2) {
    text = text + "async ";
  }
  text = text + (
    op & 1 ? (
        op & 4 ? "asserting" : "parsing"
      ) : "converting"
  );
  if (op & 8) {
    text = text + " to JSON" + (
      op & 16 ? " string" : ""
    );
  }
  let nonEmptyPath = error.path;
  let pathText = nonEmptyPath === "" ? "root" : nonEmptyPath;
  return text + " at " + pathText + ". Reason: " + reason(error, undefined);
}

function internalInline(schema, maybeVariant, param) {
  let metadataMap = Object.assign({}, schema.m);
  let literal = schema.t;
  let inlinedSchema;
  if (typeof literal !== "object") {
    switch (literal) {
      case "never" :
        inlinedSchema = "S.never";
        break;
      case "unknown" :
        inlinedSchema = "S.unknown";
        break;
      case "string" :
        inlinedSchema = "S.string";
        break;
      case "int32" :
        inlinedSchema = "S.int";
        break;
      case "number" :
        inlinedSchema = "S.float";
        break;
      case "bigint" :
        inlinedSchema = "S.bigint";
        break;
      case "boolean" :
        inlinedSchema = "S.bool";
        break;
    }
  } else {
    switch (literal.TAG) {
      case "literal" :
        inlinedSchema = "S.literal(%raw(\`" + literal._0.s + "\`))";
        break;
      case "option" :
        inlinedSchema = "S.option(" + internalInline(literal._0, undefined) + ")";
        break;
      case "null" :
        inlinedSchema = "S.null(" + internalInline(literal._0, undefined) + ")";
        break;
      case "array" :
        inlinedSchema = "S.array(" + internalInline(literal._0, undefined) + ")";
        break;
      case "object" :
        let items = literal.items;
        inlinedSchema = items.length !== 0 ? "S.object(s =>\n  {\n    " + items.map(item => item.inlinedLocation + ": s.field(" + item.inlinedLocation + ", " + internalInline(item.schema, undefined) + ")").join(",\n    ") + ",\n  }\n)" : "S.object(_ => ())";
        break;
      case "tuple" :
        let items$1 = literal.items;
        let exit = 0;
        let len = items$1.length;
        if (len >= 4) {
          exit = 1;
        } else {
          switch (len) {
            case 0 :
              exit = 1;
              break;
            case 1 :
              let s0 = items$1[0];
              inlinedSchema = "S.tuple1(" + internalInline(s0.schema, undefined) + ")";
              break;
            case 2 :
              let s0$1 = items$1[0];
              let s1 = items$1[1];
              inlinedSchema = "S.tuple2(" + internalInline(s0$1.schema, undefined) + ", " + internalInline(s1.schema, undefined) + ")";
              break;
            case 3 :
              let s0$2 = items$1[0];
              let s1$1 = items$1[1];
              let s2 = items$1[2];
              inlinedSchema = "S.tuple3(" + internalInline(s0$2.schema, undefined) + ", " + internalInline(s1$1.schema, undefined) + ", " + internalInline(s2.schema, undefined) + ")";
              break;
          }
        }
        if (exit === 1) {
          inlinedSchema = "S.tuple(s => (" + items$1.map((schema, idx) => "s.item(" + idx + ", " + internalInline(schema.schema, undefined) + ")").join(", ") + "))";
        }
        break;
      case "union" :
        let variantNamesCounter = {};
        inlinedSchema = "S.union([" + literal._0.map(s => {
          let variantName = s.n();
          let n = get$2(variantNamesCounter, variantName);
          let numberOfVariantNames = n !== undefined ? n : 0;
          variantNamesCounter[variantName] = numberOfVariantNames + 1;
          let variantName$1 = numberOfVariantNames !== 0 ? variantName + (numberOfVariantNames + 1) : variantName;
          let inlinedVariant = "#" + fromString(variantName$1);
          return internalInline(s, inlinedVariant);
        }).join(", ") + "])";
        break;
      case "dict" :
        inlinedSchema = "S.dict(" + internalInline(literal._0, undefined) + ")";
        break;
      case "JSON" :
        inlinedSchema = "S.json(~validate=" + literal.validated + ")";
        break;
    }
  }
  let $$default = schema.m[defaultMetadataId];
  let inlinedSchema$1;
  if ($$default !== undefined) {
    unsafeDeleteKey(metadataMap, defaultMetadataId);
    if ($$default.TAG === "Value") {
      let defaultValue = $$default._0;
      inlinedSchema$1 = inlinedSchema + ("->S.Option.getOr(%raw(\`" + (
        defaultValue === (void 0) ? "undefined" : JSON.stringify(defaultValue)
      ) + "\`))");
    } else {
      let any = $$default._0();
      inlinedSchema$1 = inlinedSchema + ("->S.Option.getOrWith(() => %raw(\`" + (
        any === (void 0) ? "undefined" : JSON.stringify(any)
      ) + "\`))");
    }
  } else {
    inlinedSchema$1 = inlinedSchema;
  }
  let message = deprecation(schema);
  let inlinedSchema$2 = message !== undefined ? (unsafeDeleteKey(metadataMap, deprecationMetadataId), inlinedSchema$1 + ("->S.deprecate(" + fromString(message) + ")")) : inlinedSchema$1;
  let message$1 = description(schema);
  let inlinedSchema$3 = message$1 !== undefined ? (unsafeDeleteKey(metadataMap, descriptionMetadataId), inlinedSchema$2 + ("->S.describe(" + (
      message$1 === (void 0) ? "undefined" : JSON.stringify(message$1)
    ) + ")")) : inlinedSchema$2;
  let match = schema.t;
  let inlinedSchema$4;
  inlinedSchema$4 = typeof match !== "object" || match.TAG !== "object" || match.unknownKeys === "Strip" ? inlinedSchema$3 : inlinedSchema$3 + "->S.strict";
  let match$1 = schema.t;
  let inlinedSchema$5;
  let exit$1 = 0;
  if (typeof match$1 !== "object") {
    switch (match$1) {
      case "string" :
        exit$1 = 1;
        break;
      case "int32" :
        let refinements$4 = refinements$2(schema);
        if (refinements$4.length !== 0) {
          unsafeDeleteKey(metadataMap, metadataId$2);
          inlinedSchema$5 = inlinedSchema$4 + refinements$4.map(refinement => {
            let match = refinement.kind;
            if (typeof match !== "object") {
              return "->S.port(~message=" + fromString(refinement.message) + ")";
            } else if (match.TAG === "Min") {
              return "->S.intMin(" + match.value + ", ~message=" + fromString(refinement.message) + ")";
            } else {
              return "->S.intMax(" + match.value + ", ~message=" + fromString(refinement.message) + ")";
            }
          }).join("");
        } else {
          inlinedSchema$5 = inlinedSchema$4;
        }
        break;
      case "number" :
        let refinements$5 = refinements$3(schema);
        if (refinements$5.length !== 0) {
          unsafeDeleteKey(metadataMap, metadataId$3);
          inlinedSchema$5 = inlinedSchema$4 + refinements$5.map(refinement => {
            let match = refinement.kind;
            if (match.TAG === "Min") {
              let value = match.value;
              return "->S.floatMin(" + (value.toString() + (
                value % 1 === 0 ? "." : ""
              )) + ", ~message=" + fromString(refinement.message) + ")";
            }
            let value$1 = match.value;
            return "->S.floatMax(" + (value$1.toString() + (
              value$1 % 1 === 0 ? "." : ""
            )) + ", ~message=" + fromString(refinement.message) + ")";
          }).join("");
        } else {
          inlinedSchema$5 = inlinedSchema$4;
        }
        break;
      default:
        inlinedSchema$5 = inlinedSchema$4;
    }
  } else {
    switch (match$1.TAG) {
      case "literal" :
        if (match$1._0.kind === "String") {
          exit$1 = 1;
        } else {
          inlinedSchema$5 = inlinedSchema$4;
        }
        break;
      case "array" :
        let refinements$6 = refinements(schema);
        if (refinements$6.length !== 0) {
          unsafeDeleteKey(metadataMap, metadataId);
          inlinedSchema$5 = inlinedSchema$4 + refinements$6.map(refinement => {
            let match = refinement.kind;
            switch (match.TAG) {
              case "Min" :
                return "->S.arrayMinLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
              case "Max" :
                return "->S.arrayMaxLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
              case "Length" :
                return "->S.arrayLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
            }
          }).join("");
        } else {
          inlinedSchema$5 = inlinedSchema$4;
        }
        break;
      default:
        inlinedSchema$5 = inlinedSchema$4;
    }
  }
  if (exit$1 === 1) {
    let refinements$7 = refinements$1(schema);
    if (refinements$7.length !== 0) {
      unsafeDeleteKey(metadataMap, metadataId$1);
      inlinedSchema$5 = inlinedSchema$4 + refinements$7.map(refinement => {
        let match = refinement.kind;
        if (typeof match !== "object") {
          switch (match) {
            case "Email" :
              return "->S.email(~message=" + fromString(refinement.message) + ")";
            case "Uuid" :
              return "->S.uuid(~message=" + fromString(refinement.message) + ")";
            case "Cuid" :
              return "->S.cuid(~message=" + fromString(refinement.message) + ")";
            case "Url" :
              return "->S.url(~message=" + fromString(refinement.message) + ")";
            case "Datetime" :
              return "->S.datetime(~message=" + fromString(refinement.message) + ")";
          }
        } else {
          switch (match.TAG) {
            case "Min" :
              return "->S.stringMinLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
            case "Max" :
              return "->S.stringMaxLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
            case "Length" :
              return "->S.stringLength(" + match.length + ", ~message=" + fromString(refinement.message) + ")";
            case "Pattern" :
              return "->S.pattern(%re(" + fromString(match.re.toString()) + "), ~message=" + fromString(refinement.message) + ")";
          }
        }
      }).join("");
    } else {
      inlinedSchema$5 = inlinedSchema$4;
    }
  }
  let inlinedSchema$6 = Object.keys(metadataMap).length !== 0 ? "{\n  let s = " + inlinedSchema$5 + "\n  let _ = %raw(\`s.m = " + JSON.stringify(metadataMap) + "\`)\n  s\n}" : inlinedSchema$5;
  if (maybeVariant !== undefined) {
    return inlinedSchema$6 + ("->S.shape(v => " + maybeVariant + "(v))");
  } else {
    return inlinedSchema$6;
  }
}

function inline(schema) {
  return internalInline(schema, undefined);
}

function tuple1(v0) {
  return tuple(s => s.item(0, v0));
}

function tuple2(v0, v1) {
  return definitionToSchema([
    v0,
    v1
  ]);
}

function tuple3(v0, v1, v2) {
  return definitionToSchema([
    v0,
    v1,
    v2
  ]);
}

function intMin(schema, minValue, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Number must be greater than or equal to " + minValue;
  return addRefinement(schema, metadataId$2, {
    kind: {
      TAG: "Min",
      value: minValue
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + "<" + embed(b, minValue) + "){" + fail(b, message, path) + "}");
}

function intMax(schema, maxValue, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Number must be lower than or equal to " + maxValue;
  return addRefinement(schema, metadataId$2, {
    kind: {
      TAG: "Max",
      value: maxValue
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ">" + embed(b, maxValue) + "){" + fail(b, message, path) + "}");
}

function port(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid port";
  return addRefinement(schema, metadataId$2, {
    kind: "Port",
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + "<1||" + inputVar + ">65535){" + fail(b, message, path) + "}");
}

function floatMin(schema, minValue, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Number must be greater than or equal to " + minValue;
  return addRefinement(schema, metadataId$3, {
    kind: {
      TAG: "Min",
      value: minValue
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + "<" + embed(b, minValue) + "){" + fail(b, message, path) + "}");
}

function floatMax(schema, maxValue, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Number must be lower than or equal to " + maxValue;
  return addRefinement(schema, metadataId$3, {
    kind: {
      TAG: "Max",
      value: maxValue
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ">" + embed(b, maxValue) + "){" + fail(b, message, path) + "}");
}

function arrayMinLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Array must be " + length + " or more items long";
  return addRefinement(schema, metadataId, {
    kind: {
      TAG: "Min",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length<" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function arrayMaxLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Array must be " + length + " or fewer items long";
  return addRefinement(schema, metadataId, {
    kind: {
      TAG: "Max",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length>" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function arrayLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "Array must be exactly " + length + " items long";
  return addRefinement(schema, metadataId, {
    kind: {
      TAG: "Length",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length!==" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function stringMinLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "String must be " + length + " or more characters long";
  return addRefinement(schema, metadataId$1, {
    kind: {
      TAG: "Min",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length<" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function stringMaxLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "String must be " + length + " or fewer characters long";
  return addRefinement(schema, metadataId$1, {
    kind: {
      TAG: "Max",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length>" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function stringLength(schema, length, maybeMessage) {
  let message = maybeMessage !== undefined ? maybeMessage : "String must be exactly " + length + " characters long";
  return addRefinement(schema, metadataId$1, {
    kind: {
      TAG: "Length",
      length: length
    },
    message: message
  }, (b, inputVar, param, path) => "if(" + inputVar + ".length!==" + embed(b, length) + "){" + fail(b, message, path) + "}");
}

function email(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid email address";
  return addRefinement(schema, metadataId$1, {
    kind: "Email",
    message: message
  }, (b, inputVar, param, path) => "if(!" + embed(b, emailRegex) + ".test(" + inputVar + ")){" + fail(b, message, path) + "}");
}

function uuid(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid UUID";
  return addRefinement(schema, metadataId$1, {
    kind: "Uuid",
    message: message
  }, (b, inputVar, param, path) => "if(!" + embed(b, uuidRegex) + ".test(" + inputVar + ")){" + fail(b, message, path) + "}");
}

function cuid(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid CUID";
  return addRefinement(schema, metadataId$1, {
    kind: "Cuid",
    message: message
  }, (b, inputVar, param, path) => "if(!" + embed(b, cuidRegex) + ".test(" + inputVar + ")){" + fail(b, message, path) + "}");
}

function url(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid url";
  return addRefinement(schema, metadataId$1, {
    kind: "Url",
    message: message
  }, (b, inputVar, param, path) => "try{new URL(" + inputVar + ")}catch(_){" + fail(b, message, path) + "}");
}

function pattern(schema, re, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid";
  return addRefinement(schema, metadataId$1, {
    kind: {
      TAG: "Pattern",
      re: re
    },
    message: message
  }, (b, inputVar, param, path) => {
    let reVal = {
      b: b,
      v: _var,
      i: embed(b, re),
      a: false
    };
    return reVal.i + ".lastIndex=0;if(!" + reVal.i + ".test(" + inputVar + ")){" + fail(b, message, path) + "}";
  });
}

function datetime(schema, messageOpt) {
  let message = messageOpt !== undefined ? messageOpt : "Invalid datetime string! Must be UTC";
  let refinement = {
    kind: "Datetime",
    message: message
  };
  let refinements = schema.m[metadataId$1];
  return transform$1(set$2(schema, metadataId$1, refinements !== undefined ? refinements.concat(refinement) : [refinement]), s => ({
    p: string => {
      if (!datetimeRe.test(string)) {
        s.fail(message, undefined);
      }
      return new Date(string);
    },
    s: date => date.toISOString()
  }));
}

function trim(schema) {
  let transformer = string => string.trim();
  return transform$1(schema, param => ({
    p: transformer,
    s: transformer
  }));
}

function coerce(from, to) {
  if (from === to) {
    return from;
  }
  let extendCoercion = 0;
  let literalCoercion = 1;
  let match = from["~r"]().t;
  let match$1 = to.t;
  let coercion;
  let exit = 0;
  let literal;
  if (typeof match !== "object") {
    switch (match) {
      case "string" :
        let exit$1 = 0;
        if (typeof match$1 !== "object") {
          switch (match$1) {
            case "string" :
              coercion = extendCoercion;
              break;
            case "int32" :
            case "number" :
              exit$1 = 4;
              break;
            case "bigint" :
              coercion = (b, inputVar, failCoercion) => {
                let output = allocateVal(b);
                b.c = b.c + ("try{" + output.i + "=BigInt(" + inputVar + ")}catch(_){" + failCoercion + "}");
                return output;
              };
              break;
            case "boolean" :
              coercion = (b, inputVar, failCoercion) => {
                let output = allocateVal(b);
                b.c = b.c + ("(" + output.i + "=" + inputVar + "===\"true\")||" + inputVar + "===\"false\"||" + failCoercion + ";");
                return output;
              };
              break;
            default:
              exit = 1;
          }
        } else if (match$1.TAG === "literal") {
          let literal$1 = match$1._0;
          switch (literal$1.kind) {
            case "String" :
              coercion = literalCoercion;
              break;
            case "Symbol" :
            case "Array" :
            case "Dict" :
            case "Function" :
            case "Object" :
              exit = 1;
              break;
            default:
              coercion = (b, inputVar, failCoercion) => {
                b.c = b.c + (inputVar + "===\"" + literal$1.value + "\"||" + failCoercion + ";");
                return {
                  b: b,
                  v: _notVar,
                  i: literal$1.s,
                  a: false
                };
              };
          }
        } else {
          exit = 1;
        }
        if (exit$1 === 4) {
          coercion = (b, inputVar, failCoercion) => {
            let output = {
              b: b,
              v: _notVar,
              i: "+" + inputVar,
              a: false
            };
            b.c = b.c + ("Number.isNaN(" + output.v(b) + ")" + (
              match$1 === "int32" ? "||" + refinement(inputVar) : ""
            ) + "&&" + failCoercion + ";");
            return output;
          };
        }
        break;
      case "int32" :
        if (typeof match$1 !== "object") {
          switch (match$1) {
            case "string" :
              exit = 2;
              break;
            case "number" :
              coercion = extendCoercion;
              break;
            default:
              exit = 1;
          }
        } else {
          exit = 1;
        }
        break;
      case "number" :
        exit = typeof match$1 !== "object" && match$1 === "string" ? 2 : 1;
        break;
      case "bigint" :
        exit = typeof match$1 !== "object" && match$1 === "string" ? 2 : 1;
        break;
      case "boolean" :
        exit = typeof match$1 !== "object" && match$1 === "string" ? 2 : 1;
        break;
      default:
        exit = 1;
    }
  } else if (match.TAG === "literal") {
    let literal$2 = match._0;
    switch (literal$2.kind) {
      case "String" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          coercion = literalCoercion;
        } else {
          exit = 1;
        }
        break;
      case "Number" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      case "Boolean" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      case "BigInt" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      case "Null" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      case "Undefined" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      case "NaN" :
        if (typeof match$1 !== "object" && match$1 === "string") {
          literal = literal$2;
          exit = 3;
        } else {
          exit = 1;
        }
        break;
      default:
        exit = 1;
    }
  } else {
    exit = 1;
  }
  switch (exit) {
    case 1 :
      let message = "S.coerce from " + from["~r"]().n() + " to " + to.n() + " is not supported";
      throw new Error("[rescript-schema] " + message);
    case 2 :
      coercion = (b, inputVar, param) => ({
        b: b,
        v: _notVar,
        i: "\"\"+" + inputVar,
        a: false
      });
      break;
    case 3 :
      coercion = (b, param, param$1) => ({
        b: b,
        v: _notVar,
        i: "\"" + literal.value + "\"",
        a: false
      });
      break;
  }
  return makeSchema(from.n, from.t, to.m, (b, input, param, path) => {
    let input$1 = from.b(b, input, from, path);
    if (coercion === extendCoercion) {
      return to.b(b, input$1, to, path);
    }
    if (coercion === literalCoercion) {
      return parseWithTypeValidation(b, to, input$1, path);
    }
    let bb = {
      c: "",
      l: "",
      a: initialAllocate,
      g: b.g
    };
    let inputVar = input$1.v(bb);
    let input$2 = coercion(bb, inputVar, failWithArg(bb, path, input => ({
      TAG: "InvalidType",
      expected: to,
      received: input
    }), inputVar));
    let output = to.b(bb, input$2, to, path);
    b.c = b.c + allocateScope(bb);
    return output;
  }, from.f, () => coerce(to["~r"](), from["~r"]()));
}

function js_union(values) {
  return factory$5(values.map(definitionToSchema));
}

function js_transform(schema, maybeParser, maybeSerializer) {
  return transform$1(schema, s => ({
    p: maybeParser !== undefined ? v => maybeParser(v, s) : undefined,
    s: maybeSerializer !== undefined ? v => maybeSerializer(v, s) : undefined
  }));
}

function js_refine(schema, refiner) {
  return refine(schema, s => (v => refiner(v, s)));
}

function noop$1(a) {
  return a;
}

function js_asyncParserRefine(schema, refine) {
  return transform$1(schema, s => ({
    a: v => refine(v, s).then(() => v),
    s: noop$1
  }));
}

function js_optional(schema, maybeOr) {
  let schema$1 = factory(schema);
  if (maybeOr === undefined) {
    return schema$1;
  }
  let or = valFromOption(maybeOr);
  if (typeof or === "function") {
    return getWithDefault(schema$1, {
      TAG: "Callback",
      _0: or
    });
  } else {
    return getWithDefault(schema$1, {
      TAG: "Value",
      _0: or
    });
  }
}

function js_custom(name, maybeParser, maybeSerializer, param) {
  return custom(name, s => ({
    p: maybeParser !== undefined ? v => maybeParser(v, s) : undefined,
    s: maybeSerializer !== undefined ? v => maybeSerializer(v, s) : undefined
  }));
}

function js_merge(s1, s2) {
  let match = s1.t;
  if (typeof match === "object" && match.TAG === "object") {
    let match$1 = s2.t;
    if (typeof match$1 === "object" && match$1.TAG === "object") {
      let items2 = match$1.items;
      let items = [].concat(match.items);
      let fields = Object.assign({}, match.fields);
      for (let idx = 0, idx_finish = items2.length; idx < idx_finish; ++idx) {
        let item = items2[idx];
        if (fields[item.location]) {
          throw new Error("[rescript-schema] " + ("The field " + item.inlinedLocation + " is defined multiple times"));
        }
        items.push(item);
        fields[item.location] = item;
      }
      return makeSchema(() => s1.n() + " & " + s2.n(), {
        TAG: "object",
        items: items,
        fields: fields,
        unknownKeys: match$1.unknownKeys,
        advanced: true
      }, empty, (b, input, param, path) => {
        let s1Result = s1.b(b, input, s1, path);
        let s2Result = s2.b(b, input, s2, path);
        return {
          b: b,
          v: _notVar,
          i: "{..." + s1Result.i + ", ..." + s2Result.i + "}",
          a: false
        };
      }, typeFilter$1, () => makeReverseSchema(primitiveName, "unknown", empty, (b, param, param$1, path) => invalidOperation(b, path, "The S.merge serializing is not supported yet"), undefined));
    }
    
  }
  throw new Error("[rescript-schema] The merge supports only Object schemas");
}

function js_name(prim) {
  return prim.n();
}

function standard(schema) {
  let parseOrThrow = compile$1(schema, "Any", "Output", "Sync", true);
  return {
    "~standard": {
      version: 1,
      vendor: "rescript-schema",
      validate: input => {
        try {
          return {
            value: parseOrThrow(input)
          };
        } catch (exn) {
          let error = getOrRethrow(exn);
          return {
            issues: [{
                message: message(error),
                path: error.path === "" ? undefined : toArray(error.path)
              }]
          };
        }
      }
    }
  };
}

let resetOperationsCache = ((schema) => {
  for (let key in schema) {
    if (+key) {
      delete schema[key];
    }
  }
});

function setGlobalConfig(override) {
  globalConfig.r = 0;
  let unknownKeys = override.defaultUnknownKeys;
  globalConfig.u = unknownKeys !== undefined ? unknownKeys : "Strip";
  let prevDisableNanNumberCheck = globalConfig.n;
  let disableNanNumberValidation = override.disableNanNumberValidation;
  globalConfig.n = disableNanNumberValidation !== undefined ? disableNanNumberValidation : false;
  if (prevDisableNanNumberCheck !== globalConfig.n) {
    return resetOperationsCache(schema$5);
  }
  
}

let Path = {
  empty: "",
  dynamic: "[]",
  toArray: toArray,
  fromArray: fromArray,
  fromLocation: fromLocation,
  concat: concat
};

let Flag = {
  none: 0,
  typeValidation: 1,
  async: 2,
  assertOutput: 4,
  jsonableOutput: 8,
  jsonStringOutput: 16,
  reverse: 32,
  has: has
};

let $$Error$1 = {
  $$class: $$class,
  make: make$2,
  raise: raise$1,
  message: message,
  reason: reason$1
};

let Literal = {
  parse: parse,
  value: value,
  isJsonable: isJsonable,
  toString: toString
};

let never = schema;

let unknown = schema$1;

let string = schema$2;

let bool = schema$3;

let int = schema$4;

let float = schema$5;

let bigint = schema$6;

let array = factory$2;

let dict = factory$3;

let option = factory;

let $$null$1 = factory$1;

let jsonString = factory$4;

let union = factory$5;

let to = shape;

let parseJsonOrThrow = parseOrThrow;

let Schema = {};

let schema$7 = factory$6;

let $$Object = {};

let Tuple = {};

let Option = {
  $$default: $$default,
  getOr: getOr,
  getOrWith: getOrWith
};

let String_Refinement = {};

let $$String = {
  Refinement: String_Refinement,
  refinements: refinements$1
};

let Int_Refinement = {};

let Int = {
  Refinement: Int_Refinement,
  refinements: refinements$2
};

let Float_Refinement = {};

let Float = {
  Refinement: Float_Refinement,
  refinements: refinements$3
};

let Array_Refinement = {};

let $$Array = {
  Refinement: Array_Refinement,
  refinements: refinements
};

let Metadata = {
  Id: Id,
  get: get$1,
  set: set$2
};

let js_schema = definitionToSchema;
/* symbol Not a pure module */

export { $$Array, $$Error$1 as $$Error, $$Object, $$String, $$catch, $$enum, $$null$1 as $$null, Catch, Flag, Float, Int, Literal, Metadata, Option, Path, Raised, Schema, Tuple, array, arrayLength, arrayMaxLength, arrayMinLength, assertOrThrow, bigint, bool, coerce, compile$1 as compile, convertAsyncOrThrow, convertOrThrow, convertToJsonOrThrow, convertToJsonStringOrThrow, cuid, custom, datetime, deepStrict, deepStrip, deprecate, deprecation, describe, description, dict, email, float, floatMax, floatMin, inline, int, intMax, intMin, isAsync, js_asyncParserRefine, js_custom, js_merge, js_name, js_optional, js_refine, js_safe, js_safeAsync, js_schema, js_transform, js_union, json, jsonString, list, literal, never, nullable, object, option, parseAsyncOrThrow, parseJsonOrThrow, parseJsonStringOrThrow, parseOrThrow, pattern, port, preprocess, recursive, refine, removeTypeValidation, reverse, reverseConvertOrThrow, reverseConvertToJsonOrThrow, reverseConvertToJsonStringOrThrow, schema$7 as schema, setGlobalConfig, setName, shape, standard, strict, string, stringLength, stringMaxLength, stringMinLength, strip, to, transform$1 as transform, trim, tuple, tuple1, tuple2, tuple3, union, unit, unknown, unnest, url, uuid };