lacspace-json 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.cjs ADDED
@@ -0,0 +1,1980 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib.ts
21
+ var lib_exports = {};
22
+ __export(lib_exports, {
23
+ JsonToolError: () => JsonToolError,
24
+ compareValues: () => compareValues,
25
+ compileQuery: () => compileQuery,
26
+ convert: () => convert,
27
+ deepClone: () => deepClone,
28
+ deepEqual: () => deepEqual,
29
+ detectFormat: () => detectFormat,
30
+ diff: () => diff,
31
+ formatFromExt: () => formatFromExt,
32
+ formatJson: () => formatJson,
33
+ getPath: () => getPath,
34
+ isEqual: () => isEqual,
35
+ isPlainObject: () => isPlainObject,
36
+ isValidQuery: () => isValidQuery,
37
+ merge: () => merge,
38
+ parseArrayStrategy: () => parseArrayStrategy,
39
+ parseCsv: () => parseCsv,
40
+ parseFormat: () => parseFormat,
41
+ parseNdjson: () => parseNdjson,
42
+ parsePath: () => parsePath,
43
+ parseToml: () => parseToml,
44
+ parseYaml: () => parseYaml,
45
+ query: () => query,
46
+ queryAll: () => queryAll,
47
+ sanitizeJson: () => sanitizeJson,
48
+ sortKeysDeep: () => sortKeysDeep,
49
+ stringifyCsv: () => stringifyCsv,
50
+ stringifyFormat: () => stringifyFormat,
51
+ stringifyNdjson: () => stringifyNdjson,
52
+ stringifyToml: () => stringifyToml,
53
+ stringifyYaml: () => stringifyYaml,
54
+ typeOf: () => typeOf,
55
+ validateSchema: () => validateSchema
56
+ });
57
+ module.exports = __toCommonJS(lib_exports);
58
+
59
+ // src/util.ts
60
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
61
+ function isForbiddenKey(key) {
62
+ return FORBIDDEN_KEYS.has(key);
63
+ }
64
+ function safeSet(obj, key, value) {
65
+ if (isForbiddenKey(key)) return;
66
+ Object.defineProperty(obj, key, {
67
+ value,
68
+ writable: true,
69
+ enumerable: true,
70
+ configurable: true
71
+ });
72
+ }
73
+ function isPlainObject(v) {
74
+ return typeof v === "object" && v !== null && !Array.isArray(v);
75
+ }
76
+ function typeOf(v) {
77
+ if (v === null || v === void 0) return "null";
78
+ if (Array.isArray(v)) return "array";
79
+ const t = typeof v;
80
+ if (t === "boolean") return "boolean";
81
+ if (t === "number") return "number";
82
+ if (t === "string") return "string";
83
+ return "object";
84
+ }
85
+ function deepEqual(a, b) {
86
+ if (a === b) return true;
87
+ if (a === null || b === null) return a === b;
88
+ const ta = typeof a;
89
+ const tb = typeof b;
90
+ if (ta !== tb) return false;
91
+ if (Array.isArray(a) || Array.isArray(b)) {
92
+ if (!Array.isArray(a) || !Array.isArray(b)) return false;
93
+ if (a.length !== b.length) return false;
94
+ for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;
95
+ return true;
96
+ }
97
+ if (ta === "object") {
98
+ const oa = a;
99
+ const ob = b;
100
+ const ka = Object.keys(oa);
101
+ const kb = Object.keys(ob);
102
+ if (ka.length !== kb.length) return false;
103
+ for (const k of ka) {
104
+ if (!Object.prototype.hasOwnProperty.call(ob, k)) return false;
105
+ if (!deepEqual(oa[k], ob[k])) return false;
106
+ }
107
+ return true;
108
+ }
109
+ return false;
110
+ }
111
+ function deepClone(v) {
112
+ if (v === null || typeof v !== "object") return v;
113
+ if (Array.isArray(v)) return v.map((x) => deepClone(x));
114
+ const out = {};
115
+ for (const k of Object.keys(v)) {
116
+ safeSet(out, k, deepClone(v[k]));
117
+ }
118
+ return out;
119
+ }
120
+ function compareValues(a, b) {
121
+ const rank = (v) => {
122
+ if (v === null || v === void 0) return 0;
123
+ if (v === false) return 1;
124
+ if (v === true) return 2;
125
+ if (typeof v === "number") return 3;
126
+ if (typeof v === "string") return 4;
127
+ if (Array.isArray(v)) return 5;
128
+ return 6;
129
+ };
130
+ const ra = rank(a);
131
+ const rb = rank(b);
132
+ if (ra !== rb) return ra - rb;
133
+ if (ra === 3) return a - b;
134
+ if (ra === 4) return a < b ? -1 : a > b ? 1 : 0;
135
+ if (ra === 5) {
136
+ const aa = a;
137
+ const bb = b;
138
+ const n = Math.min(aa.length, bb.length);
139
+ for (let i = 0; i < n; i++) {
140
+ const c = compareValues(aa[i], bb[i]);
141
+ if (c !== 0) return c;
142
+ }
143
+ return aa.length - bb.length;
144
+ }
145
+ if (ra === 6) {
146
+ const ka = Object.keys(a).sort();
147
+ const kb = Object.keys(b).sort();
148
+ const n = Math.min(ka.length, kb.length);
149
+ for (let i = 0; i < n; i++) {
150
+ if (ka[i] !== kb[i]) return ka[i] < kb[i] ? -1 : 1;
151
+ }
152
+ if (ka.length !== kb.length) return ka.length - kb.length;
153
+ for (const k of ka) {
154
+ const c = compareValues(a[k], b[k]);
155
+ if (c !== 0) return c;
156
+ }
157
+ return 0;
158
+ }
159
+ return 0;
160
+ }
161
+ function sortKeysDeep(v) {
162
+ if (Array.isArray(v)) return v.map(sortKeysDeep);
163
+ if (isPlainObject(v)) {
164
+ const out = {};
165
+ for (const k of Object.keys(v).sort()) safeSet(out, k, sortKeysDeep(v[k]));
166
+ return out;
167
+ }
168
+ return v;
169
+ }
170
+ var JsonToolError = class extends Error {
171
+ path;
172
+ constructor(message, path) {
173
+ super(message);
174
+ this.name = "JsonToolError";
175
+ if (path !== void 0) this.path = path;
176
+ }
177
+ };
178
+
179
+ // src/query.ts
180
+ function tokenize(src) {
181
+ const toks = [];
182
+ let i = 0;
183
+ const n = src.length;
184
+ while (i < n) {
185
+ const ch = src[i];
186
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
187
+ i++;
188
+ continue;
189
+ }
190
+ if (ch === ".") {
191
+ toks.push({ t: "dot" });
192
+ i++;
193
+ continue;
194
+ }
195
+ if (ch === "[") {
196
+ toks.push({ t: "lbracket" });
197
+ i++;
198
+ continue;
199
+ }
200
+ if (ch === "]") {
201
+ toks.push({ t: "rbracket" });
202
+ i++;
203
+ continue;
204
+ }
205
+ if (ch === "(") {
206
+ toks.push({ t: "lparen" });
207
+ i++;
208
+ continue;
209
+ }
210
+ if (ch === ")") {
211
+ toks.push({ t: "rparen" });
212
+ i++;
213
+ continue;
214
+ }
215
+ if (ch === "|") {
216
+ toks.push({ t: "pipe" });
217
+ i++;
218
+ continue;
219
+ }
220
+ if (ch === ",") {
221
+ toks.push({ t: "comma" });
222
+ i++;
223
+ continue;
224
+ }
225
+ if (ch === '"' || ch === "'") {
226
+ const quote = ch;
227
+ let j = i + 1;
228
+ let s = "";
229
+ while (j < n && src[j] !== quote) {
230
+ if (src[j] === "\\" && j + 1 < n) {
231
+ const esc = src[j + 1];
232
+ s += esc === "n" ? "\n" : esc === "t" ? " " : esc;
233
+ j += 2;
234
+ } else {
235
+ s += src[j];
236
+ j++;
237
+ }
238
+ }
239
+ if (j >= n) throw new JsonToolError(`Unterminated string in query near "${src.slice(i, i + 12)}"`);
240
+ toks.push({ t: "str", v: s });
241
+ i = j + 1;
242
+ continue;
243
+ }
244
+ if (ch === ">" || ch === "<" || ch === "=" || ch === "!") {
245
+ if (src[i + 1] === "=") {
246
+ toks.push({ t: "op", v: ch + "=" });
247
+ i += 2;
248
+ } else if (ch === "=" || ch === "!") throw new JsonToolError(`Use "==" / "!=" for comparison near "${src.slice(i)}"`);
249
+ else {
250
+ toks.push({ t: "op", v: ch });
251
+ i++;
252
+ }
253
+ continue;
254
+ }
255
+ if (/[0-9]/.test(ch) || ch === "-" && /[0-9]/.test(src[i + 1] ?? "")) {
256
+ let j = i + 1;
257
+ while (j < n && /[0-9.eE+-]/.test(src[j])) j++;
258
+ const raw = src.slice(i, j);
259
+ const num = Number(raw);
260
+ if (Number.isNaN(num)) throw new JsonToolError(`Invalid number "${raw}" in query`);
261
+ toks.push({ t: "num", v: num });
262
+ i = j;
263
+ continue;
264
+ }
265
+ if (/[A-Za-z_]/.test(ch)) {
266
+ let j = i + 1;
267
+ while (j < n && /[A-Za-z0-9_]/.test(src[j])) j++;
268
+ toks.push({ t: "ident", v: src.slice(i, j) });
269
+ i = j;
270
+ continue;
271
+ }
272
+ throw new JsonToolError(`Unexpected character "${ch}" in query near "${src.slice(i, i + 12)}"`);
273
+ }
274
+ return toks;
275
+ }
276
+ var FUNCS_NO_ARG = /* @__PURE__ */ new Set([
277
+ "keys",
278
+ "values",
279
+ "length",
280
+ "type",
281
+ "unique",
282
+ "reverse",
283
+ "first",
284
+ "last",
285
+ "min",
286
+ "max",
287
+ "sum",
288
+ "avg",
289
+ "add",
290
+ "flatten"
291
+ ]);
292
+ var FUNCS_WITH_ARG = /* @__PURE__ */ new Set(["map", "sort_by", "group_by", "has", "select"]);
293
+ var Parser = class {
294
+ toks;
295
+ pos = 0;
296
+ constructor(toks) {
297
+ this.toks = toks;
298
+ }
299
+ peek() {
300
+ return this.toks[this.pos];
301
+ }
302
+ next() {
303
+ return this.toks[this.pos++];
304
+ }
305
+ expect(t) {
306
+ const tk = this.next();
307
+ if (!tk || tk.t !== t) throw new JsonToolError(`Query parse error: expected ${t}`);
308
+ return tk;
309
+ }
310
+ parsePipeline(stopAtParen = false) {
311
+ const stages = [];
312
+ stages.push(this.parseStage());
313
+ while (this.peek()?.t === "pipe") {
314
+ this.next();
315
+ stages.push(this.parseStage());
316
+ }
317
+ if (stopAtParen && this.peek() && this.peek().t !== "rparen") {
318
+ throw new JsonToolError("Query parse error: expected ')'");
319
+ }
320
+ return { stages };
321
+ }
322
+ parseStage() {
323
+ const tk = this.peek();
324
+ if (!tk) throw new JsonToolError("Query parse error: unexpected end of expression");
325
+ if (tk.t === "dot" || tk.t === "lbracket") return this.parsePath();
326
+ if (tk.t === "ident") return this.parseFunc();
327
+ throw new JsonToolError(`Query parse error: unexpected token near "${describeTok(tk)}"`);
328
+ }
329
+ parsePath() {
330
+ const steps = [];
331
+ while (true) {
332
+ const tk = this.peek();
333
+ if (tk?.t === "dot") {
334
+ this.next();
335
+ const after = this.peek();
336
+ if (after?.t === "ident") {
337
+ this.next();
338
+ steps.push({ kind: "key", name: after.v });
339
+ continue;
340
+ }
341
+ if (after?.t === "str") {
342
+ this.next();
343
+ steps.push({ kind: "key", name: after.v });
344
+ continue;
345
+ }
346
+ if (after?.t === "lbracket") {
347
+ this.parseBracket(steps);
348
+ continue;
349
+ }
350
+ continue;
351
+ }
352
+ if (tk?.t === "lbracket") {
353
+ this.parseBracket(steps);
354
+ continue;
355
+ }
356
+ break;
357
+ }
358
+ return { kind: "path", steps };
359
+ }
360
+ parseBracket(steps) {
361
+ this.expect("lbracket");
362
+ const inner = this.peek();
363
+ if (inner?.t === "rbracket") {
364
+ this.next();
365
+ steps.push({ kind: "iterate" });
366
+ return;
367
+ }
368
+ if (inner?.t === "num") {
369
+ this.next();
370
+ this.expect("rbracket");
371
+ steps.push({ kind: "index", index: inner.v });
372
+ return;
373
+ }
374
+ if (inner?.t === "str") {
375
+ this.next();
376
+ this.expect("rbracket");
377
+ steps.push({ kind: "key", name: inner.v });
378
+ return;
379
+ }
380
+ if (inner?.t === "op" && inner.v === "<") {
381
+ }
382
+ throw new JsonToolError("Query parse error: expected number, string or empty in [ ]");
383
+ }
384
+ parseFunc() {
385
+ const nameTok = this.expect("ident");
386
+ const name = nameTok.v;
387
+ if (name === "select") {
388
+ this.expect("lparen");
389
+ const cond = this.parseCond();
390
+ this.expect("rparen");
391
+ return { kind: "select", cond };
392
+ }
393
+ if (FUNCS_WITH_ARG.has(name)) {
394
+ this.expect("lparen");
395
+ if (name === "has") {
396
+ const arg = this.next();
397
+ let key;
398
+ if (arg?.t === "str") key = arg.v;
399
+ else if (arg?.t === "num") key = arg.v;
400
+ else if (arg?.t === "ident") key = arg.v;
401
+ else throw new JsonToolError('has() needs a key, e.g. has("id")');
402
+ this.expect("rparen");
403
+ return { kind: "func", name, litKey: key };
404
+ }
405
+ const inner = this.parsePipeline(true);
406
+ this.expect("rparen");
407
+ return { kind: "func", name, arg: inner };
408
+ }
409
+ if (FUNCS_NO_ARG.has(name)) return { kind: "func", name };
410
+ throw new JsonToolError(`Unknown query function "${name}"`);
411
+ }
412
+ // --- conditions (inside select) ---
413
+ parseCond() {
414
+ return this.parseOr();
415
+ }
416
+ parseOr() {
417
+ let left = this.parseAnd();
418
+ while (this.peek()?.t === "ident" && this.peek().v === "or") {
419
+ this.next();
420
+ const right = this.parseAnd();
421
+ left = { kind: "or", l: left, r: right };
422
+ }
423
+ return left;
424
+ }
425
+ parseAnd() {
426
+ let left = this.parseCondAtom();
427
+ while (this.peek()?.t === "ident" && this.peek().v === "and") {
428
+ this.next();
429
+ const right = this.parseCondAtom();
430
+ left = { kind: "and", l: left, r: right };
431
+ }
432
+ return left;
433
+ }
434
+ parseCondAtom() {
435
+ const tk = this.peek();
436
+ if (tk?.t === "ident" && tk.v === "not") {
437
+ this.next();
438
+ return { kind: "not", c: this.parseCondAtom() };
439
+ }
440
+ if (tk?.t === "lparen") {
441
+ this.next();
442
+ const c = this.parseCond();
443
+ this.expect("rparen");
444
+ return c;
445
+ }
446
+ const left = this.parseCondPipeline();
447
+ const opTok = this.peek();
448
+ if (opTok?.t === "op") {
449
+ this.next();
450
+ const right = this.parseLiteral();
451
+ return { kind: "cmp", left, op: opTok.v, right };
452
+ }
453
+ return { kind: "truthy", expr: left };
454
+ }
455
+ parseCondPipeline() {
456
+ const stages = [this.parseStage()];
457
+ while (this.peek()?.t === "pipe") {
458
+ this.next();
459
+ stages.push(this.parseStage());
460
+ }
461
+ return { stages };
462
+ }
463
+ parseLiteral() {
464
+ const tk = this.next();
465
+ if (!tk) throw new JsonToolError("Query parse error: expected a value after operator");
466
+ if (tk.t === "num") return { lit: true, value: tk.v };
467
+ if (tk.t === "str") return { lit: true, value: tk.v };
468
+ if (tk.t === "ident") {
469
+ if (tk.v === "true") return { lit: true, value: true };
470
+ if (tk.v === "false") return { lit: true, value: false };
471
+ if (tk.v === "null") return { lit: true, value: null };
472
+ return { lit: true, value: tk.v };
473
+ }
474
+ throw new JsonToolError("Query parse error: expected a literal (number, string, true/false/null)");
475
+ }
476
+ };
477
+ function describeTok(t) {
478
+ if (t.t === "ident" || t.t === "str") return t.v;
479
+ if (t.t === "num") return String(t.v);
480
+ if (t.t === "op") return t.v;
481
+ return t.t;
482
+ }
483
+ function getKey(v, key) {
484
+ if (v === null || v === void 0) return void 0;
485
+ if (Array.isArray(v)) return void 0;
486
+ if (typeof v !== "object") return void 0;
487
+ if (!Object.prototype.hasOwnProperty.call(v, key)) return void 0;
488
+ return v[key];
489
+ }
490
+ function evalPath(steps, inputs) {
491
+ let cur = inputs;
492
+ for (const step of steps) {
493
+ if (step.kind === "key") {
494
+ cur = cur.map((v) => getKey(v, step.name));
495
+ } else if (step.kind === "index") {
496
+ cur = cur.map((v) => {
497
+ if (!Array.isArray(v)) return void 0;
498
+ const idx = step.index < 0 ? v.length + step.index : step.index;
499
+ return v[idx];
500
+ });
501
+ } else {
502
+ const out = [];
503
+ for (const v of cur) {
504
+ if (Array.isArray(v)) out.push(...v);
505
+ else if (v && typeof v === "object") out.push(...Object.values(v));
506
+ }
507
+ cur = out;
508
+ }
509
+ }
510
+ return cur;
511
+ }
512
+ function asNumbers(arr, fn) {
513
+ const out = [];
514
+ for (const v of arr) {
515
+ if (typeof v !== "number") throw new JsonToolError(`${fn}: expected an array of numbers, found ${typeOf(v)}`);
516
+ out.push(v);
517
+ }
518
+ return out;
519
+ }
520
+ function evalFunc(stage, inputs) {
521
+ const name = stage.name;
522
+ const litKey = stage.litKey;
523
+ const perValue = (fn) => inputs.map(fn);
524
+ switch (name) {
525
+ case "keys":
526
+ return perValue((v) => {
527
+ if (Array.isArray(v)) return v.map((_, i) => i);
528
+ if (v && typeof v === "object") return Object.keys(v).sort();
529
+ throw new JsonToolError(`keys: expected object or array, found ${typeOf(v)}`);
530
+ });
531
+ case "values":
532
+ return perValue((v) => {
533
+ if (Array.isArray(v)) return v;
534
+ if (v && typeof v === "object") return Object.values(v);
535
+ throw new JsonToolError(`values: expected object or array, found ${typeOf(v)}`);
536
+ });
537
+ case "length":
538
+ return perValue((v) => {
539
+ if (v === null || v === void 0) return 0;
540
+ if (typeof v === "string") return v.length;
541
+ if (Array.isArray(v)) return v.length;
542
+ if (typeof v === "number") return Math.abs(v);
543
+ if (typeof v === "object") return Object.keys(v).length;
544
+ throw new JsonToolError(`length: unsupported type ${typeOf(v)}`);
545
+ });
546
+ case "type":
547
+ return perValue((v) => typeOf(v));
548
+ case "has":
549
+ return perValue((v) => {
550
+ if (Array.isArray(v)) return typeof litKey === "number" && litKey >= 0 && litKey < v.length;
551
+ if (v && typeof v === "object") return Object.prototype.hasOwnProperty.call(v, String(litKey));
552
+ throw new JsonToolError(`has: expected object or array, found ${typeOf(v)}`);
553
+ });
554
+ case "unique":
555
+ return perValue((v) => {
556
+ if (!Array.isArray(v)) throw new JsonToolError(`unique: expected array, found ${typeOf(v)}`);
557
+ const sorted = [...v].sort(compareValues);
558
+ const out = [];
559
+ for (const x of sorted) if (out.length === 0 || !deepEqual(out[out.length - 1], x)) out.push(x);
560
+ return out;
561
+ });
562
+ case "reverse":
563
+ return perValue((v) => {
564
+ if (Array.isArray(v)) return [...v].reverse();
565
+ if (typeof v === "string") return [...v].reverse().join("");
566
+ throw new JsonToolError(`reverse: expected array or string, found ${typeOf(v)}`);
567
+ });
568
+ case "flatten":
569
+ return perValue((v) => {
570
+ if (!Array.isArray(v)) throw new JsonToolError(`flatten: expected array, found ${typeOf(v)}`);
571
+ const out = [];
572
+ const walk2 = (a) => {
573
+ for (const x of a) Array.isArray(x) ? walk2(x) : out.push(x);
574
+ };
575
+ walk2(v);
576
+ return out;
577
+ });
578
+ case "first":
579
+ return perValue((v) => {
580
+ if (!Array.isArray(v)) throw new JsonToolError(`first: expected array`);
581
+ return v.length ? v[0] : null;
582
+ });
583
+ case "last":
584
+ return perValue((v) => {
585
+ if (!Array.isArray(v)) throw new JsonToolError(`last: expected array`);
586
+ return v.length ? v[v.length - 1] : null;
587
+ });
588
+ case "min":
589
+ return perValue((v) => {
590
+ if (!Array.isArray(v)) throw new JsonToolError(`min: expected array`);
591
+ if (!v.length) return null;
592
+ return [...v].sort(compareValues)[0];
593
+ });
594
+ case "max":
595
+ return perValue((v) => {
596
+ if (!Array.isArray(v)) throw new JsonToolError(`max: expected array`);
597
+ if (!v.length) return null;
598
+ return [...v].sort(compareValues)[v.length - 1];
599
+ });
600
+ case "sum":
601
+ return perValue((v) => {
602
+ if (!Array.isArray(v)) throw new JsonToolError(`sum: expected array`);
603
+ return asNumbers(v, "sum").reduce((a, b) => a + b, 0);
604
+ });
605
+ case "avg":
606
+ return perValue((v) => {
607
+ if (!Array.isArray(v)) throw new JsonToolError(`avg: expected array`);
608
+ const nums = asNumbers(v, "avg");
609
+ return nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : null;
610
+ });
611
+ case "add":
612
+ return perValue((v) => {
613
+ if (!Array.isArray(v)) throw new JsonToolError(`add: expected array`);
614
+ if (!v.length) return null;
615
+ if (v.every((x) => typeof x === "number")) return v.reduce((a, b) => a + b, 0);
616
+ if (v.every((x) => typeof x === "string")) return v.join("");
617
+ if (v.every((x) => Array.isArray(x))) return [].concat(...v);
618
+ throw new JsonToolError("add: array must be all numbers, all strings, or all arrays");
619
+ });
620
+ case "map": {
621
+ const inner = stage.arg;
622
+ return perValue((v) => {
623
+ if (!Array.isArray(v)) throw new JsonToolError(`map: expected array, found ${typeOf(v)}`);
624
+ return v.map((el) => firstOf(evalPipeline(inner, [el])));
625
+ });
626
+ }
627
+ case "sort_by": {
628
+ const inner = stage.arg;
629
+ return perValue((v) => {
630
+ if (!Array.isArray(v)) throw new JsonToolError(`sort_by: expected array, found ${typeOf(v)}`);
631
+ return [...v].sort((a, b) => compareValues(firstOf(evalPipeline(inner, [a])), firstOf(evalPipeline(inner, [b]))));
632
+ });
633
+ }
634
+ case "group_by": {
635
+ const inner = stage.arg;
636
+ return perValue((v) => {
637
+ if (!Array.isArray(v)) throw new JsonToolError(`group_by: expected array, found ${typeOf(v)}`);
638
+ const withKey = v.map((el) => ({ el, key: firstOf(evalPipeline(inner, [el])) }));
639
+ withKey.sort((a, b) => compareValues(a.key, b.key));
640
+ const groups = [];
641
+ let curKey = /* @__PURE__ */ Symbol();
642
+ for (const { el, key } of withKey) {
643
+ if (groups.length === 0 || !deepEqual(curKey, key)) {
644
+ groups.push([]);
645
+ curKey = key;
646
+ }
647
+ groups[groups.length - 1].push(el);
648
+ }
649
+ return groups;
650
+ });
651
+ }
652
+ default:
653
+ throw new JsonToolError(`Unknown query function "${name}"`);
654
+ }
655
+ }
656
+ function truthy(v) {
657
+ return v !== null && v !== void 0 && v !== false;
658
+ }
659
+ function evalCond(cond, value) {
660
+ switch (cond.kind) {
661
+ case "or":
662
+ return evalCond(cond.l, value) || evalCond(cond.r, value);
663
+ case "and":
664
+ return evalCond(cond.l, value) && evalCond(cond.r, value);
665
+ case "not":
666
+ return !evalCond(cond.c, value);
667
+ case "truthy":
668
+ return truthy(firstOf(evalPipeline(cond.expr, [value])));
669
+ case "cmp": {
670
+ const left = firstOf(evalPipeline(cond.left, [value]));
671
+ const right = cond.right.value;
672
+ switch (cond.op) {
673
+ case "==":
674
+ return deepEqual(left, right);
675
+ case "!=":
676
+ return !deepEqual(left, right);
677
+ case ">":
678
+ return compareValues(left, right) > 0;
679
+ case "<":
680
+ return compareValues(left, right) < 0;
681
+ case ">=":
682
+ return compareValues(left, right) >= 0;
683
+ case "<=":
684
+ return compareValues(left, right) <= 0;
685
+ default:
686
+ throw new JsonToolError(`Unknown operator "${cond.op}"`);
687
+ }
688
+ }
689
+ }
690
+ }
691
+ function evalPipeline(pipe, inputs) {
692
+ let cur = inputs;
693
+ for (const stage of pipe.stages) {
694
+ if (stage.kind === "path") cur = evalPath(stage.steps, cur);
695
+ else if (stage.kind === "select") cur = cur.filter((v) => evalCond(stage.cond, v));
696
+ else cur = evalFunc(stage, cur);
697
+ }
698
+ return cur;
699
+ }
700
+ function firstOf(arr) {
701
+ return arr.length ? arr[0] : null;
702
+ }
703
+ function compileQuery(expr) {
704
+ const toks = tokenize(expr);
705
+ if (toks.length === 0) return (d) => [d];
706
+ const ast = new Parser(toks).parsePipeline();
707
+ return (data) => evalPipeline(ast, [data]);
708
+ }
709
+ function query(data, expr) {
710
+ const results = compileQuery(expr)(data);
711
+ const clean = results.map((v) => v === void 0 ? null : v);
712
+ return clean.length === 1 ? clean[0] : clean;
713
+ }
714
+ function queryAll(data, expr) {
715
+ return compileQuery(expr)(data).map((v) => v === void 0 ? null : v);
716
+ }
717
+ function isValidQuery(expr) {
718
+ try {
719
+ compileQuery(expr);
720
+ return true;
721
+ } catch {
722
+ return false;
723
+ }
724
+ }
725
+
726
+ // src/yaml.ts
727
+ function splitLines(src) {
728
+ const out = [];
729
+ const rawLines = src.split(/\r?\n/);
730
+ for (let i = 0; i < rawLines.length; i++) {
731
+ const raw = rawLines[i];
732
+ if (/^\s*$/.test(raw)) continue;
733
+ if (/^\s*#/.test(raw)) continue;
734
+ const trimmedRight = raw.replace(/\s+$/, "");
735
+ if (trimmedRight === "---" || trimmedRight === "...") continue;
736
+ const indent = raw.length - raw.replace(/^\s+/, "").length;
737
+ out.push({ indent, content: raw.trim(), raw, n: i + 1 });
738
+ }
739
+ return out;
740
+ }
741
+ function stripComment(s) {
742
+ let inS = false, inD = false;
743
+ for (let i = 0; i < s.length; i++) {
744
+ const ch = s[i];
745
+ if (ch === "'" && !inD) inS = !inS;
746
+ else if (ch === '"' && !inS) inD = !inD;
747
+ else if (ch === "#" && !inS && !inD && (i === 0 || s[i - 1] === " " || s[i - 1] === " ")) {
748
+ return s.slice(0, i).replace(/\s+$/, "");
749
+ }
750
+ }
751
+ return s;
752
+ }
753
+ function parseScalar(raw) {
754
+ const s = raw.trim();
755
+ if (s === "" || s === "~" || s === "null" || s === "Null" || s === "NULL") return null;
756
+ if (s === "true" || s === "True" || s === "TRUE") return true;
757
+ if (s === "false" || s === "False" || s === "FALSE") return false;
758
+ if (s.length >= 2 && s[0] === '"' && s[s.length - 1] === '"') {
759
+ return s.slice(1, -1).replace(/\\(["\\/ntr])/g, (_m, c) => c === "n" ? "\n" : c === "t" ? " " : c === "r" ? "\r" : c);
760
+ }
761
+ if (s.length >= 2 && s[0] === "'" && s[s.length - 1] === "'") {
762
+ return s.slice(1, -1).replace(/''/g, "'");
763
+ }
764
+ if (s[0] === "[" || s[0] === "{") return parseFlow(s);
765
+ if (/^[-+]?(0|[1-9][0-9]*)$/.test(s)) return parseInt(s, 10);
766
+ if (/^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$/.test(s) && /\d/.test(s)) {
767
+ const num = Number(s);
768
+ if (!Number.isNaN(num)) return num;
769
+ }
770
+ return s;
771
+ }
772
+ function parseFlow(s) {
773
+ let i = 0;
774
+ const parseValue2 = () => {
775
+ skipWs();
776
+ const ch = s[i];
777
+ if (ch === "[") return parseArr();
778
+ if (ch === "{") return parseObj();
779
+ return parseFlowScalar();
780
+ };
781
+ const skipWs = () => {
782
+ while (i < s.length && /\s/.test(s[i])) i++;
783
+ };
784
+ const parseArr = () => {
785
+ i++;
786
+ const arr = [];
787
+ skipWs();
788
+ if (s[i] === "]") {
789
+ i++;
790
+ return arr;
791
+ }
792
+ while (i < s.length) {
793
+ arr.push(parseValue2());
794
+ skipWs();
795
+ if (s[i] === ",") {
796
+ i++;
797
+ continue;
798
+ }
799
+ if (s[i] === "]") {
800
+ i++;
801
+ break;
802
+ }
803
+ throw new JsonToolError(`YAML: malformed flow sequence near "${s.slice(i)}"`);
804
+ }
805
+ return arr;
806
+ };
807
+ const parseObj = () => {
808
+ i++;
809
+ const obj = {};
810
+ skipWs();
811
+ if (s[i] === "}") {
812
+ i++;
813
+ return obj;
814
+ }
815
+ while (i < s.length) {
816
+ skipWs();
817
+ const key = parseFlowKey();
818
+ skipWs();
819
+ if (s[i] !== ":") throw new JsonToolError(`YAML: expected ':' in flow map near "${s.slice(i)}"`);
820
+ i++;
821
+ const val = parseValue2();
822
+ if (!isForbiddenKey(key)) safeSet(obj, key, val);
823
+ skipWs();
824
+ if (s[i] === ",") {
825
+ i++;
826
+ continue;
827
+ }
828
+ if (s[i] === "}") {
829
+ i++;
830
+ break;
831
+ }
832
+ throw new JsonToolError(`YAML: malformed flow map near "${s.slice(i)}"`);
833
+ }
834
+ return obj;
835
+ };
836
+ const parseFlowKey = () => {
837
+ skipWs();
838
+ if (s[i] === '"' || s[i] === "'") {
839
+ const v = parseFlowScalar();
840
+ return String(v);
841
+ }
842
+ let j = i;
843
+ while (j < s.length && s[j] !== ":" && s[j] !== "," && s[j] !== "}") j++;
844
+ const k = s.slice(i, j).trim();
845
+ i = j;
846
+ return k;
847
+ };
848
+ const parseFlowScalar = () => {
849
+ skipWs();
850
+ if (s[i] === '"' || s[i] === "'") {
851
+ const q = s[i];
852
+ let j2 = i + 1;
853
+ let str = "";
854
+ while (j2 < s.length && s[j2] !== q) {
855
+ if (q === '"' && s[j2] === "\\") {
856
+ str += s[j2 + 1] === "n" ? "\n" : s[j2 + 1];
857
+ j2 += 2;
858
+ } else {
859
+ str += s[j2];
860
+ j2++;
861
+ }
862
+ }
863
+ i = j2 + 1;
864
+ return str;
865
+ }
866
+ let j = i;
867
+ while (j < s.length && !",]}".includes(s[j])) j++;
868
+ const tok = s.slice(i, j).trim();
869
+ i = j;
870
+ return parseScalar(tok);
871
+ };
872
+ const result = parseValue2();
873
+ return result;
874
+ }
875
+ function parseBlock(lines, start, minIndent) {
876
+ const first = lines[start];
877
+ const indent = first.indent;
878
+ if (/^-(\s|$)/.test(first.content)) {
879
+ const arr = [];
880
+ let i2 = start;
881
+ while (i2 < lines.length && lines[i2].indent === indent && /^-(\s|$)/.test(lines[i2].content)) {
882
+ const line = lines[i2];
883
+ const after = line.content.slice(1).trim();
884
+ if (after === "") {
885
+ const inner = parseBlock(lines, i2 + 1, indent + 1);
886
+ arr.push(inner.value);
887
+ i2 = inner.next;
888
+ } else if (/^[^:\s][^:]*:(\s|$)/.test(after) || isInlineMapStart(after)) {
889
+ const synthetic = [{ indent: indent + 2, content: after, raw: line.raw, n: line.n }];
890
+ let j = i2 + 1;
891
+ while (j < lines.length && lines[j].indent > indent) {
892
+ synthetic.push(lines[j]);
893
+ j++;
894
+ }
895
+ const inner = parseBlock(synthetic, 0, indent + 2);
896
+ arr.push(inner.value);
897
+ i2 = j;
898
+ } else {
899
+ arr.push(parseScalar(stripComment(after)));
900
+ i2++;
901
+ }
902
+ }
903
+ return { value: arr, next: i2 };
904
+ }
905
+ const obj = {};
906
+ let i = start;
907
+ while (i < lines.length && lines[i].indent === indent) {
908
+ const line = lines[i];
909
+ if (/^-(\s|$)/.test(line.content)) break;
910
+ const { key, rest } = splitKey(line.content, line.n);
911
+ const restClean = stripComment(rest);
912
+ if (restClean === "") {
913
+ const child = lines[i + 1];
914
+ if (child && child.indent > indent) {
915
+ const inner = parseBlock(lines, i + 1, indent + 1);
916
+ if (!isForbiddenKey(key)) safeSet(obj, key, inner.value);
917
+ i = inner.next;
918
+ } else {
919
+ if (!isForbiddenKey(key)) safeSet(obj, key, null);
920
+ i++;
921
+ }
922
+ } else if (restClean === "|" || restClean === ">" || /^[|>][-+]?$/.test(restClean)) {
923
+ const { text, next } = readBlockScalar(lines, i + 1, indent, restClean);
924
+ if (!isForbiddenKey(key)) safeSet(obj, key, text);
925
+ i = next;
926
+ } else {
927
+ if (!isForbiddenKey(key)) safeSet(obj, key, parseScalar(restClean));
928
+ i++;
929
+ }
930
+ }
931
+ void minIndent;
932
+ return { value: obj, next: i };
933
+ }
934
+ function isInlineMapStart(s) {
935
+ return /^[^:]+:\s/.test(s);
936
+ }
937
+ function splitKey(content, n) {
938
+ let inS = false, inD = false;
939
+ for (let i = 0; i < content.length; i++) {
940
+ const ch = content[i];
941
+ if (ch === "'" && !inD) inS = !inS;
942
+ else if (ch === '"' && !inS) inD = !inD;
943
+ else if (ch === ":" && !inS && !inD && (i + 1 >= content.length || content[i + 1] === " ")) {
944
+ let key = content.slice(0, i).trim();
945
+ if (key.length >= 2 && (key[0] === '"' && key.endsWith('"') || key[0] === "'" && key.endsWith("'"))) {
946
+ key = key.slice(1, -1);
947
+ }
948
+ return { key, rest: content.slice(i + 1).trim() };
949
+ }
950
+ }
951
+ throw new JsonToolError(`YAML: expected "key: value" mapping at line ${n}: "${content}"`);
952
+ }
953
+ function readBlockScalar(lines, start, parentIndent, marker) {
954
+ const folded = marker[0] === ">";
955
+ const chomp = marker.includes("-") ? "strip" : marker.includes("+") ? "keep" : "clip";
956
+ const body = [];
957
+ let i = start;
958
+ let blockIndent = -1;
959
+ while (i < lines.length && lines[i].indent > parentIndent) {
960
+ if (blockIndent < 0) blockIndent = lines[i].indent;
961
+ body.push(lines[i].raw.slice(blockIndent));
962
+ i++;
963
+ }
964
+ let text = folded ? body.join(" ") : body.join("\n");
965
+ if (chomp === "strip") text = text.replace(/\n+$/, "");
966
+ else if (chomp === "clip") text = text.replace(/\n+$/, "") + (body.length ? "\n" : "");
967
+ return { text, next: i };
968
+ }
969
+ function parseYaml(src) {
970
+ const lines = splitLines(src);
971
+ if (lines.length === 0) return null;
972
+ if (lines.length === 1 && !/^-(\s|$)/.test(lines[0].content) && !/:\s|:$/.test(lines[0].content)) {
973
+ return parseScalar(stripComment(lines[0].content));
974
+ }
975
+ const { value } = parseBlock(lines, 0, 0);
976
+ return value;
977
+ }
978
+ function needsQuote(s) {
979
+ if (s === "") return true;
980
+ if (/^(true|false|null|~|yes|no|on|off)$/i.test(s)) return true;
981
+ if (/^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$/.test(s)) return true;
982
+ if (/^[\s]|[\s]$/.test(s)) return true;
983
+ if (/[:#\[\]{}&*!|>'"%@`,]/.test(s)) return true;
984
+ if (/^[?-]/.test(s)) return true;
985
+ return false;
986
+ }
987
+ function writeScalar(v) {
988
+ if (v === null) return "null";
989
+ if (typeof v === "boolean") return v ? "true" : "false";
990
+ if (typeof v === "number") return Number.isFinite(v) ? String(v) : "null";
991
+ const s = String(v);
992
+ if (needsQuote(s)) return JSON.stringify(s);
993
+ return s;
994
+ }
995
+ function writeYamlNode(v, indent) {
996
+ const pad = " ".repeat(indent);
997
+ if (Array.isArray(v)) {
998
+ if (v.length === 0) return pad + "[]";
999
+ return v.map((item) => {
1000
+ if (item !== null && typeof item === "object") {
1001
+ const inner = writeYamlNode(item, indent + 1);
1002
+ return pad + "-\n" + inner;
1003
+ }
1004
+ return pad + "- " + writeScalar(item);
1005
+ }).join("\n");
1006
+ }
1007
+ if (v !== null && typeof v === "object") {
1008
+ const keys = Object.keys(v);
1009
+ if (keys.length === 0) return pad + "{}";
1010
+ return keys.map((k) => {
1011
+ const val = v[k];
1012
+ const keyStr = needsQuote(k) ? JSON.stringify(k) : k;
1013
+ if (val !== null && typeof val === "object" && (Array.isArray(val) ? val.length : Object.keys(val).length)) {
1014
+ const nested = writeYamlNode(val, indent + 1);
1015
+ return pad + keyStr + ":\n" + nested;
1016
+ }
1017
+ return pad + keyStr + ": " + writeScalar(val);
1018
+ }).join("\n");
1019
+ }
1020
+ return pad + writeScalar(v);
1021
+ }
1022
+ function stringifyYaml(value) {
1023
+ if (value === null || typeof value !== "object") return writeScalar(value) + "\n";
1024
+ return writeYamlNode(value, 0) + "\n";
1025
+ }
1026
+
1027
+ // src/toml.ts
1028
+ function parseValue(raw) {
1029
+ const s = raw.trim();
1030
+ if (s === "true") return true;
1031
+ if (s === "false") return false;
1032
+ if (s[0] === '"') return parseBasicString(s);
1033
+ if (s[0] === "'") return parseLiteralString(s);
1034
+ if (s[0] === "[") return parseArray(s);
1035
+ if (s[0] === "{") return parseInline(s);
1036
+ const numStr = s.replace(/_/g, "");
1037
+ if (/^[-+]?(0|[1-9]\d*)$/.test(numStr)) return parseInt(numStr, 10);
1038
+ if (/^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$/.test(numStr) && /\d/.test(numStr)) {
1039
+ const n = Number(numStr);
1040
+ if (!Number.isNaN(n)) return n;
1041
+ }
1042
+ if (/^0x[0-9a-fA-F]+$/.test(numStr)) return parseInt(numStr, 16);
1043
+ return s;
1044
+ }
1045
+ function parseBasicString(s) {
1046
+ if (s.length < 2 || s[s.length - 1] !== '"') throw new JsonToolError(`TOML: unterminated string ${s}`);
1047
+ return s.slice(1, -1).replace(/\\(["\\/nrt]|u[0-9a-fA-F]{4})/g, (_m, c) => {
1048
+ if (c[0] === "u") return String.fromCharCode(parseInt(c.slice(1), 16));
1049
+ return c === "n" ? "\n" : c === "t" ? " " : c === "r" ? "\r" : c;
1050
+ });
1051
+ }
1052
+ function parseLiteralString(s) {
1053
+ if (s.length < 2 || s[s.length - 1] !== "'") throw new JsonToolError(`TOML: unterminated literal string ${s}`);
1054
+ return s.slice(1, -1);
1055
+ }
1056
+ function splitTop(s, open, close) {
1057
+ const inner = s.slice(1, -1);
1058
+ const items = [];
1059
+ let depth = 0, inD = false, inSq = false, cur = "";
1060
+ for (let i = 0; i < inner.length; i++) {
1061
+ const ch = inner[i];
1062
+ if (inD) {
1063
+ cur += ch;
1064
+ if (ch === '"' && inner[i - 1] !== "\\") inD = false;
1065
+ continue;
1066
+ }
1067
+ if (inSq) {
1068
+ cur += ch;
1069
+ if (ch === "'") inSq = false;
1070
+ continue;
1071
+ }
1072
+ if (ch === '"') {
1073
+ inD = true;
1074
+ cur += ch;
1075
+ continue;
1076
+ }
1077
+ if (ch === "'") {
1078
+ inSq = true;
1079
+ cur += ch;
1080
+ continue;
1081
+ }
1082
+ if (ch === "[" || ch === "{") depth++;
1083
+ if (ch === "]" || ch === "}") depth--;
1084
+ if (ch === "," && depth === 0) {
1085
+ items.push(cur);
1086
+ cur = "";
1087
+ continue;
1088
+ }
1089
+ cur += ch;
1090
+ }
1091
+ if (cur.trim() !== "") items.push(cur);
1092
+ void open;
1093
+ void close;
1094
+ return items;
1095
+ }
1096
+ function parseArray(s) {
1097
+ const items = splitTop(s, "[", "]");
1098
+ return items.map((it) => parseValue(it.trim()));
1099
+ }
1100
+ function parseInline(s) {
1101
+ const items = splitTop(s, "{", "}");
1102
+ const obj = {};
1103
+ for (const it of items) {
1104
+ const t = it.trim();
1105
+ if (t === "") continue;
1106
+ const eq = findEquals(t);
1107
+ const key = t.slice(0, eq).trim();
1108
+ const val = parseValue(t.slice(eq + 1).trim());
1109
+ assignDotted(obj, splitKeyPath(key), val);
1110
+ }
1111
+ return obj;
1112
+ }
1113
+ function findEquals(line) {
1114
+ let inD = false, inSq = false;
1115
+ for (let i = 0; i < line.length; i++) {
1116
+ const ch = line[i];
1117
+ if (inD) {
1118
+ if (ch === '"' && line[i - 1] !== "\\") inD = false;
1119
+ continue;
1120
+ }
1121
+ if (inSq) {
1122
+ if (ch === "'") inSq = false;
1123
+ continue;
1124
+ }
1125
+ if (ch === '"') {
1126
+ inD = true;
1127
+ continue;
1128
+ }
1129
+ if (ch === "'") {
1130
+ inSq = true;
1131
+ continue;
1132
+ }
1133
+ if (ch === "=") return i;
1134
+ }
1135
+ return -1;
1136
+ }
1137
+ function splitKeyPath(key) {
1138
+ const parts = [];
1139
+ let cur = "", inD = false, inSq = false;
1140
+ for (let i = 0; i < key.length; i++) {
1141
+ const ch = key[i];
1142
+ if (inD) {
1143
+ if (ch === '"') {
1144
+ inD = false;
1145
+ } else cur += ch;
1146
+ continue;
1147
+ }
1148
+ if (inSq) {
1149
+ if (ch === "'") {
1150
+ inSq = false;
1151
+ } else cur += ch;
1152
+ continue;
1153
+ }
1154
+ if (ch === '"') {
1155
+ inD = true;
1156
+ continue;
1157
+ }
1158
+ if (ch === "'") {
1159
+ inSq = true;
1160
+ continue;
1161
+ }
1162
+ if (ch === ".") {
1163
+ parts.push(cur.trim());
1164
+ cur = "";
1165
+ continue;
1166
+ }
1167
+ cur += ch;
1168
+ }
1169
+ parts.push(cur.trim());
1170
+ return parts.filter((p) => p !== "");
1171
+ }
1172
+ function assignDotted(root, path, value) {
1173
+ let cur = root;
1174
+ for (let i = 0; i < path.length - 1; i++) {
1175
+ const k = path[i];
1176
+ if (isForbiddenKey(k)) return;
1177
+ if (!isPlainObject(cur[k])) safeSet(cur, k, {});
1178
+ cur = cur[k];
1179
+ }
1180
+ const last = path[path.length - 1];
1181
+ if (!isForbiddenKey(last)) safeSet(cur, last, value);
1182
+ }
1183
+ function ensureTable(root, path) {
1184
+ let cur = root;
1185
+ for (const k of path) {
1186
+ if (isForbiddenKey(k)) throw new JsonToolError(`TOML: forbidden key "${k}"`);
1187
+ const existing = cur[k];
1188
+ if (Array.isArray(existing)) {
1189
+ const arr = existing;
1190
+ cur = arr[arr.length - 1];
1191
+ } else if (isPlainObject(existing)) {
1192
+ cur = existing;
1193
+ } else {
1194
+ safeSet(cur, k, {});
1195
+ cur = cur[k];
1196
+ }
1197
+ }
1198
+ return cur;
1199
+ }
1200
+ function ensureArrayTable(root, path) {
1201
+ const parent = ensureTable(root, path.slice(0, -1));
1202
+ const last = path[path.length - 1];
1203
+ if (isForbiddenKey(last)) throw new JsonToolError(`TOML: forbidden key "${last}"`);
1204
+ if (!Array.isArray(parent[last])) safeSet(parent, last, []);
1205
+ const arr = parent[last];
1206
+ const tbl = {};
1207
+ arr.push(tbl);
1208
+ return tbl;
1209
+ }
1210
+ function parseToml(src) {
1211
+ const root = {};
1212
+ let cur = root;
1213
+ const lines = src.split(/\r?\n/);
1214
+ for (let li = 0; li < lines.length; li++) {
1215
+ let line = lines[li];
1216
+ line = stripComment2(line).trim();
1217
+ if (line === "") continue;
1218
+ if (line.startsWith("[[") && line.endsWith("]]")) {
1219
+ const path = splitKeyPath(line.slice(2, -2).trim());
1220
+ cur = ensureArrayTable(root, path);
1221
+ continue;
1222
+ }
1223
+ if (line.startsWith("[") && line.endsWith("]")) {
1224
+ const path = splitKeyPath(line.slice(1, -1).trim());
1225
+ cur = ensureTable(root, path);
1226
+ continue;
1227
+ }
1228
+ const eq = findEquals(line);
1229
+ if (eq < 0) throw new JsonToolError(`TOML: expected "key = value" at line ${li + 1}: "${line}"`);
1230
+ const key = line.slice(0, eq).trim();
1231
+ const value = parseValue(line.slice(eq + 1).trim());
1232
+ assignDotted(cur, splitKeyPath(key), value);
1233
+ }
1234
+ return root;
1235
+ }
1236
+ function stripComment2(line) {
1237
+ let inD = false, inSq = false;
1238
+ for (let i = 0; i < line.length; i++) {
1239
+ const ch = line[i];
1240
+ if (inD) {
1241
+ if (ch === '"' && line[i - 1] !== "\\") inD = false;
1242
+ continue;
1243
+ }
1244
+ if (inSq) {
1245
+ if (ch === "'") inSq = false;
1246
+ continue;
1247
+ }
1248
+ if (ch === '"') {
1249
+ inD = true;
1250
+ continue;
1251
+ }
1252
+ if (ch === "'") {
1253
+ inSq = true;
1254
+ continue;
1255
+ }
1256
+ if (ch === "#") return line.slice(0, i);
1257
+ }
1258
+ return line;
1259
+ }
1260
+ function bareKey(k) {
1261
+ return /^[A-Za-z0-9_-]+$/.test(k) ? k : JSON.stringify(k);
1262
+ }
1263
+ function writeInlineValue(v) {
1264
+ if (v === null) return '""';
1265
+ if (typeof v === "boolean") return v ? "true" : "false";
1266
+ if (typeof v === "number") return Number.isFinite(v) ? String(v) : '"NaN"';
1267
+ if (typeof v === "string") return JSON.stringify(v);
1268
+ if (Array.isArray(v)) return "[" + v.map(writeInlineValue).join(", ") + "]";
1269
+ const entries = Object.keys(v).map((k) => `${bareKey(k)} = ${writeInlineValue(v[k])}`);
1270
+ return "{ " + entries.join(", ") + " }";
1271
+ }
1272
+ function isTableArray(v) {
1273
+ return Array.isArray(v) && v.length > 0 && v.every((x) => isPlainObject(x));
1274
+ }
1275
+ function writeToml(obj, prefix, out) {
1276
+ const scalars = [];
1277
+ const tables = [];
1278
+ const tableArrays = [];
1279
+ for (const k of Object.keys(obj)) {
1280
+ const v = obj[k];
1281
+ if (isPlainObject(v)) tables.push([k, v]);
1282
+ else if (isTableArray(v)) tableArrays.push([k, v]);
1283
+ else scalars.push(`${bareKey(k)} = ${writeInlineValue(v)}`);
1284
+ }
1285
+ if (scalars.length) out.push(scalars.join("\n"));
1286
+ for (const [k, v] of tables) {
1287
+ const path = [...prefix, k];
1288
+ out.push(`
1289
+ [${path.map(bareKey).join(".")}]`);
1290
+ writeToml(v, path, out);
1291
+ }
1292
+ for (const [k, arr] of tableArrays) {
1293
+ const path = [...prefix, k];
1294
+ for (const item of arr) {
1295
+ out.push(`
1296
+ [[${path.map(bareKey).join(".")}]]`);
1297
+ writeToml(item, path, out);
1298
+ }
1299
+ }
1300
+ }
1301
+ function stringifyToml(value) {
1302
+ if (!isPlainObject(value)) {
1303
+ throw new JsonToolError("TOML output requires a top-level object/table");
1304
+ }
1305
+ const out = [];
1306
+ writeToml(value, [], out);
1307
+ return out.join("\n").replace(/^\n+/, "").replace(/\n{3,}/g, "\n\n") + "\n";
1308
+ }
1309
+
1310
+ // src/csv.ts
1311
+ function coerce(raw) {
1312
+ if (raw === "") return "";
1313
+ if (raw === "true") return true;
1314
+ if (raw === "false") return false;
1315
+ if (raw === "null") return null;
1316
+ if (/^[-+]?(0|[1-9]\d*)$/.test(raw)) {
1317
+ const n = parseInt(raw, 10);
1318
+ if (String(n) === raw.replace(/^\+/, "")) return n;
1319
+ }
1320
+ if (/^[-+]?(\d+\.\d+|\.\d+|\d+)([eE][-+]?\d+)?$/.test(raw)) {
1321
+ const n = Number(raw);
1322
+ if (!Number.isNaN(n)) return n;
1323
+ }
1324
+ return raw;
1325
+ }
1326
+ function parseCsv(src, opts = {}) {
1327
+ const delim = opts.delimiter ?? ",";
1328
+ const parseTypes = opts.parseTypes ?? true;
1329
+ const rows = parseCsvRows(src, delim);
1330
+ if (rows.length === 0) return [];
1331
+ const header = rows[0];
1332
+ const out = [];
1333
+ for (let r = 1; r < rows.length; r++) {
1334
+ const row = rows[r];
1335
+ if (row.length === 1 && row[0] === "") continue;
1336
+ const obj = {};
1337
+ for (let c = 0; c < header.length; c++) {
1338
+ const key = header[c] ?? `col${c}`;
1339
+ if (isForbiddenKey(key)) continue;
1340
+ const cell2 = row[c] ?? "";
1341
+ safeSet(obj, key, parseTypes ? coerce(cell2) : cell2);
1342
+ }
1343
+ out.push(obj);
1344
+ }
1345
+ return out;
1346
+ }
1347
+ function parseCsvRows(src, delim) {
1348
+ const rows = [];
1349
+ let field = "";
1350
+ let row = [];
1351
+ let inQuotes = false;
1352
+ let i = 0;
1353
+ const n = src.length;
1354
+ if (src.charCodeAt(0) === 65279) i = 1;
1355
+ while (i < n) {
1356
+ const ch = src[i];
1357
+ if (inQuotes) {
1358
+ if (ch === '"') {
1359
+ if (src[i + 1] === '"') {
1360
+ field += '"';
1361
+ i += 2;
1362
+ continue;
1363
+ }
1364
+ inQuotes = false;
1365
+ i++;
1366
+ continue;
1367
+ }
1368
+ field += ch;
1369
+ i++;
1370
+ continue;
1371
+ }
1372
+ if (ch === '"') {
1373
+ inQuotes = true;
1374
+ i++;
1375
+ continue;
1376
+ }
1377
+ if (ch === delim) {
1378
+ row.push(field);
1379
+ field = "";
1380
+ i++;
1381
+ continue;
1382
+ }
1383
+ if (ch === "\r") {
1384
+ i++;
1385
+ continue;
1386
+ }
1387
+ if (ch === "\n") {
1388
+ row.push(field);
1389
+ rows.push(row);
1390
+ row = [];
1391
+ field = "";
1392
+ i++;
1393
+ continue;
1394
+ }
1395
+ field += ch;
1396
+ i++;
1397
+ }
1398
+ if (field !== "" || row.length > 0) {
1399
+ row.push(field);
1400
+ rows.push(row);
1401
+ }
1402
+ return rows;
1403
+ }
1404
+ function needsQuote2(s, delim) {
1405
+ return s.includes(delim) || s.includes('"') || s.includes("\n") || s.includes("\r");
1406
+ }
1407
+ function cell(v, delim) {
1408
+ let s;
1409
+ if (v === null || v === void 0) s = "";
1410
+ else if (typeof v === "object") s = JSON.stringify(v);
1411
+ else s = String(v);
1412
+ if (needsQuote2(s, delim)) return '"' + s.replace(/"/g, '""') + '"';
1413
+ return s;
1414
+ }
1415
+ function stringifyCsv(value, opts = {}) {
1416
+ const delim = opts.delimiter ?? ",";
1417
+ if (!Array.isArray(value)) {
1418
+ throw new JsonToolError("CSV output requires an array of objects");
1419
+ }
1420
+ const rows = value;
1421
+ let columns = opts.columns;
1422
+ if (!columns) {
1423
+ const seen = [];
1424
+ const set = /* @__PURE__ */ new Set();
1425
+ for (const r of rows) {
1426
+ if (isPlainObject(r)) {
1427
+ for (const k of Object.keys(r)) if (!set.has(k)) {
1428
+ set.add(k);
1429
+ seen.push(k);
1430
+ }
1431
+ }
1432
+ }
1433
+ columns = seen;
1434
+ }
1435
+ const lines = [];
1436
+ lines.push(columns.map((c) => cell(c, delim)).join(delim));
1437
+ for (const r of rows) {
1438
+ if (isPlainObject(r)) {
1439
+ lines.push(columns.map((c) => cell(r[c] ?? null, delim)).join(delim));
1440
+ } else {
1441
+ lines.push(cell(r, delim));
1442
+ }
1443
+ }
1444
+ return lines.join("\n") + "\n";
1445
+ }
1446
+ function parseNdjson(src) {
1447
+ const out = [];
1448
+ const lines = src.split(/\r?\n/);
1449
+ for (let i = 0; i < lines.length; i++) {
1450
+ const line = lines[i].trim();
1451
+ if (line === "") continue;
1452
+ try {
1453
+ out.push(JSON.parse(line));
1454
+ } catch (err) {
1455
+ throw new JsonToolError(`NDJSON: invalid JSON on line ${i + 1}: ${err.message}`);
1456
+ }
1457
+ }
1458
+ return out;
1459
+ }
1460
+ function stringifyNdjson(value) {
1461
+ const arr = Array.isArray(value) ? value : [value];
1462
+ return arr.map((v) => JSON.stringify(v)).join("\n") + "\n";
1463
+ }
1464
+
1465
+ // src/convert.ts
1466
+ var EXT_MAP = {
1467
+ json: "json",
1468
+ json5: "json",
1469
+ yaml: "yaml",
1470
+ yml: "yaml",
1471
+ toml: "toml",
1472
+ csv: "csv",
1473
+ tsv: "csv",
1474
+ ndjson: "ndjson",
1475
+ jsonl: "ndjson"
1476
+ };
1477
+ function formatFromExt(filename) {
1478
+ const m = /\.([A-Za-z0-9]+)$/.exec(filename);
1479
+ if (!m) return void 0;
1480
+ return EXT_MAP[m[1].toLowerCase()];
1481
+ }
1482
+ function detectFormat(src) {
1483
+ const trimmed = src.trim();
1484
+ if (trimmed === "") return "json";
1485
+ const lines = trimmed.split(/\r?\n/).filter((l) => l.trim() !== "");
1486
+ if (lines.length > 1 && lines.every((l) => {
1487
+ const t = l.trim();
1488
+ return t.startsWith("{") && t.endsWith("}") || t.startsWith("[") && t.endsWith("]");
1489
+ })) {
1490
+ if (lines.every((l) => {
1491
+ try {
1492
+ JSON.parse(l);
1493
+ return true;
1494
+ } catch {
1495
+ return false;
1496
+ }
1497
+ })) return "ndjson";
1498
+ }
1499
+ if (trimmed[0] === "{" || trimmed[0] === "[") {
1500
+ try {
1501
+ JSON.parse(trimmed);
1502
+ return "json";
1503
+ } catch {
1504
+ }
1505
+ }
1506
+ if (/^\s*\[\[?[^\]]+\]\]?\s*$/m.test(trimmed) && /^\s*[A-Za-z0-9_."'-]+\s*=/m.test(trimmed)) return "toml";
1507
+ const first = lines[0].trim();
1508
+ if (first.includes(",") && !first.includes(": ") && !/^[\[{]/.test(first) && lines.length >= 1) {
1509
+ if (!/^\s*-\s/.test(first)) return "csv";
1510
+ }
1511
+ if (/^\s*[A-Za-z0-9_."'-]+\s*=\s*/m.test(trimmed) && !/:\s/.test(trimmed)) return "toml";
1512
+ return "yaml";
1513
+ }
1514
+ function parseFormat(src, format) {
1515
+ switch (format) {
1516
+ case "json": {
1517
+ try {
1518
+ return sanitizeJson(JSON.parse(src === "" ? "null" : src));
1519
+ } catch (err) {
1520
+ throw new JsonToolError(`Invalid JSON: ${err.message}`);
1521
+ }
1522
+ }
1523
+ case "yaml":
1524
+ return parseYaml(src);
1525
+ case "toml":
1526
+ return parseToml(src);
1527
+ case "csv":
1528
+ return parseCsv(src);
1529
+ case "ndjson":
1530
+ return parseNdjson(src);
1531
+ }
1532
+ }
1533
+ function stringifyFormat(value, format, opts = {}) {
1534
+ switch (format) {
1535
+ case "json": {
1536
+ const space = opts.minify ? void 0 : opts.indent ?? 2;
1537
+ return JSON.stringify(value, null, space) + (opts.minify ? "" : "\n");
1538
+ }
1539
+ case "yaml":
1540
+ return stringifyYaml(value);
1541
+ case "toml":
1542
+ return stringifyToml(value);
1543
+ case "csv":
1544
+ return stringifyCsv(value);
1545
+ case "ndjson":
1546
+ return stringifyNdjson(value);
1547
+ }
1548
+ }
1549
+ function convert(src, from, to, opts = {}) {
1550
+ const value = parseFormat(src, from);
1551
+ return stringifyFormat(value, to, opts);
1552
+ }
1553
+ function sanitizeJson(v) {
1554
+ if (v === null || typeof v !== "object") return v;
1555
+ if (Array.isArray(v)) return v.map(sanitizeJson);
1556
+ const out = {};
1557
+ for (const k of Object.keys(v)) {
1558
+ if (isForbiddenKey(k)) continue;
1559
+ safeSet(out, k, sanitizeJson(v[k]));
1560
+ }
1561
+ return out;
1562
+ }
1563
+
1564
+ // src/schema.ts
1565
+ var FORMATS = {
1566
+ email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
1567
+ uri: /^[A-Za-z][A-Za-z0-9+.-]*:\/\/\S+$/,
1568
+ url: /^https?:\/\/\S+$/i,
1569
+ uuid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
1570
+ date: /^\d{4}-\d{2}-\d{2}$/,
1571
+ "date-time": /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?$/,
1572
+ time: /^\d{2}:\d{2}:\d{2}(\.\d+)?$/,
1573
+ ipv4: /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/,
1574
+ hostname: /^(?=.{1,253}$)([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/
1575
+ };
1576
+ var Validator = class _Validator {
1577
+ root;
1578
+ errors = [];
1579
+ constructor(root) {
1580
+ this.root = root;
1581
+ }
1582
+ validate(data, schema, path) {
1583
+ if (schema === true || schema === void 0) return;
1584
+ if (schema === false) {
1585
+ this.err(path, "schema is `false` \u2014 no value is valid here");
1586
+ return;
1587
+ }
1588
+ if (typeof schema !== "object") return;
1589
+ if (typeof schema["$ref"] === "string") {
1590
+ const resolved = this.resolveRef(schema["$ref"]);
1591
+ if (resolved === void 0) this.err(path, `cannot resolve $ref "${schema["$ref"]}"`);
1592
+ else this.validate(data, resolved, path);
1593
+ return;
1594
+ }
1595
+ this.checkType(data, schema, path);
1596
+ this.checkEnumConst(data, schema, path);
1597
+ this.checkNumber(data, schema, path);
1598
+ this.checkString(data, schema, path);
1599
+ this.checkArray(data, schema, path);
1600
+ this.checkObject(data, schema, path);
1601
+ this.checkCombinators(data, schema, path);
1602
+ }
1603
+ err(path, message) {
1604
+ this.errors.push({ path, message });
1605
+ }
1606
+ resolveRef(ref) {
1607
+ if (!ref.startsWith("#/")) return void 0;
1608
+ const parts = ref.slice(2).split("/").map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
1609
+ let cur = this.root;
1610
+ for (const p of parts) {
1611
+ if (cur && typeof cur === "object") cur = cur[p];
1612
+ else return void 0;
1613
+ }
1614
+ return cur;
1615
+ }
1616
+ checkType(data, schema, path) {
1617
+ const t = schema["type"];
1618
+ if (t === void 0) return;
1619
+ const types = Array.isArray(t) ? t : [t];
1620
+ const actual = typeOf(data);
1621
+ const ok = types.some((want) => {
1622
+ if (want === "integer") return actual === "number" && Number.isInteger(data);
1623
+ return want === actual;
1624
+ });
1625
+ if (!ok) this.err(path, `expected type ${types.join(" | ")}, got ${actual}`);
1626
+ }
1627
+ checkEnumConst(data, schema, path) {
1628
+ if ("const" in schema && !deepEqual(data, schema["const"])) {
1629
+ this.err(path, `must equal const ${JSON.stringify(schema["const"])}`);
1630
+ }
1631
+ if (Array.isArray(schema["enum"])) {
1632
+ const list = schema["enum"];
1633
+ if (!list.some((e) => deepEqual(e, data))) {
1634
+ this.err(path, `must be one of ${JSON.stringify(list)}`);
1635
+ }
1636
+ }
1637
+ }
1638
+ checkNumber(data, schema, path) {
1639
+ if (typeof data !== "number") return;
1640
+ if (typeof schema["minimum"] === "number" && data < schema["minimum"]) this.err(path, `must be >= ${schema["minimum"]}`);
1641
+ if (typeof schema["maximum"] === "number" && data > schema["maximum"]) this.err(path, `must be <= ${schema["maximum"]}`);
1642
+ if (typeof schema["exclusiveMinimum"] === "number" && data <= schema["exclusiveMinimum"]) this.err(path, `must be > ${schema["exclusiveMinimum"]}`);
1643
+ if (typeof schema["exclusiveMaximum"] === "number" && data >= schema["exclusiveMaximum"]) this.err(path, `must be < ${schema["exclusiveMaximum"]}`);
1644
+ if (typeof schema["multipleOf"] === "number" && schema["multipleOf"] > 0) {
1645
+ const q = data / schema["multipleOf"];
1646
+ if (Math.abs(q - Math.round(q)) > 1e-9) this.err(path, `must be a multiple of ${schema["multipleOf"]}`);
1647
+ }
1648
+ }
1649
+ checkString(data, schema, path) {
1650
+ if (typeof data !== "string") return;
1651
+ if (typeof schema["minLength"] === "number" && data.length < schema["minLength"]) this.err(path, `must be at least ${schema["minLength"]} characters`);
1652
+ if (typeof schema["maxLength"] === "number" && data.length > schema["maxLength"]) this.err(path, `must be at most ${schema["maxLength"]} characters`);
1653
+ if (typeof schema["pattern"] === "string") {
1654
+ let re = null;
1655
+ try {
1656
+ re = new RegExp(schema["pattern"]);
1657
+ } catch {
1658
+ }
1659
+ if (re && !re.test(data)) this.err(path, `must match pattern /${schema["pattern"]}/`);
1660
+ }
1661
+ if (typeof schema["format"] === "string") {
1662
+ const fmt = FORMATS[schema["format"]];
1663
+ if (fmt && !fmt.test(data)) this.err(path, `must be a valid ${schema["format"]}`);
1664
+ if (schema["format"] === "ipv4" && fmt && fmt.test(data)) {
1665
+ if (!data.split(".").every((o) => Number(o) <= 255)) this.err(path, `must be a valid ipv4`);
1666
+ }
1667
+ }
1668
+ }
1669
+ checkArray(data, schema, path) {
1670
+ if (!Array.isArray(data)) return;
1671
+ if (typeof schema["minItems"] === "number" && data.length < schema["minItems"]) this.err(path, `must have at least ${schema["minItems"]} items`);
1672
+ if (typeof schema["maxItems"] === "number" && data.length > schema["maxItems"]) this.err(path, `must have at most ${schema["maxItems"]} items`);
1673
+ if (schema["uniqueItems"] === true) {
1674
+ for (let i = 0; i < data.length; i++) {
1675
+ for (let j = i + 1; j < data.length; j++) {
1676
+ if (deepEqual(data[i], data[j])) {
1677
+ this.err(path, `items must be unique (indexes ${i} and ${j})`);
1678
+ break;
1679
+ }
1680
+ }
1681
+ }
1682
+ }
1683
+ const items = schema["items"];
1684
+ if (Array.isArray(items)) {
1685
+ for (let i = 0; i < items.length && i < data.length; i++) {
1686
+ this.validate(data[i], items[i], `${path}[${i}]`);
1687
+ }
1688
+ const additional = schema["additionalItems"];
1689
+ if (additional !== void 0 && data.length > items.length) {
1690
+ for (let i = items.length; i < data.length; i++) {
1691
+ if (additional === false) this.err(`${path}[${i}]`, "additional items are not allowed");
1692
+ else this.validate(data[i], additional, `${path}[${i}]`);
1693
+ }
1694
+ }
1695
+ } else if (items !== void 0) {
1696
+ for (let i = 0; i < data.length; i++) this.validate(data[i], items, `${path}[${i}]`);
1697
+ }
1698
+ }
1699
+ checkObject(data, schema, path) {
1700
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return;
1701
+ const obj = data;
1702
+ const keys = Object.keys(obj);
1703
+ if (Array.isArray(schema["required"])) {
1704
+ for (const req of schema["required"]) {
1705
+ if (!Object.prototype.hasOwnProperty.call(obj, req)) this.err(path, `missing required property "${req}"`);
1706
+ }
1707
+ }
1708
+ if (typeof schema["minProperties"] === "number" && keys.length < schema["minProperties"]) this.err(path, `must have at least ${schema["minProperties"]} properties`);
1709
+ if (typeof schema["maxProperties"] === "number" && keys.length > schema["maxProperties"]) this.err(path, `must have at most ${schema["maxProperties"]} properties`);
1710
+ const props = schema["properties"] || {};
1711
+ const patternProps = schema["patternProperties"] || {};
1712
+ const additional = schema["additionalProperties"];
1713
+ for (const key of keys) {
1714
+ const childPath = `${path}.${key}`;
1715
+ let matched = false;
1716
+ if (Object.prototype.hasOwnProperty.call(props, key)) {
1717
+ matched = true;
1718
+ this.validate(obj[key], props[key], childPath);
1719
+ }
1720
+ for (const pat of Object.keys(patternProps)) {
1721
+ let re = null;
1722
+ try {
1723
+ re = new RegExp(pat);
1724
+ } catch {
1725
+ }
1726
+ if (re && re.test(key)) {
1727
+ matched = true;
1728
+ this.validate(obj[key], patternProps[pat], childPath);
1729
+ }
1730
+ }
1731
+ if (!matched && additional !== void 0) {
1732
+ if (additional === false) this.err(childPath, `additional property "${key}" is not allowed`);
1733
+ else if (additional !== true) this.validate(obj[key], additional, childPath);
1734
+ }
1735
+ }
1736
+ }
1737
+ checkCombinators(data, schema, path) {
1738
+ if (Array.isArray(schema["allOf"])) {
1739
+ for (const sub of schema["allOf"]) this.validate(data, sub, path);
1740
+ }
1741
+ if (Array.isArray(schema["anyOf"])) {
1742
+ const subs = schema["anyOf"];
1743
+ const ok = subs.some((sub) => this.subValid(data, sub, path));
1744
+ if (!ok) this.err(path, "must match at least one schema in anyOf");
1745
+ }
1746
+ if (Array.isArray(schema["oneOf"])) {
1747
+ const subs = schema["oneOf"];
1748
+ const count = subs.filter((sub) => this.subValid(data, sub, path)).length;
1749
+ if (count !== 1) this.err(path, `must match exactly one schema in oneOf (matched ${count})`);
1750
+ }
1751
+ if (schema["not"] !== void 0) {
1752
+ if (this.subValid(data, schema["not"], path)) this.err(path, "must not match the `not` schema");
1753
+ }
1754
+ }
1755
+ subValid(data, schema, path) {
1756
+ const probe = new _Validator(this.root);
1757
+ probe.validate(data, schema, path);
1758
+ return probe.errors.length === 0;
1759
+ }
1760
+ result() {
1761
+ return { valid: this.errors.length === 0, errors: this.errors };
1762
+ }
1763
+ };
1764
+ function validateSchema(data, schema) {
1765
+ const v = new Validator(schema);
1766
+ v.validate(data, schema, "$");
1767
+ return v.result();
1768
+ }
1769
+
1770
+ // src/diff.ts
1771
+ function join(base, key) {
1772
+ if (typeof key === "number") return `${base}[${key}]`;
1773
+ return base === "" ? key : `${base}.${key}`;
1774
+ }
1775
+ function walk(a, b, path, out) {
1776
+ if (deepEqual(a, b)) return;
1777
+ const aMissing = a === void 0;
1778
+ const bMissing = b === void 0;
1779
+ if (aMissing && !bMissing) {
1780
+ out.push({ kind: "added", path, after: b });
1781
+ return;
1782
+ }
1783
+ if (!aMissing && bMissing) {
1784
+ out.push({ kind: "removed", path, before: a });
1785
+ return;
1786
+ }
1787
+ if (isPlainObject(a) && isPlainObject(b)) {
1788
+ const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
1789
+ for (const k of [...keys].sort()) {
1790
+ walk(
1791
+ Object.prototype.hasOwnProperty.call(a, k) ? a[k] : void 0,
1792
+ Object.prototype.hasOwnProperty.call(b, k) ? b[k] : void 0,
1793
+ join(path, k),
1794
+ out
1795
+ );
1796
+ }
1797
+ return;
1798
+ }
1799
+ if (Array.isArray(a) && Array.isArray(b)) {
1800
+ const max = Math.max(a.length, b.length);
1801
+ for (let i = 0; i < max; i++) {
1802
+ walk(i < a.length ? a[i] : void 0, i < b.length ? b[i] : void 0, join(path, i), out);
1803
+ }
1804
+ return;
1805
+ }
1806
+ out.push({ kind: "changed", path: path === "" ? "$" : path, before: a, after: b });
1807
+ }
1808
+ function diff(a, b) {
1809
+ const out = [];
1810
+ walk(a, b, "", out);
1811
+ return out;
1812
+ }
1813
+ function isEqual(a, b) {
1814
+ return deepEqual(a, b);
1815
+ }
1816
+
1817
+ // src/merge.ts
1818
+ function mergeArrays(a, b, strat) {
1819
+ if (strat.mode === "replace") return deepClone(b);
1820
+ if (strat.mode === "concat") return [...deepClone(a), ...deepClone(b)];
1821
+ const key = strat.key;
1822
+ const out = deepClone(a);
1823
+ const indexByKey = /* @__PURE__ */ new Map();
1824
+ out.forEach((item, i) => {
1825
+ if (isPlainObject(item) && item[key] !== void 0) indexByKey.set(JSON.stringify(item[key]), i);
1826
+ });
1827
+ for (const item of b) {
1828
+ if (isPlainObject(item) && item[key] !== void 0) {
1829
+ const id = JSON.stringify(item[key]);
1830
+ if (indexByKey.has(id)) {
1831
+ const idx = indexByKey.get(id);
1832
+ out[idx] = mergeTwo(out[idx], item, { array: strat });
1833
+ } else {
1834
+ indexByKey.set(id, out.length);
1835
+ out.push(deepClone(item));
1836
+ }
1837
+ } else {
1838
+ out.push(deepClone(item));
1839
+ }
1840
+ }
1841
+ return out;
1842
+ }
1843
+ function mergeTwo(a, b, opts) {
1844
+ const strat = opts.array ?? { mode: "replace" };
1845
+ if (Array.isArray(a) && Array.isArray(b)) return mergeArrays(a, b, strat);
1846
+ if (isPlainObject(a) && isPlainObject(b)) {
1847
+ const out = {};
1848
+ for (const k of Object.keys(a)) {
1849
+ if (isForbiddenKey(k)) continue;
1850
+ safeSet(out, k, deepClone(a[k]));
1851
+ }
1852
+ for (const k of Object.keys(b)) {
1853
+ if (isForbiddenKey(k)) continue;
1854
+ if (Object.prototype.hasOwnProperty.call(out, k)) {
1855
+ safeSet(out, k, mergeTwo(out[k], b[k], opts));
1856
+ } else {
1857
+ safeSet(out, k, deepClone(b[k]));
1858
+ }
1859
+ }
1860
+ return out;
1861
+ }
1862
+ return deepClone(b);
1863
+ }
1864
+ function merge(values, opts = {}) {
1865
+ if (values.length === 0) return null;
1866
+ let acc = deepClone(values[0]);
1867
+ for (let i = 1; i < values.length; i++) acc = mergeTwo(acc, values[i], opts);
1868
+ return acc;
1869
+ }
1870
+ function parseArrayStrategy(spec, byKey) {
1871
+ if (byKey) return { mode: "by-key", key: byKey };
1872
+ if (spec === "concat") return { mode: "concat" };
1873
+ if (spec === "replace") return { mode: "replace" };
1874
+ if (spec && spec.startsWith("by-key")) {
1875
+ const key = spec.split(/[:=]/)[1];
1876
+ if (key) return { mode: "by-key", key };
1877
+ }
1878
+ return { mode: "replace" };
1879
+ }
1880
+
1881
+ // src/format.ts
1882
+ function formatJson(value, opts = {}) {
1883
+ const v = opts.sortKeys ? sortKeysDeep(value) : value;
1884
+ if (opts.minify) return JSON.stringify(v);
1885
+ const indent = opts.indent ?? 2;
1886
+ return JSON.stringify(v, null, indent);
1887
+ }
1888
+ function getPath(data, path) {
1889
+ const segments = parsePath(path);
1890
+ let cur = data;
1891
+ for (const seg of segments) {
1892
+ if (cur === null || cur === void 0) return void 0;
1893
+ if (typeof seg === "number") {
1894
+ if (!Array.isArray(cur)) return void 0;
1895
+ const idx = seg < 0 ? cur.length + seg : seg;
1896
+ cur = cur[idx];
1897
+ } else {
1898
+ if (Array.isArray(cur) || typeof cur !== "object") return void 0;
1899
+ if (!Object.prototype.hasOwnProperty.call(cur, seg)) return void 0;
1900
+ cur = cur[seg];
1901
+ }
1902
+ }
1903
+ return cur;
1904
+ }
1905
+ function parsePath(path) {
1906
+ const out = [];
1907
+ let i = 0;
1908
+ const n = path.length;
1909
+ if (path[0] === ".") i = 1;
1910
+ let cur = "";
1911
+ const flush = () => {
1912
+ if (cur !== "") {
1913
+ out.push(cur);
1914
+ cur = "";
1915
+ }
1916
+ };
1917
+ while (i < n) {
1918
+ const ch = path[i];
1919
+ if (ch === ".") {
1920
+ flush();
1921
+ i++;
1922
+ continue;
1923
+ }
1924
+ if (ch === "[") {
1925
+ flush();
1926
+ const close = path.indexOf("]", i);
1927
+ if (close < 0) throw new JsonToolError(`Unbalanced [ in path "${path}"`);
1928
+ const inner = path.slice(i + 1, close).trim();
1929
+ if (inner[0] === '"' && inner.endsWith('"') || inner[0] === "'" && inner.endsWith("'")) {
1930
+ out.push(inner.slice(1, -1));
1931
+ } else if (/^-?\d+$/.test(inner)) {
1932
+ out.push(parseInt(inner, 10));
1933
+ } else {
1934
+ out.push(inner);
1935
+ }
1936
+ i = close + 1;
1937
+ continue;
1938
+ }
1939
+ cur += ch;
1940
+ i++;
1941
+ }
1942
+ flush();
1943
+ return out;
1944
+ }
1945
+ // Annotate the CommonJS export names for ESM import in node:
1946
+ 0 && (module.exports = {
1947
+ JsonToolError,
1948
+ compareValues,
1949
+ compileQuery,
1950
+ convert,
1951
+ deepClone,
1952
+ deepEqual,
1953
+ detectFormat,
1954
+ diff,
1955
+ formatFromExt,
1956
+ formatJson,
1957
+ getPath,
1958
+ isEqual,
1959
+ isPlainObject,
1960
+ isValidQuery,
1961
+ merge,
1962
+ parseArrayStrategy,
1963
+ parseCsv,
1964
+ parseFormat,
1965
+ parseNdjson,
1966
+ parsePath,
1967
+ parseToml,
1968
+ parseYaml,
1969
+ query,
1970
+ queryAll,
1971
+ sanitizeJson,
1972
+ sortKeysDeep,
1973
+ stringifyCsv,
1974
+ stringifyFormat,
1975
+ stringifyNdjson,
1976
+ stringifyToml,
1977
+ stringifyYaml,
1978
+ typeOf,
1979
+ validateSchema
1980
+ });