UNPKG

@jsonquerylang/jsonquery

Version:

A small, flexible, and expandable JSON query language

435 lines (434 loc) 12.8 kB
const w = (t) => Array.isArray(t), et = (t) => t !== null && typeof t == "object" && !w(t), nt = (t) => typeof t == "string", E = (t, e) => t === e ? !0 : t !== null && e !== null && typeof t == "object" && typeof e == "object" && Object.keys(t).length === Object.keys(e).length && Object.entries(t).every(([r, s]) => E(s, e[r])), Z = (t, e) => { const n = t == null ? void 0 : t[e]; if (n !== void 0) { if (!Object.hasOwn(t, e) || Array.isArray(t) && !/^\d+$/.test(e) || typeof t != "object") throw new TypeError(`Unsupported property "${e}"`); return n; } }; function g(t) { return (...e) => { const n = e.map((o) => h(o)), r = n[0], s = n[1]; return n.length === 1 ? (o) => t(r(o)) : n.length === 2 ? (o) => t(r(o), s(o)) : (o) => t(...n.map((m) => m(o))); }; } const F = { boolean: 0, number: 1, string: 2 }, D = 3, H = (t, e) => typeof t == typeof e && typeof t in F ? t > e : !1, rt = (t, e) => E(t, e) || H(t, e), X = (t, e) => typeof t == typeof e && typeof t in F ? t < e : !1, st = (t, e) => E(t, e) || X(t, e), M = { pipe: (...t) => { const e = t.map((n) => h(n)); return (n) => e.reduce((r, s) => s(r), n); }, object: (t) => { const e = Object.keys(t).map((n) => [n, h(t[n])]); return (n) => { const r = {}; for (const [s, o] of e) r[s] = o(n); return r; }; }, array: (...t) => { const e = t.map((n) => h(n)); return (n) => e.map((r) => r(n)); }, get: (...t) => { if (t.length === 0) return (e) => e ?? null; if (t.length === 1) { const e = t[0]; return (n) => Z(n, e) ?? null; } return (e) => { let n = e; for (const r of t) n = Z(n, r); return n ?? null; }; }, map: (t) => { const e = h(t); return (n) => n.map(e); }, mapObject: (t) => { const e = h(t); return (n) => { const r = {}; for (const s of Object.keys(n)) { const o = e({ key: s, value: n[s] }); r[o.key] = o.value; } return r; }; }, mapKeys: (t) => { const e = h(t); return (n) => { const r = {}; for (const s of Object.keys(n)) { const o = e(s); r[o] = n[s]; } return r; }; }, mapValues: (t) => { const e = h(t); return (n) => { const r = {}; for (const s of Object.keys(n)) r[s] = e(n[s]); return r; }; }, filter: (t) => { const e = h(t); return (n) => n.filter((r) => C(e(r))); }, sort: (t = ["get"], e) => { const n = h(t), r = e === "desc" ? -1 : 1; function s(o, m) { const u = n(o), j = n(m); if (typeof u != typeof j) { const I = F[typeof u] ?? D, N = F[typeof j] ?? D; return I > N ? r : I < N ? -r : 0; } return typeof u in F ? u > j ? r : u < j ? -r : 0 : 0; } return (o) => o.slice().sort(s); }, reverse: () => (t) => t.toReversed(), pick: (...t) => { const e = t.map( ([r, ...s]) => [s[s.length - 1], M.get(...s)] ), n = (r, s) => { const o = {}; for (const [m, u] of s) o[m] = u(r); return o; }; return (r) => w(r) ? r.map((s) => n(s, e)) : n(r, e); }, groupBy: (t) => { const e = h(t); return (n) => { const r = {}; for (const s of n) { const o = e(s); r[o] ? r[o].push(s) : r[o] = [s]; } return r; }; }, keyBy: (t) => { const e = h(t); return (n) => { const r = {}; for (const s of n) { const o = e(s); o in r || (r[o] = s); } return r; }; }, flatten: () => (t) => t.flat(), join: (t = "") => (e) => e.join(t), split: g( (t, e) => e !== void 0 ? t.split(e) : t.trim().split(/\s+/) ), substring: g( (t, e, n) => t.slice(Math.max(e, 0), n) ), uniq: () => (t) => { const e = []; for (const n of t) e.findIndex((r) => E(r, n)) === -1 && e.push(n); return e; }, uniqBy: (t) => (e) => Object.values(M.keyBy(t)(e)), limit: (t) => (e) => e.slice(0, Math.max(t, 0)), size: () => (t) => t.length, keys: () => Object.keys, values: () => Object.values, prod: () => (t) => T(t, (e, n) => e * n), sum: () => (t) => w(t) ? t.reduce((e, n) => e + n, 0) : U(), average: () => (t) => w(t) ? t.length > 0 ? t.reduce((e, n) => e + n) / t.length : null : U(), min: () => (t) => T(t, (e, n) => Math.min(e, n)), max: () => (t) => T(t, (e, n) => Math.max(e, n)), and: g((...t) => T(t, (e, n) => !!(e && n))), or: g((...t) => T(t, (e, n) => !!(e || n))), not: g((t) => !t), exists: (t) => { const e = t.slice(1), n = e.pop(), r = M.get(...e); return (s) => { const o = r(s); return !!o && Object.hasOwnProperty.call(o, n); }; }, if: (t, e, n) => { const r = h(t), s = h(e), o = h(n); return (m) => C(r(m)) ? s(m) : o(m); }, in: (t, e) => { const n = h(t), r = h(e); return (s) => { const o = n(s); return r(s).findIndex((u) => E(u, o)) !== -1; }; }, "not in": (t, e) => { const n = M.in(t, e); return (r) => !n(r); }, regex: (t, e, n) => { const r = new RegExp(e, n), s = h(t); return (o) => r.test(s(o)); }, match: (t, e, n) => { const r = new RegExp(e, n), s = h(t); return (o) => { const m = s(o).match(r); return m ? G(m) : null; }; }, matchAll: (t, e, n) => { const r = new RegExp(e, `${n ?? ""}g`), s = h(t); return (o) => Array.from(s(o).matchAll(r)).map(G); }, eq: g(E), gt: g(H), gte: g(rt), lt: g(X), lte: g(st), ne: g((t, e) => !E(t, e)), add: g((t, e) => t + e), subtract: g((t, e) => t - e), multiply: g((t, e) => t * e), divide: g((t, e) => t / e), mod: g((t, e) => t % e), pow: g((t, e) => t ** e), abs: g(Math.abs), round: g((t, e = 0) => +`${Math.round(+`${t}e${e}`)}e${-e}`), number: g((t) => { const e = Number(t); return Number.isNaN(Number(t)) ? null : e; }), string: g(String) }, C = (t) => t !== null && t !== 0 && t !== !1, T = (t, e) => (w(t) || U(), t.length === 0 ? null : t.reduce(e)), G = (t) => { const [e, ...n] = t, r = t.groups; return n.length ? r ? { value: e, groups: n, namedGroups: r } : { value: e, groups: n } : { value: e }; }, U = () => { z("Array expected"); }, z = (t) => { throw new TypeError(t); }, L = []; function h(t, e) { L.unshift({ ...M, ...L[0], ...e == null ? void 0 : e.functions }); try { const n = w(t) ? ot(t, L[0]) : et(t) ? z( `Function notation ["object", {...}] expected but got ${JSON.stringify(t)}` ) : () => t; return (r) => { try { return n(r); } catch (s) { throw s.jsonquery = [{ data: r, query: t }, ...s.jsonquery ?? []], s; } }; } finally { L.shift(); } } function ot(t, e) { const [n, ...r] = t, s = e[n]; return s || z(`Unknown function '${n}'`), s(...r); } const Q = [ { pow: "^" }, { multiply: "*", divide: "/", mod: "%" }, { add: "+", subtract: "-" }, { gt: ">", gte: ">=", lt: "<", lte: "<=", in: "in", "not in": "not in" }, { eq: "==", ne: "!=" }, { and: "and" }, { or: "or" }, { pipe: "|" } ], ct = ["|", "and", "or"], Y = ["|", "and", "or", "*", "/", "%", "+", "-"]; function q(t, e) { if (!w(e)) throw new Error("Invalid custom operators"); return e.reduce(it, t); } function it(t, { name: e, op: n, at: r, after: s, before: o }) { if (r) return t.map((j) => Object.values(j).includes(r) ? { ...j, [e]: n } : j); const m = s ?? o, u = t.findIndex((j) => Object.values(j).includes(m)); if (u !== -1) return t.toSpliced(u + (s ? 1 : 0), 0, { [e]: n }); throw new Error("Invalid custom operator"); } const ut = /^[a-zA-Z_$][a-zA-Z\d_$]*$/, at = /^[a-zA-Z_$][a-zA-Z\d_$]*/, lt = /^"(?:[^"\\]|\\.)*"/, ft = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/, pt = /^(0|[1-9][0-9]*)/, gt = /^(true|false|null)/, ht = /^[ \n\t\r]+/; function mt(t, e) { const n = (e == null ? void 0 : e.operators) ?? [], r = q(Q, n), s = Object.assign({}, ...r), o = ct.concat( n.filter((c) => c.vararg).map((c) => c.op) ), m = Y.concat( n.filter((c) => c.leftAssociative).map((c) => c.op) ), u = (c = r.length - 1) => { const p = r[c]; if (!p) return I(); const d = t[i] === "("; let y = u(c - 1); for (; ; ) { if (f(), t[i] === "." && "pipe" in p) { const V = N(); y = y[0] === "pipe" ? [...y, V] : ["pipe", y, V]; continue; } const P = i, R = j(p); if (!R) break; const B = u(c - 1), tt = y[0], K = R === tt && !d; if (K && !m.includes(s[R])) { i = P; break; } y = K && o.includes(s[R]) ? [...y, B] : [R, y, B]; } return y; }, j = (c) => { const p = Object.keys(c).sort((d, y) => y.length - d.length); for (const d of p) { const y = c[d]; if (t.substring(i, i + y.length) === y) return i += y.length, f(), d; } }, I = () => { if (f(), t[i] === "(") { i++; const c = u(); return $(")"), c; } return N(); }, N = () => { if (t[i] === ".") { const c = []; for (; t[i] === "."; ) i++, c.push( a() ?? O() ?? x() ?? _("Property expected") ), f(); return ["get", ...c]; } return J(); }, J = () => { const c = i, p = O(); if (f(), !p || t[i] !== "(") return i = c, S(); i++, f(); const d = t[i] !== ")" ? [u()] : []; for (; i < t.length && t[i] !== ")"; ) f(), $(","), d.push(u()); return $(")"), [p, ...d]; }, S = () => { if (t[i] === "{") { i++, f(); const c = {}; let p = !0; for (; i < t.length && t[i] !== "}"; ) { p ? p = !1 : ($(","), f()); const d = a() ?? O() ?? x() ?? _("Key expected"); f(), $(":"), c[d] = u(); } return $("}"), ["object", c]; } return l(); }, l = () => { if (t[i] === "[") { i++, f(); const c = []; let p = !0; for (; i < t.length && t[i] !== "]"; ) p ? p = !1 : ($(","), f()), c.push(u()); return $("]"), ["array", ...c]; } return a() ?? b() ?? v(); }, a = () => k(lt, JSON.parse), O = () => k(at, (c) => c), b = () => k(ft, JSON.parse), x = () => k(pt, JSON.parse), v = () => { const c = k(gt, JSON.parse); if (c !== void 0) return c; _("Value expected"); }, A = () => { f(), i < t.length && _(`Unexpected part '${t.substring(i)}'`); }, k = (c, p) => { const d = t.substring(i).match(c); if (d) return i += d[0].length, p(d[0]); }, f = () => k(ht, (c) => c), $ = (c) => { t[i] !== c && _(`Character '${c}' expected`), i++; }, _ = (c, p = i) => { throw new SyntaxError(`${c} (pos: ${p})`); }; let i = 0; const W = u(); return A(), W; } const dt = 40, yt = " ", Ot = (t, e) => { const n = (e == null ? void 0 : e.indentation) ?? yt, r = (e == null ? void 0 : e.operators) ?? [], s = q(Q, r), o = Object.assign({}, ...s), m = Y.concat( r.filter((l) => l.leftAssociative).map((l) => l.op) ), u = (l, a, O = !1) => w(l) ? j(l, a, O) : JSON.stringify(l), j = (l, a, O) => { const [b, ...x] = l; if (b === "get" && x.length > 0) return N(x); if (b === "object") return I(x[0], a); if (b === "array") { const f = x.map(($) => u($, a)); return S( f, ["[", ", ", "]"], [`[ ${a + n}`, `, ${a + n}`, ` ${a}]`] ); } const v = o[b]; if (v) { const f = O ? "(" : "", $ = O ? ")" : "", _ = x.map((i, W) => { const c = i == null ? void 0 : i[0], p = s.findIndex((P) => b in P), d = s.findIndex((P) => c in P), y = p < d || p === d && W > 0 || b === c && !m.includes(v); return u(i, a + n, y); }); return S(_, [f, ` ${v} `, $], [f, ` ${a + n}${v} `, $]); } const A = x.length === 1 ? a : a + n, k = x.map((f) => u(f, A)); return S( k, [`${b}(`, ", ", ")"], x.length === 1 ? [`${b}(`, `, ${a}`, ")"] : [`${b}( ${A}`, `, ${A}`, ` ${a})`] ); }, I = (l, a) => { const O = a + n, b = Object.entries(l).map(([x, v]) => `${J(x)}: ${u(v, O)}`); return S( b, ["{ ", ", ", " }"], [`{ ${O}`, `, ${O}`, ` ${a}}`] ); }, N = (l) => l.map((a) => `.${J(a)}`).join(""), J = (l) => ut.test(l) ? l : JSON.stringify(l), S = (l, [a, O, b], [x, v, A]) => a.length + l.reduce((f, $) => f + $.length + O.length, 0) - O.length + b.length <= ((e == null ? void 0 : e.maxLineLength) ?? dt) ? a + l.join(O) + b : x + l.join(v) + A; return u(t, ""); }; function bt(t, e, n) { return h(nt(e) ? mt(e, n) : e, n)(t); } export { g as buildFunction, h as compile, bt as jsonquery, mt as parse, Ot as stringify }; //# sourceMappingURL=jsonquery.js.map