snowkit 0.0.0-stage → 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.
@@ -0,0 +1,1241 @@
1
+ const IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2
+ const Q1 = "\u201C";
3
+ const Q2 = "\u201D";
4
+
5
+ export function pathJoin(base, key) {
6
+ if (typeof key === "number") return base + "[" + key + "]";
7
+ return IDENT.test(key) ? base + "." + key : base + "['" + String(key).replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "']";
8
+ }
9
+
10
+ function lineCol(text, pos) {
11
+ const before = text.slice(0, pos);
12
+ const line = before.split("\n").length;
13
+ return { line, column: pos - before.lastIndexOf("\n") };
14
+ }
15
+
16
+ function locate(text) {
17
+ let i = 0;
18
+ const fail = (msg, at = i) => {
19
+ const e = new Error(msg);
20
+ e.pos = Math.min(at, text.length);
21
+ throw e;
22
+ };
23
+ const ws = () => {
24
+ while (i < text.length && " \t\n\r".includes(text[i])) i++;
25
+ };
26
+ const describe = () => (i >= text.length ? "Unexpected end of input" : "Unexpected character " + Q1 + text[i] + Q2);
27
+ function value() {
28
+ ws();
29
+ const c = text[i];
30
+ if (c === "{") {
31
+ i++;
32
+ ws();
33
+ if (text[i] === "}") return i++;
34
+ for (;;) {
35
+ ws();
36
+ if (text[i] !== '"') fail(text[i] === "}" ? "Trailing comma before }" : text[i] === "'" ? "Property names need double quotes" : "Expected a property name in double quotes");
37
+ string();
38
+ ws();
39
+ if (text[i] !== ":") fail("Expected : after the property name");
40
+ i++;
41
+ value();
42
+ ws();
43
+ if (text[i] === ",") {
44
+ i++;
45
+ continue;
46
+ }
47
+ if (text[i] === "}") return i++;
48
+ fail(i >= text.length ? "Unexpected end of input, a } is missing" : "Expected , or } after a value");
49
+ }
50
+ }
51
+ if (c === "[") {
52
+ i++;
53
+ ws();
54
+ if (text[i] === "]") return i++;
55
+ for (;;) {
56
+ ws();
57
+ if (text[i] === "]") fail("Trailing comma before ]");
58
+ value();
59
+ ws();
60
+ if (text[i] === ",") {
61
+ i++;
62
+ continue;
63
+ }
64
+ if (text[i] === "]") return i++;
65
+ fail(i >= text.length ? "Unexpected end of input, a ] is missing" : "Expected , or ] after a value");
66
+ }
67
+ }
68
+ if (c === '"') return string();
69
+ if (c === "'") fail("Strings need double quotes, not single quotes");
70
+ if (c === "-" || (c >= "0" && c <= "9")) {
71
+ const m = /^-?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?/.exec(text.slice(i));
72
+ if (!m) fail("Invalid number");
73
+ i += m[0].length;
74
+ return;
75
+ }
76
+ for (const w of ["true", "false", "null"]) {
77
+ if (text.startsWith(w, i)) {
78
+ i += w.length;
79
+ return;
80
+ }
81
+ }
82
+ if (text.startsWith("//", i) || text.startsWith("/*", i)) fail("Comments are not allowed in JSON");
83
+ fail(describe());
84
+ }
85
+ function string() {
86
+ const start = i;
87
+ i++;
88
+ while (i < text.length) {
89
+ const c = text[i];
90
+ if (c === '"') return i++;
91
+ if (c === "\\") {
92
+ const n = text[i + 1];
93
+ if (n === "u") {
94
+ if (!/^[0-9a-fA-F]{4}$/.test(text.slice(i + 2, i + 6))) fail("Bad \\u escape in a string");
95
+ i += 6;
96
+ continue;
97
+ }
98
+ if (!'"\\/bfnrt'.includes(n)) fail("Bad escape \\" + (n || "") + " in a string");
99
+ i += 2;
100
+ continue;
101
+ }
102
+ if (c === "\n") fail("Unterminated string (strings can't contain line breaks)", start);
103
+ if (c < " ") fail("Control characters must be escaped in strings");
104
+ i++;
105
+ }
106
+ fail("Unterminated string", start);
107
+ }
108
+ value();
109
+ ws();
110
+ if (i < text.length) fail("Unexpected content after the end of the JSON value");
111
+ return null;
112
+ }
113
+
114
+ export function parseJsonText(text) {
115
+ if (!String(text).trim()) {
116
+ const e = new Error("Nothing to parse yet");
117
+ e.line = 1;
118
+ e.column = 1;
119
+ throw e;
120
+ }
121
+ try {
122
+ return JSON.parse(text);
123
+ } catch (first) {
124
+ let msg = first.message;
125
+ let pos = text.length;
126
+ try {
127
+ locate(text);
128
+ } catch (e) {
129
+ if (e.pos !== undefined) {
130
+ msg = e.message;
131
+ pos = e.pos;
132
+ }
133
+ }
134
+ const { line, column } = lineCol(text, pos);
135
+ const err = new Error("Line " + line + ", column " + column + ": " + msg);
136
+ err.line = line;
137
+ err.column = column;
138
+ err.reason = msg;
139
+ throw err;
140
+ }
141
+ }
142
+
143
+ function typeOf(v) {
144
+ if (v === null) return "null";
145
+ if (Array.isArray(v)) return "array";
146
+ if (typeof v === "number") return Number.isInteger(v) ? "integer" : "number";
147
+ return typeof v;
148
+ }
149
+
150
+ function isType(v, t) {
151
+ const a = typeOf(v);
152
+ return a === t || (t === "number" && a === "integer");
153
+ }
154
+
155
+ export function deepEqual(a, b) {
156
+ if (a === b) return true;
157
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
158
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
159
+ if (Array.isArray(a)) return a.length === b.length && a.every((x, i) => deepEqual(x, b[i]));
160
+ const ka = Object.keys(a);
161
+ const kb = Object.keys(b);
162
+ return ka.length === kb.length && ka.every((k) => Object.prototype.hasOwnProperty.call(b, k) && deepEqual(a[k], b[k]));
163
+ }
164
+
165
+ function validDate(y, m, d) {
166
+ if (m < 1 || m > 12 || d < 1) return false;
167
+ const days = [31, (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
168
+ return d <= days[m - 1];
169
+ }
170
+
171
+ const FORMATS = {
172
+ email: (s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s),
173
+ "idn-email": (s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s),
174
+ uri: (s) => /^[A-Za-z][A-Za-z0-9+.-]*:[^\s]*$/.test(s),
175
+ "uri-reference": (s) => !/\s/.test(s),
176
+ url: (s) => /^https?:\/\/[^\s/$.?#].[^\s]*$/i.test(s),
177
+ uuid: (s) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s),
178
+ date: (s) => {
179
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
180
+ return !!m && validDate(+m[1], +m[2], +m[3]);
181
+ },
182
+ time: (s) => {
183
+ const m = /^(\d{2}):(\d{2}):(\d{2})(\.\d+)?([Zz]|[+-]\d{2}:\d{2})?$/.exec(s);
184
+ return !!m && +m[1] < 24 && +m[2] < 60 && +m[3] <= 60;
185
+ },
186
+ "date-time": (s) => {
187
+ const m = /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2}):(\d{2})(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/.exec(s);
188
+ return !!m && validDate(+m[1], +m[2], +m[3]) && +m[4] < 24 && +m[5] < 60 && +m[6] <= 60;
189
+ },
190
+ ipv4: (s) => /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(s),
191
+ ipv6: (s) => /^[0-9a-f:.]+$/i.test(s) && s.includes(":") && (s.match(/::/g) || []).length <= 1 && s.split(":").every((p) => p.length <= 4 || p.includes(".")),
192
+ hostname: (s) => s.length <= 253 && /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(\.(?!-)[A-Za-z0-9-]{1,63}(?<!-))*$/.test(s),
193
+ };
194
+
195
+ const FORMAT_NAMES = { email: "email address", "idn-email": "email address", uri: "URI", "uri-reference": "URI reference", url: "URL", uuid: "UUID", date: "date (YYYY-MM-DD)", time: "time (HH:MM:SS)", "date-time": "date-time (RFC 3339)", ipv4: "IPv4 address", ipv6: "IPv6 address", hostname: "hostname" };
196
+
197
+ function show(v) {
198
+ const s = JSON.stringify(v);
199
+ return s.length > 40 ? s.slice(0, 37) + "..." : s;
200
+ }
201
+
202
+ function listTypes(t) {
203
+ const a = Array.isArray(t) ? t : [t];
204
+ return a.length > 1 ? a.slice(0, -1).join(", ") + " or " + a[a.length - 1] : a[0];
205
+ }
206
+
207
+ function decodePointer(seg) {
208
+ return decodeURIComponent(seg).replace(/~1/g, "/").replace(/~0/g, "~");
209
+ }
210
+
211
+ export function resolvePointer(root, ref) {
212
+ if (ref === "#" || ref === "") return root;
213
+ if (!ref.startsWith("#/")) return undefined;
214
+ let node = root;
215
+ for (const raw of ref.slice(2).split("/")) {
216
+ const k = decodePointer(raw);
217
+ if (node === null || typeof node !== "object" || !Object.prototype.hasOwnProperty.call(node, k)) return undefined;
218
+ node = node[k];
219
+ }
220
+ return node;
221
+ }
222
+
223
+ export function validateJson(data, schema) {
224
+ const errors = [];
225
+ if (schema === null || (typeof schema !== "object" && typeof schema !== "boolean")) {
226
+ return [{ path: "$", message: "The schema must be a JSON object or a boolean" }];
227
+ }
228
+ const root = schema;
229
+ const chars = (s) => [...s].length;
230
+
231
+ function check(v, s, path, out, depth) {
232
+ if (s === true || s === undefined) return;
233
+ if (s === false) {
234
+ out.push({ path, message: "No value is allowed here" });
235
+ return;
236
+ }
237
+ if (s === null || typeof s !== "object") return;
238
+ if (depth > 120) {
239
+ out.push({ path, message: "Schema nesting is too deep (a circular $ref?)" });
240
+ return;
241
+ }
242
+ if (typeof s.$ref === "string") {
243
+ const target = resolvePointer(root, s.$ref);
244
+ if (target === undefined) out.push({ path, message: "Can't resolve $ref " + Q1 + s.$ref + Q2 + " (only local refs like #/$defs/name work)" });
245
+ else check(v, target, path, out, depth + 1);
246
+ }
247
+ if (s.type !== undefined) {
248
+ const types = Array.isArray(s.type) ? s.type : [s.type];
249
+ if (!types.some((t) => isType(v, t))) {
250
+ out.push({ path, message: "Expected " + listTypes(types) + ", got " + typeOf(v) });
251
+ return;
252
+ }
253
+ }
254
+ if (s.enum && !s.enum.some((e) => deepEqual(e, v))) out.push({ path, message: "Must be one of " + s.enum.map(show).join(", ") });
255
+ if ("const" in s && !deepEqual(s.const, v)) out.push({ path, message: "Must equal " + show(s.const) });
256
+
257
+ if (typeof v === "number") {
258
+ if (typeof s.minimum === "number") {
259
+ if (s.exclusiveMinimum === true ? v <= s.minimum : v < s.minimum) out.push({ path, message: (s.exclusiveMinimum === true ? "Must be greater than " : "Must be at least ") + s.minimum });
260
+ }
261
+ if (typeof s.maximum === "number") {
262
+ if (s.exclusiveMaximum === true ? v >= s.maximum : v > s.maximum) out.push({ path, message: (s.exclusiveMaximum === true ? "Must be less than " : "Must be at most ") + s.maximum });
263
+ }
264
+ if (typeof s.exclusiveMinimum === "number" && v <= s.exclusiveMinimum) out.push({ path, message: "Must be greater than " + s.exclusiveMinimum });
265
+ if (typeof s.exclusiveMaximum === "number" && v >= s.exclusiveMaximum) out.push({ path, message: "Must be less than " + s.exclusiveMaximum });
266
+ if (typeof s.multipleOf === "number" && s.multipleOf > 0) {
267
+ const q = v / s.multipleOf;
268
+ if (Math.abs(q - Math.round(q)) > 1e-9) out.push({ path, message: "Must be a multiple of " + s.multipleOf });
269
+ }
270
+ }
271
+
272
+ if (typeof v === "string") {
273
+ if (typeof s.minLength === "number" && chars(v) < s.minLength) out.push({ path, message: "Must be at least " + s.minLength + (s.minLength === 1 ? " character" : " characters") + " long" });
274
+ if (typeof s.maxLength === "number" && chars(v) > s.maxLength) out.push({ path, message: "Must be at most " + s.maxLength + (s.maxLength === 1 ? " character" : " characters") + " long" });
275
+ if (typeof s.pattern === "string") {
276
+ let re = null;
277
+ try {
278
+ re = new RegExp(s.pattern, "u");
279
+ } catch (e) {
280
+ out.push({ path, message: "The schema pattern " + Q1 + s.pattern + Q2 + " is not a valid regular expression" });
281
+ }
282
+ if (re && !re.test(v)) out.push({ path, message: "Doesn't match the pattern " + s.pattern });
283
+ }
284
+ if (typeof s.format === "string" && FORMATS[s.format] && !FORMATS[s.format](v)) out.push({ path, message: "Not a valid " + FORMAT_NAMES[s.format] });
285
+ }
286
+
287
+ if (Array.isArray(v)) {
288
+ if (typeof s.minItems === "number" && v.length < s.minItems) out.push({ path, message: "Must have at least " + s.minItems + (s.minItems === 1 ? " item" : " items") });
289
+ if (typeof s.maxItems === "number" && v.length > s.maxItems) out.push({ path, message: "Must have at most " + s.maxItems + (s.maxItems === 1 ? " item" : " items") });
290
+ let start = 0;
291
+ const tuple = Array.isArray(s.prefixItems) ? s.prefixItems : Array.isArray(s.items) ? s.items : null;
292
+ if (tuple) {
293
+ tuple.forEach((sub, i) => {
294
+ if (i < v.length) check(v[i], sub, pathJoin(path, i), out, depth + 1);
295
+ });
296
+ start = tuple.length;
297
+ }
298
+ const rest = Array.isArray(s.items) ? s.additionalItems : s.items;
299
+ if (rest !== undefined && !(Array.isArray(s.items) && Array.isArray(s.prefixItems))) {
300
+ for (let i = start; i < v.length; i++) {
301
+ if (rest === false) {
302
+ out.push({ path: pathJoin(path, i), message: "No more than " + start + (start === 1 ? " item is" : " items are") + " allowed" });
303
+ break;
304
+ }
305
+ check(v[i], rest, pathJoin(path, i), out, depth + 1);
306
+ }
307
+ }
308
+ if (s.uniqueItems === true) {
309
+ outer: for (let i = 0; i < v.length; i++) {
310
+ for (let j = i + 1; j < v.length; j++) {
311
+ if (deepEqual(v[i], v[j])) {
312
+ out.push({ path, message: "Items must be unique, but items " + i + " and " + j + " are equal" });
313
+ break outer;
314
+ }
315
+ }
316
+ }
317
+ }
318
+ if (s.contains !== undefined) {
319
+ const hits = v.filter((x) => {
320
+ const tmp = [];
321
+ check(x, s.contains, path, tmp, depth + 1);
322
+ return !tmp.length;
323
+ }).length;
324
+ const min = typeof s.minContains === "number" ? s.minContains : 1;
325
+ if (hits < min) out.push({ path, message: min === 1 ? "Must contain at least one item that matches the contains schema" : "Must contain at least " + min + " matching items" });
326
+ if (typeof s.maxContains === "number" && hits > s.maxContains) out.push({ path, message: "Must contain at most " + s.maxContains + " matching items" });
327
+ }
328
+ }
329
+
330
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
331
+ const keys = Object.keys(v);
332
+ if (Array.isArray(s.required)) {
333
+ for (const k of s.required) if (!Object.prototype.hasOwnProperty.call(v, k)) out.push({ path, message: "Missing required property " + Q1 + k + Q2 });
334
+ }
335
+ if (typeof s.minProperties === "number" && keys.length < s.minProperties) out.push({ path, message: "Must have at least " + s.minProperties + (s.minProperties === 1 ? " property" : " properties") });
336
+ if (typeof s.maxProperties === "number" && keys.length > s.maxProperties) out.push({ path, message: "Must have at most " + s.maxProperties + (s.maxProperties === 1 ? " property" : " properties") });
337
+ const props = s.properties && typeof s.properties === "object" ? s.properties : {};
338
+ const pats = s.patternProperties && typeof s.patternProperties === "object" ? Object.entries(s.patternProperties).map(([p, sub]) => {
339
+ try {
340
+ return [new RegExp(p, "u"), sub];
341
+ } catch (e) {
342
+ return [null, sub];
343
+ }
344
+ }) : [];
345
+ for (const k of keys) {
346
+ const at = pathJoin(path, k);
347
+ let known = false;
348
+ if (Object.prototype.hasOwnProperty.call(props, k)) {
349
+ known = true;
350
+ check(v[k], props[k], at, out, depth + 1);
351
+ }
352
+ for (const [re, sub] of pats) {
353
+ if (re && re.test(k)) {
354
+ known = true;
355
+ check(v[k], sub, at, out, depth + 1);
356
+ }
357
+ }
358
+ if (!known && s.additionalProperties !== undefined) {
359
+ if (s.additionalProperties === false) out.push({ path: at, message: "Property " + Q1 + k + Q2 + " is not allowed" });
360
+ else check(v[k], s.additionalProperties, at, out, depth + 1);
361
+ }
362
+ if (s.propertyNames !== undefined) {
363
+ const tmp = [];
364
+ check(k, s.propertyNames, at, tmp, depth + 1);
365
+ if (tmp.length) out.push({ path: at, message: "Property name " + Q1 + k + Q2 + " is not allowed: " + tmp[0].message.charAt(0).toLowerCase() + tmp[0].message.slice(1) });
366
+ }
367
+ }
368
+ const deps = s.dependentRequired || (s.dependencies && typeof s.dependencies === "object" ? s.dependencies : null);
369
+ if (deps) {
370
+ for (const [k, need] of Object.entries(deps)) {
371
+ if (!Object.prototype.hasOwnProperty.call(v, k)) continue;
372
+ if (Array.isArray(need)) {
373
+ for (const n of need) if (!Object.prototype.hasOwnProperty.call(v, n)) out.push({ path, message: "Property " + Q1 + k + Q2 + " requires " + Q1 + n + Q2 });
374
+ } else if (need && typeof need === "object") check(v, need, path, out, depth + 1);
375
+ }
376
+ }
377
+ if (s.dependentSchemas) {
378
+ for (const [k, sub] of Object.entries(s.dependentSchemas)) if (Object.prototype.hasOwnProperty.call(v, k)) check(v, sub, path, out, depth + 1);
379
+ }
380
+ }
381
+
382
+ if (Array.isArray(s.allOf)) for (const sub of s.allOf) check(v, sub, path, out, depth + 1);
383
+ if (Array.isArray(s.anyOf)) {
384
+ const tries = s.anyOf.map((sub) => {
385
+ const tmp = [];
386
+ check(v, sub, path, tmp, depth + 1);
387
+ return tmp;
388
+ });
389
+ if (!tries.some((t) => !t.length)) {
390
+ const best = tries.reduce((a, b) => (b.length < a.length ? b : a));
391
+ out.push({ path, message: "Doesn't match any of the anyOf options" + (best.length === 1 && tries.length === 1 ? ": " + best[0].message : "") });
392
+ }
393
+ }
394
+ if (Array.isArray(s.oneOf)) {
395
+ const ok = s.oneOf.filter((sub) => {
396
+ const tmp = [];
397
+ check(v, sub, path, tmp, depth + 1);
398
+ return !tmp.length;
399
+ }).length;
400
+ if (ok === 0) out.push({ path, message: "Doesn't match any of the oneOf options" });
401
+ else if (ok > 1) out.push({ path, message: "Matches " + ok + " of the oneOf options, but exactly one is allowed" });
402
+ }
403
+ if (s.not !== undefined) {
404
+ const tmp = [];
405
+ check(v, s.not, path, tmp, depth + 1);
406
+ if (!tmp.length) out.push({ path, message: "Must not match the schema in not" });
407
+ }
408
+ if (s.if !== undefined) {
409
+ const tmp = [];
410
+ check(v, s.if, path, tmp, depth + 1);
411
+ if (!tmp.length) {
412
+ if (s.then !== undefined) check(v, s.then, path, out, depth + 1);
413
+ } else if (s.else !== undefined) check(v, s.else, path, out, depth + 1);
414
+ }
415
+ }
416
+
417
+ check(data, schema, "$", errors, 0);
418
+ return errors;
419
+ }
420
+
421
+ function parseFilter(src) {
422
+ let i = 0;
423
+ const err = (m) => {
424
+ throw new Error("Filter: " + m);
425
+ };
426
+ const ws = () => {
427
+ while (src[i] === " " || src[i] === "\t") i++;
428
+ };
429
+ function relPath() {
430
+ const segs = [];
431
+ for (;;) {
432
+ if (src[i] === "." && src[i + 1] !== ".") {
433
+ i++;
434
+ const m = /^[A-Za-z_$][\w$-]*/.exec(src.slice(i));
435
+ if (!m) err("expected a name after the dot");
436
+ segs.push(m[0]);
437
+ i += m[0].length;
438
+ } else if (src[i] === "[") {
439
+ i++;
440
+ ws();
441
+ if (src[i] === "'" || src[i] === '"') segs.push(str());
442
+ else {
443
+ const m = /^-?\d+/.exec(src.slice(i));
444
+ if (!m) err("expected an index or quoted name inside [ ]");
445
+ segs.push(+m[0]);
446
+ i += m[0].length;
447
+ }
448
+ ws();
449
+ if (src[i] !== "]") err("expected ]");
450
+ i++;
451
+ } else break;
452
+ }
453
+ return segs;
454
+ }
455
+ function str() {
456
+ const q = src[i++];
457
+ let out = "";
458
+ while (i < src.length && src[i] !== q) {
459
+ if (src[i] === "\\" && i + 1 < src.length) {
460
+ out += src[i + 1];
461
+ i += 2;
462
+ } else out += src[i++];
463
+ }
464
+ if (src[i] !== q) err("unterminated string");
465
+ i++;
466
+ return out;
467
+ }
468
+ function operand() {
469
+ ws();
470
+ const c = src[i];
471
+ if (c === "@" || c === "$") {
472
+ i++;
473
+ return { k: c === "@" ? "cur" : "root", segs: relPath() };
474
+ }
475
+ if (c === "'" || c === '"') return { k: "lit", v: str() };
476
+ if (c === "/") {
477
+ const m = /^\/((?:\\.|[^/\\])+)\/([a-z]*)/.exec(src.slice(i));
478
+ if (!m) err("bad regular expression");
479
+ i += m[0].length;
480
+ try {
481
+ return { k: "lit", v: new RegExp(m[1], m[2]) };
482
+ } catch (e) {
483
+ err("bad regular expression");
484
+ }
485
+ }
486
+ const num = /^-?\d+(\.\d+)?([eE][+-]?\d+)?/.exec(src.slice(i));
487
+ if (num) {
488
+ i += num[0].length;
489
+ return { k: "lit", v: +num[0] };
490
+ }
491
+ for (const [w, v] of [["true", true], ["false", false], ["null", null]]) {
492
+ if (src.startsWith(w, i)) {
493
+ i += w.length;
494
+ return { k: "lit", v };
495
+ }
496
+ }
497
+ err("unexpected " + (i < src.length ? Q1 + src[i] + Q2 : "end of filter"));
498
+ }
499
+ function comparison() {
500
+ const left = operand();
501
+ ws();
502
+ const m = /^(==|!=|<=|>=|<|>|=~)/.exec(src.slice(i));
503
+ if (!m) return { k: "exists", left };
504
+ i += m[0].length;
505
+ const right = operand();
506
+ return { k: "cmp", op: m[0], left, right };
507
+ }
508
+ function unary() {
509
+ ws();
510
+ if (src[i] === "!" && src[i + 1] !== "=") {
511
+ i++;
512
+ return { k: "not", a: unary() };
513
+ }
514
+ if (src[i] === "(") {
515
+ i++;
516
+ const e = or();
517
+ ws();
518
+ if (src[i] !== ")") err("missing )");
519
+ i++;
520
+ return e;
521
+ }
522
+ return comparison();
523
+ }
524
+ function and() {
525
+ let a = unary();
526
+ for (;;) {
527
+ ws();
528
+ if (!src.startsWith("&&", i)) return a;
529
+ i += 2;
530
+ a = { k: "and", a, b: unary() };
531
+ }
532
+ }
533
+ function or() {
534
+ let a = and();
535
+ for (;;) {
536
+ ws();
537
+ if (!src.startsWith("||", i)) return a;
538
+ i += 2;
539
+ a = { k: "or", a, b: and() };
540
+ }
541
+ }
542
+ const tree = or();
543
+ ws();
544
+ if (i < src.length) err("unexpected " + Q1 + src.slice(i, i + 10) + Q2);
545
+ return tree;
546
+ }
547
+
548
+ const MISSING = Symbol("missing");
549
+
550
+ function walkRel(v, segs) {
551
+ for (const s of segs) {
552
+ if (v === null || typeof v !== "object") {
553
+ if (s === "length" && typeof v === "string") {
554
+ v = v.length;
555
+ continue;
556
+ }
557
+ return MISSING;
558
+ }
559
+ if (Array.isArray(v)) {
560
+ if (s === "length") v = v.length;
561
+ else if (typeof s === "number") {
562
+ const idx = s < 0 ? v.length + s : s;
563
+ if (idx < 0 || idx >= v.length) return MISSING;
564
+ v = v[idx];
565
+ } else return MISSING;
566
+ } else {
567
+ if (!Object.prototype.hasOwnProperty.call(v, s)) return MISSING;
568
+ v = v[s];
569
+ }
570
+ }
571
+ return v;
572
+ }
573
+
574
+ function evalFilter(t, cur, root) {
575
+ const val = (o) => (o.k === "lit" ? o.v : walkRel(o.k === "cur" ? cur : root, o.segs));
576
+ switch (t.k) {
577
+ case "exists": {
578
+ const v = val(t.left);
579
+ return t.left.k === "lit" ? !!v : v !== MISSING;
580
+ }
581
+ case "not":
582
+ return !evalFilter(t.a, cur, root);
583
+ case "and":
584
+ return evalFilter(t.a, cur, root) && evalFilter(t.b, cur, root);
585
+ case "or":
586
+ return evalFilter(t.a, cur, root) || evalFilter(t.b, cur, root);
587
+ case "cmp": {
588
+ const a = val(t.left);
589
+ const b = val(t.right);
590
+ if (t.op === "=~") return a !== MISSING && b instanceof RegExp && typeof a === "string" && b.test(a);
591
+ if (t.op === "==") return a !== MISSING && b !== MISSING && deepEqual(a, b);
592
+ if (t.op === "!=") return !(a !== MISSING && b !== MISSING && deepEqual(a, b));
593
+ if (a === MISSING || b === MISSING) return false;
594
+ if (!((typeof a === "number" && typeof b === "number") || (typeof a === "string" && typeof b === "string"))) return false;
595
+ if (t.op === "<") return a < b;
596
+ if (t.op === "<=") return a <= b;
597
+ if (t.op === ">") return a > b;
598
+ return a >= b;
599
+ }
600
+ }
601
+ return false;
602
+ }
603
+
604
+ function findClose(expr, i) {
605
+ let depth = 0;
606
+ let q = null;
607
+ for (; i < expr.length; i++) {
608
+ const c = expr[i];
609
+ if (q) {
610
+ if (c === "\\") i++;
611
+ else if (c === q) q = null;
612
+ continue;
613
+ }
614
+ if (c === "'" || c === '"') q = c;
615
+ else if (c === "[" || c === "(") depth++;
616
+ else if (c === ")") depth--;
617
+ else if (c === "]") {
618
+ if (depth === 0) return i;
619
+ depth--;
620
+ }
621
+ }
622
+ return -1;
623
+ }
624
+
625
+ export function parseJsonPath(input) {
626
+ let expr = String(input).trim();
627
+ if (!expr) throw new Error("Type a path such as $.store.book[*].title");
628
+ if (expr[0] !== "$") expr = expr[0] === "." || expr[0] === "[" ? "$" + expr : "$." + expr;
629
+ const segs = [];
630
+ let i = 1;
631
+ const nameAt = () => {
632
+ const m = /^[A-Za-z_$\u00C0-\uFFFF][\w$\u00C0-\uFFFF-]*/.exec(expr.slice(i));
633
+ return m ? m[0] : null;
634
+ };
635
+ while (i < expr.length) {
636
+ const c = expr[i];
637
+ if (c === " ") {
638
+ i++;
639
+ continue;
640
+ }
641
+ let desc = false;
642
+ if (expr.startsWith("..", i)) {
643
+ desc = true;
644
+ i += 2;
645
+ } else if (c === ".") i++;
646
+ else if (c !== "[") throw new Error("Unexpected " + Q1 + c + Q2 + " at position " + (i + 1));
647
+ if (expr[i] === "[") {
648
+ const end = findClose(expr, i + 1);
649
+ if (end < 0) throw new Error("Missing ] for the bracket at position " + (i + 1));
650
+ segs.push({ desc, sel: parseBracket(expr.slice(i + 1, end), i + 2) });
651
+ i = end + 1;
652
+ } else if (expr[i] === "*") {
653
+ segs.push({ desc, sel: [{ k: "wild" }] });
654
+ i++;
655
+ } else {
656
+ const n = nameAt();
657
+ if (!n) throw new Error("Expected a name or * at position " + (i + 1));
658
+ segs.push({ desc, sel: [{ k: "name", v: n }] });
659
+ i += n.length;
660
+ }
661
+ }
662
+ return segs;
663
+ }
664
+
665
+ function parseBracket(body, at) {
666
+ const parts = [];
667
+ let i = 0;
668
+ const b = body;
669
+ while (i < b.length) {
670
+ while (b[i] === " ") i++;
671
+ if (b[i] === "?") {
672
+ i++;
673
+ while (b[i] === " ") i++;
674
+ let src = b.slice(i).trim();
675
+ if (src.startsWith("(")) {
676
+ let depth = 0;
677
+ let end = -1;
678
+ let q = null;
679
+ for (let j = 0; j < src.length; j++) {
680
+ const c = src[j];
681
+ if (q) {
682
+ if (c === "\\") j++;
683
+ else if (c === q) q = null;
684
+ continue;
685
+ }
686
+ if (c === "'" || c === '"') q = c;
687
+ else if (c === "(") depth++;
688
+ else if (c === ")" && --depth === 0) {
689
+ end = j;
690
+ break;
691
+ }
692
+ }
693
+ if (end === src.length - 1) src = src.slice(1, -1);
694
+ }
695
+ parts.push({ k: "filter", tree: parseFilter(src) });
696
+ return parts;
697
+ }
698
+ if (b[i] === "'" || b[i] === '"') {
699
+ const q = b[i++];
700
+ let s = "";
701
+ while (i < b.length && b[i] !== q) {
702
+ if (b[i] === "\\") {
703
+ s += b[i + 1];
704
+ i += 2;
705
+ } else s += b[i++];
706
+ }
707
+ if (b[i] !== q) throw new Error("Unterminated string inside [ ] at position " + at);
708
+ i++;
709
+ parts.push({ k: "name", v: s });
710
+ } else if (b[i] === "*") {
711
+ parts.push({ k: "wild" });
712
+ i++;
713
+ } else {
714
+ const m = /^(-?\d*)\s*(?::\s*(-?\d*)\s*(?::\s*(-?\d*))?)?/.exec(b.slice(i));
715
+ if (!m || !m[0].trim()) throw new Error("Can't read " + Q1 + b.slice(i) + Q2 + " inside [ ]");
716
+ if (m[0].includes(":")) {
717
+ parts.push({ k: "slice", start: m[1] === "" ? null : +m[1], end: m[2] === "" || m[2] === undefined ? null : +m[2], step: m[3] === "" || m[3] === undefined ? 1 : +m[3] });
718
+ } else parts.push({ k: "index", v: +m[1] });
719
+ i += m[0].length;
720
+ }
721
+ while (b[i] === " ") i++;
722
+ if (i < b.length) {
723
+ if (b[i] !== ",") throw new Error("Expected , between items inside [ ]");
724
+ i++;
725
+ }
726
+ }
727
+ if (!parts.length) throw new Error("Empty [ ] at position " + at);
728
+ return parts;
729
+ }
730
+
731
+ function children(node) {
732
+ const v = node.value;
733
+ if (Array.isArray(v)) return v.map((x, i) => ({ path: pathJoin(node.path, i), value: x }));
734
+ if (v !== null && typeof v === "object") return Object.keys(v).map((k) => ({ path: pathJoin(node.path, k), value: v[k] }));
735
+ return [];
736
+ }
737
+
738
+ function applySel(node, sel, root, out) {
739
+ const v = node.value;
740
+ if (sel.k === "wild") {
741
+ out.push(...children(node));
742
+ } else if (sel.k === "name") {
743
+ if (v !== null && typeof v === "object" && !Array.isArray(v) && Object.prototype.hasOwnProperty.call(v, sel.v)) out.push({ path: pathJoin(node.path, sel.v), value: v[sel.v] });
744
+ else if (Array.isArray(v) && sel.v === "length") out.push({ path: node.path + ".length", value: v.length });
745
+ } else if (sel.k === "index") {
746
+ if (Array.isArray(v)) {
747
+ const idx = sel.v < 0 ? v.length + sel.v : sel.v;
748
+ if (idx >= 0 && idx < v.length) out.push({ path: pathJoin(node.path, idx), value: v[idx] });
749
+ }
750
+ } else if (sel.k === "slice") {
751
+ if (!Array.isArray(v) || sel.step === 0) return;
752
+ const n = v.length;
753
+ const norm = (x, d) => (x === null ? d : x < 0 ? Math.max(n + x, sel.step > 0 ? 0 : -1) : Math.min(x, n));
754
+ if (sel.step > 0) {
755
+ for (let i = norm(sel.start, 0); i < norm(sel.end, n); i += sel.step) out.push({ path: pathJoin(node.path, i), value: v[i] });
756
+ } else {
757
+ for (let i = sel.start === null ? n - 1 : Math.min(norm(sel.start, n - 1), n - 1); i > (sel.end === null ? -1 : norm(sel.end, -1)); i += sel.step) out.push({ path: pathJoin(node.path, i), value: v[i] });
758
+ }
759
+ } else if (sel.k === "filter") {
760
+ for (const c of children(node)) if (evalFilter(sel.tree, c.value, root)) out.push(c);
761
+ }
762
+ }
763
+
764
+ export function queryJsonPath(data, expr, limit = 100000) {
765
+ const segs = parseJsonPath(expr);
766
+ let nodes = [{ path: "$", value: data }];
767
+ for (const seg of segs) {
768
+ let pool = nodes;
769
+ if (seg.desc) {
770
+ pool = [];
771
+ const stack = [...nodes].reverse();
772
+ while (stack.length) {
773
+ const n = stack.pop();
774
+ pool.push(n);
775
+ if (pool.length > limit) throw new Error("Too many matches to show");
776
+ const kids = children(n);
777
+ for (let k = kids.length - 1; k >= 0; k--) stack.push(kids[k]);
778
+ }
779
+ }
780
+ const next = [];
781
+ for (const n of pool) for (const sel of seg.sel) applySel(n, sel, data, next);
782
+ if (next.length > limit) throw new Error("Too many matches to show");
783
+ nodes = next;
784
+ }
785
+ return nodes;
786
+ }
787
+
788
+ function hashSeed(s) {
789
+ const str = String(s);
790
+ let h = 1779033703 ^ str.length;
791
+ for (let i = 0; i < str.length; i++) {
792
+ h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
793
+ h = (h << 13) | (h >>> 19);
794
+ }
795
+ h = Math.imul(h ^ (h >>> 16), 2246822507);
796
+ h = Math.imul(h ^ (h >>> 13), 3266489909);
797
+ return (h ^ (h >>> 16)) >>> 0;
798
+ }
799
+
800
+ export function makeRng(seed) {
801
+ let a = hashSeed(seed);
802
+ const next = () => {
803
+ a = (a + 0x6d2b79f5) | 0;
804
+ let t = Math.imul(a ^ (a >>> 15), 1 | a);
805
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
806
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
807
+ };
808
+ const int = (lo, hi) => lo + Math.floor(next() * (hi - lo + 1));
809
+ const pick = (arr) => arr[Math.floor(next() * arr.length)];
810
+ return { next, int, pick };
811
+ }
812
+
813
+ const FIRST = ["Olivia", "Liam", "Amara", "Noah", "Sofia", "Mateo", "Priya", "Lucas", "Yuki", "Ethan", "Zara", "Omar", "Chloe", "Diego", "Hannah", "Kenji", "Isla", "Arjun", "Maya", "Leo", "Fatima", "Jonas", "Elena", "Samuel", "Aisha", "Felix", "Grace", "Ravi", "Nora", "Hugo", "Lina", "Theo", "Mei", "Oscar", "Ines", "Kwame", "Freya", "Tomas", "Leila", "Daniel"];
814
+ const LAST = ["Nguyen", "Garcia", "Smith", "Kowalski", "Okafor", "Silva", "Tanaka", "Martin", "Patel", "Johansson", "Rossi", "Kim", "Murphy", "Dubois", "Haddad", "Novak", "Fischer", "Lopez", "Brown", "Mensah", "Cohen", "Sato", "Andersen", "Moreau", "Ivanova", "Walker", "Costa", "Reyes", "Schmidt", "Ali", "Bennett", "Larsen", "Chen", "Hughes", "Ortiz", "Baker", "Yilmaz", "Clarke", "Sousa", "Wright"];
815
+ const CITIES = [["Lisbon", "Portugal", "PT"], ["Toronto", "Canada", "CA"], ["Osaka", "Japan", "JP"], ["Austin", "United States", "US"], ["Lyon", "France", "FR"], ["Melbourne", "Australia", "AU"], ["Nairobi", "Kenya", "KE"], ["Hamburg", "Germany", "DE"], ["Bogota", "Colombia", "CO"], ["Dublin", "Ireland", "IE"], ["Seoul", "South Korea", "KR"], ["Krakow", "Poland", "PL"], ["Porto Alegre", "Brazil", "BR"], ["Manchester", "United Kingdom", "GB"], ["Pune", "India", "IN"], ["Oslo", "Norway", "NO"], ["Valencia", "Spain", "ES"], ["Denver", "United States", "US"], ["Auckland", "New Zealand", "NZ"], ["Accra", "Ghana", "GH"]];
816
+ const STREETS = ["Maple Street", "Harbor Road", "Oak Avenue", "Station Lane", "Mill Road", "Cedar Drive", "Park Terrace", "River Walk", "Elm Court", "Hillside Way", "Bridge Street", "Garden Row"];
817
+ const COMPANY_A = ["North", "Blue", "Bright", "Copper", "Silver", "Green", "Summit", "Harbor", "Pine", "Atlas", "Lumen", "Cobalt", "Willow", "Granite", "Swift"];
818
+ const COMPANY_B = ["Labs", "Works", "Systems", "Studio", "Logistics", "Foods", "Health", "Analytics", "Supply", "Media", "Energy", "Partners", "Robotics", "Goods", "Cloud"];
819
+ const JOBS = ["Software Engineer", "Product Manager", "Data Analyst", "Designer", "Account Manager", "Support Specialist", "Marketing Lead", "Operations Manager", "QA Engineer", "Sales Representative", "Nurse", "Teacher", "Accountant", "Copywriter", "DevOps Engineer"];
820
+ const WORDS = ["quick", "simple", "fresh", "quiet", "bright", "solid", "handy", "light", "smart", "steady", "modern", "classic", "warm", "clear", "bold", "compact", "daily", "honest", "local", "gentle"];
821
+ const NOUNS = ["lamp", "notebook", "backpack", "kettle", "chair", "bottle", "jacket", "speaker", "planner", "mug", "blanket", "charger", "desk", "garden kit", "headphones", "bike light", "cookbook", "sneakers", "wallet", "tea set"];
822
+ const SENT = ["the", "team", "shipped", "a", "new", "update", "for", "our", "customers", "every", "order", "arrives", "on", "time", "with", "care", "and", "clear", "notes", "about", "next", "steps", "this", "week", "we", "plan", "to", "improve", "search", "results", "users", "love", "fast", "pages", "simple", "tools", "that", "just", "work", "today"];
823
+ const STATUS = ["active", "pending", "inactive", "archived"];
824
+ const CURRENCIES = ["USD", "EUR", "GBP", "CAD", "JPY", "AUD"];
825
+ const TAGS = ["new", "sale", "popular", "eco", "limited", "gift", "featured", "bundle"];
826
+ const LANGS = ["en", "fr", "es", "de", "pt", "ja", "it", "nl"];
827
+ const DOMAINS = ["example.com", "example.org", "example.net"];
828
+
829
+ function slugify(s) {
830
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
831
+ }
832
+
833
+ function pad(n, w = 2) {
834
+ return String(n).padStart(w, "0");
835
+ }
836
+
837
+ function uuid(r) {
838
+ const h = (n) => Array.from({ length: n }, () => r.int(0, 15).toString(16)).join("");
839
+ return h(8) + "-" + h(4) + "-4" + h(3) + "-" + "89ab"[r.int(0, 3)] + h(3) + "-" + h(12);
840
+ }
841
+
842
+ function dateParts(r) {
843
+ const t = Date.UTC(2019, 0, 1) + Math.floor(r.next() * (Date.UTC(2026, 9, 1) - Date.UTC(2019, 0, 1)));
844
+ return new Date(t);
845
+ }
846
+
847
+ function isoDate(d) {
848
+ return d.getUTCFullYear() + "-" + pad(d.getUTCMonth() + 1) + "-" + pad(d.getUTCDate());
849
+ }
850
+
851
+ function isoDateTime(d) {
852
+ return isoDate(d) + "T" + pad(d.getUTCHours()) + ":" + pad(d.getUTCMinutes()) + ":" + pad(d.getUTCSeconds()) + "Z";
853
+ }
854
+
855
+ function sentence(r, min = 6, max = 12) {
856
+ const n = r.int(min, max);
857
+ const w = Array.from({ length: n }, () => r.pick(SENT));
858
+ const s = w.join(" ");
859
+ return s.charAt(0).toUpperCase() + s.slice(1) + ".";
860
+ }
861
+
862
+ function person(ctx) {
863
+ if (!ctx.person) {
864
+ const r = ctx.r;
865
+ const first = r.pick(FIRST);
866
+ const last = r.pick(LAST);
867
+ const place = r.pick(CITIES);
868
+ ctx.person = { first, last, place, handle: (first + "." + last).toLowerCase() + (r.next() < 0.5 ? r.int(1, 99) : "") };
869
+ }
870
+ return ctx.person;
871
+ }
872
+
873
+ function norm(key) {
874
+ return String(key || "").toLowerCase().replace(/[^a-z0-9]/g, "");
875
+ }
876
+
877
+ function isIdKey(key) {
878
+ const k = String(key || "");
879
+ return /^id$/i.test(k) || /[_-]id$/i.test(k) || /[a-z0-9](Id|ID)$/.test(k);
880
+ }
881
+
882
+ const NUMBER_KEYS = /^age$|(user|person|customer|patient|member)age$|rating|stars|score|percent|progress|year|month|day|hour|minute|second|qty|quantity|count|stock|units|salary|income|price|amount|cost|total|balance|fee|^lat|latitude|^lng|^lon|longitude|weight|discount/;
883
+
884
+ function stringFor(key, format, ctx) {
885
+ const r = ctx.r;
886
+ const k = norm(key);
887
+ const f = format || "";
888
+ if (f === "email" || f === "idn-email" || /email/.test(k)) {
889
+ const p = person(ctx);
890
+ return p.handle + "@" + DOMAINS[(p.first.length + p.last.length) % DOMAINS.length];
891
+ }
892
+ if (f === "uuid" || /uuid|guid/.test(k)) return uuid(r);
893
+ if (f === "date-time") return isoDateTime(dateParts(r));
894
+ if (f === "date") return isoDate(dateParts(r));
895
+ if (f === "time") return pad(r.int(0, 23)) + ":" + pad(r.int(0, 59)) + ":" + pad(r.int(0, 59));
896
+ if (f === "ipv4" || k === "ip" || /ipaddress|ipv4/.test(k)) return r.pick(["192.0.2.", "198.51.100.", "203.0.113."]) + r.int(1, 254);
897
+ if (f === "ipv6") return "2001:db8::" + r.int(1, 65535).toString(16);
898
+ if (f === "hostname" || /hostname|domain/.test(k)) return slugify(r.pick(COMPANY_A) + r.pick(COMPANY_B)) + "." + r.pick(DOMAINS);
899
+ if (/avatar|image|photo|picture|thumbnail/.test(k)) return "https://" + r.pick(DOMAINS) + "/images/" + r.int(1000, 9999) + ".jpg";
900
+ if (f === "uri" || f === "url" || f === "uri-reference" || /url|website|homepage|link|href/.test(k)) return "https://" + r.pick(DOMAINS) + "/" + slugify(r.pick(WORDS) + " " + r.pick(NOUNS));
901
+ if (/^(createdat|updatedat|deletedat|modifiedat|publishedat|timestamp|lastlogin|lastseen)$/.test(k) || (/(at|time|timestamp)$/.test(k) && !/(format|seat|cat|lat|flat|chat|boat|stat|heat|beat|threat)$/.test(k))) return isoDateTime(dateParts(r));
902
+ if (/date|birthday|dob|since|expires|expiry|duedate/.test(k)) return isoDate(dateParts(r));
903
+ if (/^(id|key|ref|reference|sku|code)$/.test(k) || isIdKey(key)) {
904
+ if (/sku|code/.test(k)) return r.pick(["A", "B", "C", "K", "M", "T"]) + r.pick(["X", "R", "L", "P"]) + "-" + r.int(1000, 9999);
905
+ return uuid(r);
906
+ }
907
+ if (/firstname|givenname|forename/.test(k)) return person(ctx).first;
908
+ if (/lastname|surname|familyname/.test(k)) return person(ctx).last;
909
+ if (/username|login|handle|nickname/.test(k)) return person(ctx).handle;
910
+ if (/^(name|fullname|displayname|customer|customername|author|owner|contact|contactname|user)$/.test(k)) {
911
+ const p = person(ctx);
912
+ return p.first + " " + p.last;
913
+ }
914
+ if (/phone|mobile|tel|fax/.test(k)) return "+1 555-01" + pad(r.int(0, 99));
915
+ if (/countrycode/.test(k)) return person(ctx).place[2];
916
+ if (/country|nation/.test(k)) return person(ctx).place[1];
917
+ if (/city|town/.test(k)) return person(ctx).place[0];
918
+ if (/zip|postcode|postalcode/.test(k)) return String(r.int(10000, 99999));
919
+ if (/address|street/.test(k)) return r.int(1, 999) + " " + r.pick(STREETS);
920
+ if (/company|organization|organisation|employer|business|brand|vendor|supplier/.test(k)) return r.pick(COMPANY_A) + " " + r.pick(COMPANY_B);
921
+ if (/jobtitle|role|position|occupation|job/.test(k)) return r.pick(JOBS);
922
+ if (/product|item|title|subject|headline/.test(k)) {
923
+ const s = r.pick(WORDS) + " " + r.pick(NOUNS);
924
+ return s.charAt(0).toUpperCase() + s.slice(1);
925
+ }
926
+ if (/slug/.test(k)) return slugify(r.pick(WORDS) + " " + r.pick(NOUNS));
927
+ if (/description|bio|summary|notes?|comment|body|message|content|text|about|details/.test(k)) return sentence(r);
928
+ if (/colou?r/.test(k)) return "#" + r.int(0, 0xffffff).toString(16).padStart(6, "0");
929
+ if (/currency/.test(k)) return r.pick(CURRENCIES);
930
+ if (/status|state/.test(k)) return r.pick(STATUS);
931
+ if (/lang|locale/.test(k)) return r.pick(LANGS);
932
+ if (/tag|category|label|type|kind/.test(k)) return r.pick(TAGS);
933
+ if (/password|secret|token/.test(k)) return Array.from({ length: 16 }, () => "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"[r.int(0, 55)]).join("");
934
+ return null;
935
+ }
936
+
937
+ function numberFor(key, ctx, integer, lo, hi) {
938
+ const r = ctx.r;
939
+ const k = norm(key);
940
+ let min = lo;
941
+ let max = hi;
942
+ let dec = integer ? 0 : 2;
943
+ if (min === undefined || max === undefined) {
944
+ let dmin = 0;
945
+ let dmax = 1000;
946
+ if (isIdKey(key) && integer) return ctx.index + 1;
947
+ if (/^age$|(user|person|customer|patient|member)age$/.test(k)) [dmin, dmax] = [18, 80];
948
+ else if (/rating|stars/.test(k)) [dmin, dmax, dec] = integer ? [1, 5, 0] : [1, 5, 1];
949
+ else if (/score|percent|progress/.test(k)) [dmin, dmax] = [0, 100];
950
+ else if (/year/.test(k)) [dmin, dmax] = [1990, 2026];
951
+ else if (/month/.test(k)) [dmin, dmax] = [1, 12];
952
+ else if (/day/.test(k)) [dmin, dmax] = [1, 28];
953
+ else if (/hour/.test(k)) [dmin, dmax] = [0, 23];
954
+ else if (/minute|second/.test(k)) [dmin, dmax] = [0, 59];
955
+ else if (/qty|quantity|count|stock|items|units/.test(k)) [dmin, dmax] = [1, 50];
956
+ else if (/salary|income/.test(k)) [dmin, dmax] = [32000, 180000];
957
+ else if (/price|amount|cost|total|balance|fee|subtotal/.test(k)) [dmin, dmax] = [1, 500];
958
+ else if (/lat/.test(k)) [dmin, dmax, dec] = [-60, 70, 5];
959
+ else if (/lng|lon/.test(k)) [dmin, dmax, dec] = [-170, 170, 5];
960
+ else if (/weight/.test(k)) [dmin, dmax] = [1, 120];
961
+ else if (/discount/.test(k)) [dmin, dmax] = [0, 50];
962
+ if (min === undefined && max === undefined) {
963
+ min = dmin;
964
+ max = dmax;
965
+ } else if (min === undefined) min = Math.min(dmin, max);
966
+ else max = Math.max(dmax, min);
967
+ if (max < min) max = min;
968
+ }
969
+ if (integer) return r.int(Math.ceil(min), Math.floor(max));
970
+ const f = Math.pow(10, dec);
971
+ return Math.min(max, Math.max(min, Math.round((min + r.next() * (max - min)) * f) / f));
972
+ }
973
+
974
+ function boolFor(key, ctx) {
975
+ const k = norm(key);
976
+ const p = /deleted|archived|banned|blocked|disabled/.test(k) ? 0.15 : /active|enabled|verified|available|instock|published/.test(k) ? 0.8 : 0.5;
977
+ return ctx.r.next() < p;
978
+ }
979
+
980
+ function fromPattern(pattern, r) {
981
+ let src = pattern.replace(/^\^/, "").replace(/\$$/, "");
982
+ let out = "";
983
+ let i = 0;
984
+ const classes = { d: "0123456789", w: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", s: " " };
985
+ while (i < src.length) {
986
+ let set = null;
987
+ const c = src[i];
988
+ if (c === "[") {
989
+ const end = src.indexOf("]", i + 1);
990
+ if (end < 0) return null;
991
+ const body = src.slice(i + 1, end);
992
+ if (body.startsWith("^")) return null;
993
+ set = "";
994
+ for (let j = 0; j < body.length; j++) {
995
+ if (body[j] === "\\" && classes[body[j + 1]]) {
996
+ set += classes[body[j + 1]];
997
+ j++;
998
+ } else if (body[j + 1] === "-" && j + 2 < body.length) {
999
+ for (let x = body.charCodeAt(j); x <= body.charCodeAt(j + 2); x++) set += String.fromCharCode(x);
1000
+ j += 2;
1001
+ } else set += body[j];
1002
+ }
1003
+ i = end + 1;
1004
+ } else if (c === "\\") {
1005
+ const n = src[i + 1];
1006
+ set = classes[n] || n;
1007
+ i += 2;
1008
+ } else if (c === "(" || c === ")" || c === "|" || c === "*" || c === "+" || c === "?" || c === "{") {
1009
+ return null;
1010
+ } else if (c === ".") {
1011
+ set = classes.w;
1012
+ i++;
1013
+ } else {
1014
+ set = c;
1015
+ i++;
1016
+ }
1017
+ let lo = 1;
1018
+ let hi = 1;
1019
+ const q = /^(\{(\d+)(,(\d*))?\}|\?|\+|\*)/.exec(src.slice(i));
1020
+ if (q) {
1021
+ if (q[0] === "?") [lo, hi] = [0, 1];
1022
+ else if (q[0] === "+") [lo, hi] = [1, 4];
1023
+ else if (q[0] === "*") [lo, hi] = [0, 4];
1024
+ else {
1025
+ lo = +q[2];
1026
+ hi = q[3] === undefined ? lo : q[4] === "" ? lo + 4 : +q[4];
1027
+ }
1028
+ i += q[0].length;
1029
+ }
1030
+ const n = r.int(lo, Math.min(hi, lo + 50));
1031
+ for (let k = 0; k < n; k++) out += set.length === 1 ? set : set[r.int(0, set.length - 1)];
1032
+ }
1033
+ try {
1034
+ return new RegExp(pattern, "u").test(out) ? out : null;
1035
+ } catch (e) {
1036
+ return null;
1037
+ }
1038
+ }
1039
+
1040
+ function mergeAllOf(s, root) {
1041
+ const out = { ...s };
1042
+ delete out.allOf;
1043
+ for (let sub of s.allOf) {
1044
+ if (sub && sub.$ref) sub = resolvePointer(root, sub.$ref) || {};
1045
+ if (!sub || typeof sub !== "object") continue;
1046
+ for (const [k, v] of Object.entries(sub)) {
1047
+ if (k === "properties") out.properties = { ...(out.properties || {}), ...v };
1048
+ else if (k === "required") out.required = [...new Set([...(out.required || []), ...v])];
1049
+ else if (!(k in out)) out[k] = v;
1050
+ }
1051
+ }
1052
+ return out;
1053
+ }
1054
+
1055
+ function guessType(s) {
1056
+ if (s.type) return Array.isArray(s.type) ? s.type.find((t) => t !== "null") || "null" : s.type;
1057
+ if (s.properties || s.additionalProperties || s.required) return "object";
1058
+ if (s.items || s.prefixItems) return "array";
1059
+ if (s.minimum !== undefined || s.maximum !== undefined || s.multipleOf !== undefined) return "number";
1060
+ if (s.minLength !== undefined || s.pattern || s.format) return "string";
1061
+ return "string";
1062
+ }
1063
+
1064
+ function genSchema(s, key, ctx, depth) {
1065
+ const r = ctx.r;
1066
+ if (s === true || s === undefined || s === null) return stringFor(key, "", ctx) ?? r.pick(WORDS);
1067
+ if (s === false) return null;
1068
+ if (depth > 12) return null;
1069
+ if (s.$ref) {
1070
+ const t = resolvePointer(ctx.root, s.$ref);
1071
+ if (t === undefined) throw new Error("Can't resolve $ref " + Q1 + s.$ref + Q2 + " (only local refs like #/$defs/name work)");
1072
+ const rest = { ...s };
1073
+ delete rest.$ref;
1074
+ return genSchema(Object.keys(rest).length ? { ...t, ...rest } : t, key, ctx, depth + 1);
1075
+ }
1076
+ if (s.allOf) return genSchema(mergeAllOf(s, ctx.root), key, ctx, depth + 1);
1077
+ if ("const" in s) return s.const;
1078
+ if (Array.isArray(s.enum) && s.enum.length) return r.pick(s.enum);
1079
+ if (Array.isArray(s.examples) && s.examples.length && r.next() < 0.3) return r.pick(s.examples);
1080
+ const alts = s.oneOf || s.anyOf;
1081
+ if (Array.isArray(alts) && alts.length) {
1082
+ const base = { ...s };
1083
+ delete base.oneOf;
1084
+ delete base.anyOf;
1085
+ const pick = r.pick(alts);
1086
+ return genSchema(pick && typeof pick === "object" ? { ...base, ...pick } : pick, key, ctx, depth + 1);
1087
+ }
1088
+ const type = guessType(s);
1089
+ if (type === "null") return null;
1090
+ if (type === "boolean") return boolFor(key, ctx);
1091
+ if (type === "integer" || type === "number") {
1092
+ let lo = typeof s.minimum === "number" ? s.minimum : typeof s.exclusiveMinimum === "number" ? s.exclusiveMinimum + (type === "integer" ? 1 : 0.01) : undefined;
1093
+ let hi = typeof s.maximum === "number" ? s.maximum : typeof s.exclusiveMaximum === "number" ? s.exclusiveMaximum - (type === "integer" ? 1 : 0.01) : undefined;
1094
+ let v = numberFor(key, ctx, type === "integer", lo, hi);
1095
+ if (typeof s.multipleOf === "number" && s.multipleOf > 0) {
1096
+ v = Math.round(v / s.multipleOf) * s.multipleOf;
1097
+ if (hi !== undefined && v > hi) v -= s.multipleOf;
1098
+ if (lo !== undefined && v < lo) v += s.multipleOf;
1099
+ v = +v.toFixed(10);
1100
+ }
1101
+ return v;
1102
+ }
1103
+ if (type === "array") {
1104
+ const min = typeof s.minItems === "number" ? s.minItems : 1;
1105
+ const max = typeof s.maxItems === "number" ? s.maxItems : Math.max(min, 3);
1106
+ const n = r.int(min, Math.max(min, Math.min(max, min + 4)));
1107
+ const tuple = s.prefixItems || (Array.isArray(s.items) ? s.items : null);
1108
+ const item = Array.isArray(s.items) ? s.additionalItems : s.items;
1109
+ const out = [];
1110
+ const singular = String(key || "").replace(/(ies)$/, "y").replace(/s$/, "");
1111
+ let guard = 0;
1112
+ while (out.length < (tuple ? Math.max(n, tuple.length) : n) && guard++ < n * 10) {
1113
+ const i = out.length;
1114
+ const sub = tuple && i < tuple.length ? tuple[i] : item;
1115
+ if (tuple && i >= tuple.length && (item === undefined || item === false)) break;
1116
+ const v = genSchema(sub === undefined ? { type: "string" } : sub, singular, { ...ctx, person: null, index: i }, depth + 1);
1117
+ if (s.uniqueItems && out.some((x) => deepEqual(x, v))) continue;
1118
+ out.push(v);
1119
+ }
1120
+ return out;
1121
+ }
1122
+ if (type === "object") {
1123
+ const out = {};
1124
+ const props = s.properties || {};
1125
+ const req = new Set(s.required || []);
1126
+ for (const [k, sub] of Object.entries(props)) {
1127
+ if (!req.has(k) && ctx.optional === "some" && r.next() < 0.2) continue;
1128
+ out[k] = genSchema(sub, k, ctx, depth + 1);
1129
+ }
1130
+ for (const k of req) if (!(k in out)) out[k] = genSchema(true, k, ctx, depth + 1);
1131
+ return out;
1132
+ }
1133
+ if (typeof s.pattern === "string") {
1134
+ const v = fromPattern(s.pattern, r);
1135
+ if (v !== null) return v;
1136
+ }
1137
+ let v = stringFor(key, s.format, ctx);
1138
+ if (v === null) v = s.maxLength !== undefined && s.maxLength < 12 ? r.pick(WORDS) : r.pick(WORDS) + " " + r.pick(NOUNS);
1139
+ if (typeof s.maxLength === "number" && v.length > s.maxLength) v = v.slice(0, s.maxLength);
1140
+ if (typeof s.minLength === "number") while (v.length < s.minLength) v += r.pick(SENT).slice(0, s.minLength - v.length);
1141
+ return v;
1142
+ }
1143
+
1144
+ function detectFormat(v) {
1145
+ for (const f of ["uuid", "email", "date-time", "date", "time", "ipv4"]) if (FORMATS[f](v)) return f;
1146
+ if (/^https?:\/\//i.test(v)) return "uri";
1147
+ return undefined;
1148
+ }
1149
+
1150
+ export function inferSchema(sample, key) {
1151
+ const t = typeOf(sample);
1152
+ if (t === "null") return { type: "null" };
1153
+ if (t === "boolean") return { type: "boolean" };
1154
+ if (t === "integer" || t === "number") {
1155
+ const s = { type: t };
1156
+ if (!isIdKey(key) && !NUMBER_KEYS.test(norm(key))) {
1157
+ const a = Math.abs(sample);
1158
+ s.minimum = sample < 0 ? -Math.max(10, a * 2) : 0;
1159
+ s.maximum = Math.max(10, a * 2);
1160
+ }
1161
+ return s;
1162
+ }
1163
+ if (t === "string") {
1164
+ const s = { type: "string" };
1165
+ const f = detectFormat(sample);
1166
+ if (f) s.format = f;
1167
+ else if (!/\s/.test(sample) && sample.length < 16) s.maxLength = Math.max(sample.length, 8);
1168
+ if (/^#[0-9a-f]{6}$/i.test(sample)) s.pattern = "^#[0-9a-f]{6}$";
1169
+ return s;
1170
+ }
1171
+ if (t === "array") {
1172
+ const s = { type: "array", minItems: Math.min(sample.length, 1), maxItems: Math.max(sample.length, 3) };
1173
+ if (sample.length) {
1174
+ const objs = sample.filter((x) => x !== null && typeof x === "object" && !Array.isArray(x));
1175
+ if (objs.length === sample.length) {
1176
+ const merged = {};
1177
+ for (const o of objs) for (const [k, v] of Object.entries(o)) if (!(k in merged)) merged[k] = v;
1178
+ s.items = inferSchema(merged, key);
1179
+ } else s.items = inferSchema(sample[0], key);
1180
+ }
1181
+ return s;
1182
+ }
1183
+ const props = {};
1184
+ for (const [k, v] of Object.entries(sample)) props[k] = inferSchema(v, k);
1185
+ return { type: "object", properties: props, required: Object.keys(props) };
1186
+ }
1187
+
1188
+ export function mockFromSchema(schema, count = 10, seed = 1, opts = {}) {
1189
+ const r = makeRng(seed);
1190
+ const n = Math.max(0, Math.min(10000, Math.floor(count)));
1191
+ const out = [];
1192
+ let record = schema;
1193
+ if (record && typeof record === "object" && record.type === "array" && record.items && typeof record.items === "object" && !Array.isArray(record.items)) record = record.items;
1194
+ for (let i = 0; i < n; i++) out.push(genSchema(record, opts.key || "", { r, root: schema, index: i, person: null, optional: opts.optional || "all" }, 0));
1195
+ return out;
1196
+ }
1197
+
1198
+ export function mockFromSample(sample, count = 10, seed = 1) {
1199
+ let shape = sample;
1200
+ if (Array.isArray(sample)) {
1201
+ if (!sample.length) throw new Error("The sample array is empty");
1202
+ const objs = sample.filter((x) => x !== null && typeof x === "object" && !Array.isArray(x));
1203
+ if (objs.length === sample.length) {
1204
+ shape = {};
1205
+ for (const o of objs) for (const [k, v] of Object.entries(o)) if (!(k in shape)) shape[k] = v;
1206
+ } else shape = sample[0];
1207
+ }
1208
+ const schema = inferSchema(shape, "");
1209
+ return mockFromSchema(schema, count, seed);
1210
+ }
1211
+
1212
+ export function looksLikeSchema(v) {
1213
+ if (!v || typeof v !== "object" || Array.isArray(v)) return false;
1214
+ if (v.$schema || v.$defs || v.definitions) return true;
1215
+ if (typeof v.type === "string" && ["object", "array", "string", "number", "integer", "boolean", "null"].includes(v.type) && (v.properties || v.items || Object.keys(v).length <= 4)) {
1216
+ if (v.properties && typeof v.properties === "object") return Object.values(v.properties).every((p) => p === true || p === false || (p && typeof p === "object" && !Array.isArray(p)));
1217
+ return true;
1218
+ }
1219
+ return false;
1220
+ }
1221
+
1222
+ export function toCsv(rows) {
1223
+ if (!Array.isArray(rows) || !rows.length) return "";
1224
+ const cols = [];
1225
+ const flat = rows.map((r) => {
1226
+ const o = {};
1227
+ const walk = (v, p) => {
1228
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) for (const [k, x] of Object.entries(v)) walk(x, p ? p + "." + k : k);
1229
+ else o[p || "value"] = Array.isArray(v) ? JSON.stringify(v) : v;
1230
+ };
1231
+ walk(r, "");
1232
+ for (const k of Object.keys(o)) if (!cols.includes(k)) cols.push(k);
1233
+ return o;
1234
+ });
1235
+ const cell = (v) => {
1236
+ if (v === undefined || v === null) return "";
1237
+ const s = String(v);
1238
+ return /[",\n\r]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
1239
+ };
1240
+ return [cols.map(cell).join(","), ...flat.map((o) => cols.map((c) => cell(o[c])).join(","))].join("\n");
1241
+ }