fromJson

tcmts.cli.data_pages.fromJson · #xmpi6aon · term · runs anywhere

JSON (as toJson writes it) as a value of schema s: strings where it has dates become dates, pairs where it has a map a map, arrays where it has a set a set, digits where it has a bigint a bigint; a union's first member it then fits. What doesn't fit is left as it is, for the check to say so.

import { checkValue } from "#codebase/tcmts/core/schema";
import type { Schema } from "#codebase/tcmts/core/schema";

export function fromJson(s: Schema, v: unknown, defs: Schema[]): unknown {
  switch (s.t) {
    case "ref":
      return defs[s.id] ? fromJson(defs[s.id]!, v, defs) : v;
    case "date":
      return typeof v === "string" && !Number.isNaN(Date.parse(v)) ? new Date(v) : v;
    case "bigint":
      return typeof v === "string" && /^-?\d+$/.test(v)
        ? BigInt(v)
        : typeof v === "number"
          ? BigInt(Math.trunc(v))
          : v;
    case "array":
      return Array.isArray(v) ? v.map((x) => fromJson(s.of, x, defs)) : v;
    case "set":
      return Array.isArray(v) ? new Set(v.map((x) => fromJson(s.of, x, defs))) : v;
    case "map":
      return Array.isArray(v)
        ? new Map(
            v.map((p) =>
              Array.isArray(p) ? [fromJson(s.key, p[0], defs), fromJson(s.value, p[1], defs)] : p,
            ),
          )
        : v && typeof v === "object"
          ? new Map(
              Object.entries(v).map(([k, x]) => [
                fromJson(s.key, k, defs),
                fromJson(s.value, x, defs),
              ]),
            )
          : v;
    case "tuple":
      return Array.isArray(v)
        ? v.map((x, i) =>
            s.of[i] ? fromJson(s.of[i]!, x, defs) : s.rest ? fromJson(s.rest, x, defs) : x,
          )
        : v;
    case "object":
      if (!v || typeof v !== "object" || Array.isArray(v)) return v;
      return Object.fromEntries(
        Object.entries(v).map(([k, x]) => {
          const p = s.props[k];
          return [k, p ? fromJson(p.s, x, defs) : s.index ? fromJson(s.index, x, defs) : x];
        }),
      );
    case "union": {
      for (const m of s.of) {
        const c = fromJson(m, v, defs);
        if (checkValue(m, c, "row", defs) === undefined) return c;
      }
      return v;
    }
    default:
      return v;
  }
}

uses

used by