@osqd/jql 0.1.1 → 0.1.2

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +44 -1
  2. package/conformance/cases.json +2 -0
  3. package/dist/chunk-2ZMIVDES.cjs +1661 -0
  4. package/dist/chunk-2ZMIVDES.cjs.map +1 -0
  5. package/dist/chunk-6PWYYYWU.js +1637 -0
  6. package/dist/chunk-6PWYYYWU.js.map +1 -0
  7. package/dist/chunk-74QKHM6Y.cjs +145 -0
  8. package/dist/chunk-74QKHM6Y.cjs.map +1 -0
  9. package/dist/chunk-ATRXHPBJ.js +112 -0
  10. package/dist/chunk-ATRXHPBJ.js.map +1 -0
  11. package/dist/chunk-EJFHVGBC.cjs +63 -0
  12. package/dist/chunk-EJFHVGBC.cjs.map +1 -0
  13. package/dist/chunk-ITPY6VTV.cjs +115 -0
  14. package/dist/chunk-ITPY6VTV.cjs.map +1 -0
  15. package/dist/chunk-JK6OYDLX.js +712 -0
  16. package/dist/chunk-JK6OYDLX.js.map +1 -0
  17. package/dist/chunk-N7DS4QNW.js +60 -0
  18. package/dist/chunk-N7DS4QNW.js.map +1 -0
  19. package/dist/chunk-PNBQ2HIJ.js +133 -0
  20. package/dist/chunk-PNBQ2HIJ.js.map +1 -0
  21. package/dist/chunk-VMFEQXBB.js +578 -0
  22. package/dist/chunk-VMFEQXBB.js.map +1 -0
  23. package/dist/cjs/text/index.d.ts +1 -1
  24. package/dist/cjs/text/parse.d.ts +2 -1
  25. package/dist/cjs/text/quote.d.ts +17 -0
  26. package/dist/cjs/text/suggest.d.ts +27 -5
  27. package/dist/cli.js +13 -2395
  28. package/dist/cli.js.map +1 -1
  29. package/dist/global.cjs +26 -1849
  30. package/dist/global.cjs.map +1 -1
  31. package/dist/global.js +8 -1831
  32. package/dist/global.js.map +1 -1
  33. package/dist/index.cjs +143 -1996
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.js +5 -2493
  36. package/dist/index.js.map +1 -1
  37. package/dist/mongo.cjs +20 -119
  38. package/dist/mongo.cjs.map +1 -1
  39. package/dist/mongo.js +2 -101
  40. package/dist/mongo.js.map +1 -1
  41. package/dist/text/index.d.ts +1 -1
  42. package/dist/text/parse.d.ts +2 -1
  43. package/dist/text/quote.d.ts +17 -0
  44. package/dist/text/suggest.d.ts +27 -5
  45. package/dist/text.cjs +146 -101
  46. package/dist/text.cjs.map +1 -1
  47. package/dist/text.js +3 -665
  48. package/dist/text.js.map +1 -1
  49. package/docs/course/11-the-search-box.md +49 -2
  50. package/docs/course/16-extending.md +1 -1
  51. package/docs/reference/api.md +14 -1
  52. package/docs/reference/specification.md +9 -2
  53. package/docs/reference/text-syntax.md +41 -6
  54. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -1,1937 +1,21 @@
1
1
  'use strict';
2
2
 
3
- // src/errors.ts
4
- var JqlError = class extends Error {
5
- /**
6
- * Where in the query the problem is, written the way you would reach it in code:
7
- * `$or[1].age.$gt`. Empty for the query as a whole.
8
- */
9
- at;
10
- constructor(message, at = "") {
11
- super(at === "" ? message : `at ${show(at)}: ${message}`);
12
- this.name = "JqlError";
13
- this.at = at;
14
- }
15
- };
16
- function show(at) {
17
- return at.length > 80 ? `${at.slice(0, 80)}\u2026` : at;
18
- }
19
-
20
- // src/internal/closest.ts
21
- function closest(word, candidates) {
22
- let best;
23
- let bestDistance = 3;
24
- for (const candidate of candidates) {
25
- const distance = editDistance(word.toLowerCase(), candidate.toLowerCase(), bestDistance);
26
- if (distance < bestDistance) {
27
- best = candidate;
28
- bestDistance = distance;
29
- }
30
- }
31
- return best;
32
- }
33
- function editDistance(a, b, ceiling) {
34
- if (Math.abs(a.length - b.length) >= ceiling) return ceiling;
35
- let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
36
- for (let i = 1; i <= a.length; i++) {
37
- const current = [i];
38
- let rowBest = i;
39
- for (let j = 1; j <= b.length; j++) {
40
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
41
- const value = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + cost);
42
- current.push(value);
43
- if (value < rowBest) rowBest = value;
44
- }
45
- if (rowBest >= ceiling) return ceiling;
46
- previous = current;
47
- }
48
- return previous[b.length];
49
- }
50
- function didYouMean(word, candidates) {
51
- const guess = closest(word, candidates);
52
- return guess === void 0 ? "" : `; did you mean "${guess}"?`;
53
- }
54
-
55
- // src/internal/path.ts
56
- var FANOUT = /* @__PURE__ */ Symbol("jql.fanout");
57
- var INDEX = /^(?:0|[1-9]\d{0,8})$/;
58
- var INHERITED = /* @__PURE__ */ new Set([...Object.getOwnPropertyNames(Object.prototype), ...Object.getOwnPropertyNames(Map.prototype), "__proto__"]);
59
- function needsGuard(key) {
60
- return INHERITED.has(key);
61
- }
62
- var PLAIN = Object.prototype;
63
- function segment(key) {
64
- return { key, index: INDEX.test(key) ? Number(key) : -1 };
65
- }
66
- function readOwn(value, key) {
67
- if (value instanceof Map) return value.get(key);
68
- return Object.hasOwn(value, key) ? value[key] : void 0;
69
- }
70
- function readOne(value, step) {
71
- return readOwn(value, step.key);
72
- }
73
- var readSelf = (document) => document;
74
- function reachPath(keys) {
75
- const steps = keys.map(segment);
76
- return (document, test) => {
77
- let value = document;
78
- for (let at = 0; at < steps.length; at++) {
79
- if (value === null || typeof value !== "object") return test(void 0);
80
- if (Array.isArray(value)) return walk(value, steps, at, test);
81
- value = readOne(value, steps[at]);
82
- }
83
- return test(value);
84
- };
85
- }
86
- function probePath(keys) {
87
- const steps = keys.map(segment);
88
- const last = steps.length - 1;
89
- const [first, second] = steps;
90
- if (steps.length === 1 && first.index === -1) {
91
- const only = first.key;
92
- const guarded = needsGuard(only);
93
- return (document) => {
94
- if (document === null || typeof document !== "object") return void 0;
95
- if (Array.isArray(document)) return FANOUT;
96
- if (!guarded && document.__proto__ === PLAIN) return document[only];
97
- return readOwn(document, only);
98
- };
99
- }
100
- if (steps.length === 2 && first.index === -1 && second.index === -1) {
101
- const outer = first.key;
102
- const inner = second.key;
103
- const outerGuarded = needsGuard(outer);
104
- const innerGuarded = needsGuard(inner);
105
- return (document) => {
106
- if (document === null || typeof document !== "object") return void 0;
107
- if (Array.isArray(document)) return FANOUT;
108
- const value = !outerGuarded && document.__proto__ === PLAIN ? document[outer] : readOwn(document, outer);
109
- if (value === null || typeof value !== "object") return void 0;
110
- if (Array.isArray(value)) return FANOUT;
111
- return !innerGuarded && value.__proto__ === PLAIN ? value[inner] : readOwn(value, inner);
112
- };
113
- }
114
- return (document) => {
115
- let value = document;
116
- for (let at = 0; at <= last; at++) {
117
- if (value === null || typeof value !== "object") return void 0;
118
- if (Array.isArray(value) && steps[at].index === -1) return FANOUT;
119
- const step = steps[at];
120
- value = Array.isArray(value) ? value[step.index] : readOwn(value, step.key);
121
- }
122
- return value;
123
- };
124
- }
125
- function probeFrom(read, keys) {
126
- const probe = probePath(keys);
127
- return (document) => probe(read(document));
128
- }
129
- function reachFrom(read, keys) {
130
- const steps = keys.map(segment);
131
- return (document, test) => walk(read(document), steps, 0, test);
132
- }
133
- var MAX_DOCUMENT_DEPTH = 512;
134
- function walk(value, steps, at, test, depth = 0) {
135
- if (at === steps.length) return test(value);
136
- if (value === null || typeof value !== "object" || depth > MAX_DOCUMENT_DEPTH) return test(void 0);
137
- const step = steps[at];
138
- if (Array.isArray(value)) {
139
- if (step.index !== -1) return walk(value[step.index], steps, at + 1, test, depth + 1);
140
- if (value.length === 0) return test(void 0);
141
- for (let i = 0; i < value.length; i++) if (walk(value[i], steps, at, test, depth + 1)) return true;
142
- return false;
143
- }
144
- return walk(readOne(value, step), steps, at + 1, test, depth + 1);
145
- }
146
- var MAX_PATH_SEGMENTS = 512;
147
- function splitPath(path) {
148
- if (path === "") return "an empty field name reaches nothing";
149
- const keys = path.split(".");
150
- if (keys.length > MAX_PATH_SEGMENTS) {
151
- return `the path has ${keys.length} segments, past the limit of ${MAX_PATH_SEGMENTS}; nothing nests that deep`;
152
- }
153
- for (const key of keys) if (key === "") return `the path "${path.length > 80 ? `${path.slice(0, 80)}\u2026` : path}" has an empty segment, which reaches nothing`;
154
- return keys;
155
- }
156
-
157
- // src/internal/duration.ts
158
- var PART = /(\d+)(ms|s|m|h|d|w)/g;
159
- var SHAPE = /^(?:\d+(?:ms|s|m|h|d|w))+$/;
160
- var UNITS = {
161
- ms: 1,
162
- s: 1e3,
163
- m: 6e4,
164
- h: 36e5,
165
- d: 864e5,
166
- w: 6048e5
167
- };
168
- var DURATION_UNITS = Object.keys(UNITS);
169
- function parseDuration(text2) {
170
- if (!SHAPE.test(text2)) return void 0;
171
- let total = 0;
172
- PART.lastIndex = 0;
173
- for (; ; ) {
174
- const part = PART.exec(text2);
175
- if (part === null) break;
176
- const count4 = Number(part[1]);
177
- if (!Number.isSafeInteger(count4)) return void 0;
178
- total += count4 * UNITS[part[2]];
179
- }
180
- return Number.isSafeInteger(total) ? total : void 0;
181
- }
182
-
183
- // src/internal/values.ts
184
- function isPlainObject(value) {
185
- if (value === null || typeof value !== "object") return false;
186
- const prototype = Object.getPrototypeOf(value);
187
- return prototype === Object.prototype || prototype === null;
188
- }
189
- function isDateLiteral(value) {
190
- if (!isPlainObject(value) || !("$date" in value)) return false;
191
- for (const key in value) if (key !== "$date") return false;
192
- return true;
193
- }
194
- function isFieldReference(value) {
195
- if (!isPlainObject(value) || typeof value.$field !== "string") return false;
196
- for (const key in value) if (key !== "$field") return false;
197
- return true;
198
- }
199
- function resolveDate(value, now) {
200
- if (typeof value === "number") return value;
201
- if (typeof value === "string") return value === "now" ? now : instant(value);
202
- if (isPlainObject(value)) {
203
- const keys = Object.keys(value);
204
- if (keys.length !== 1) return Number.NaN;
205
- const amount = keys[0] === "$ago" || keys[0] === "$ahead" ? value[keys[0]] : void 0;
206
- if (typeof amount !== "string") return Number.NaN;
207
- const span = parseDuration(amount);
208
- if (span === void 0) return Number.NaN;
209
- return keys[0] === "$ago" ? now - span : now + span;
210
- }
211
- return Number.NaN;
212
- }
213
- var ISO_8601 = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
214
- var NO_OFFSET = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?)$/;
215
- function instant(text2) {
216
- const bare = NO_OFFSET.exec(text2);
217
- return bare === null ? Date.parse(text2) : Date.parse(`${bare[1]}T${bare[2]}Z`);
218
- }
219
- function toTime(value) {
220
- if (typeof value === "number") return value;
221
- if (value instanceof Date) return value.getTime();
222
- if (typeof value === "string") return ISO_8601.test(value) ? instant(value) : Number.NaN;
223
- return Number.NaN;
224
- }
225
- var TYPE_NAMES = ["string", "number", "integer", "bigint", "boolean", "null", "array", "object", "date"];
226
- function isOfType(value, type) {
227
- switch (type) {
228
- case "string":
229
- return typeof value === "string";
230
- case "number":
231
- return typeof value === "number" || typeof value === "bigint";
232
- case "integer":
233
- return Number.isInteger(value) || typeof value === "bigint";
234
- case "bigint":
235
- return typeof value === "bigint";
236
- case "boolean":
237
- return typeof value === "boolean";
238
- case "null":
239
- return value === null;
240
- case "array":
241
- return Array.isArray(value);
242
- case "date":
243
- return value instanceof Date;
244
- case "object":
245
- return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
246
- }
247
- }
248
- function describe(value) {
249
- if (value === null) return "null";
250
- if (typeof value === "function") return "a function";
251
- if (Array.isArray(value)) return "an array";
252
- if (value instanceof RegExp) return "a RegExp object";
253
- if (value instanceof Date) return "a Date object";
254
- if (value instanceof Map) return "a Map";
255
- if (value instanceof Set) return "a Set";
256
- if (typeof value === "object") {
257
- if (isPlainObject(value)) return "an object";
258
- const name = nameOf(value);
259
- return name === void 0 ? "an object" : `an instance of ${name}`;
260
- }
261
- if (typeof value === "string") return `the string ${JSON.stringify(value.length > 40 ? `${value.slice(0, 40)}\u2026` : value)}`;
262
- return `${typeof value} ${String(value)}`;
263
- }
264
- function nameOf(value) {
265
- const prototype = Object.getPrototypeOf(value);
266
- const name = prototype?.constructor?.name;
267
- return typeof name === "string" && name !== "" && name !== "Object" ? name : void 0;
268
- }
269
-
270
- // src/limits.ts
271
- var DEFAULT_LIMITS = Object.freeze({
272
- maxDepth: 32,
273
- maxNodes: 1e4,
274
- maxPatternLength: 1024,
275
- maxGlobLength: 1024,
276
- maxTextDepth: 16,
277
- allowRegex: true,
278
- allowOperators: "all"
279
- });
280
- var UNTRUSTED_LIMITS = Object.freeze({
281
- maxDepth: 16,
282
- maxNodes: 512,
283
- maxPatternLength: 0,
284
- maxGlobLength: 256,
285
- maxTextDepth: 8,
286
- allowRegex: false,
287
- // Still every operator but `$regex`: which of the rest an endpoint wants is a decision
288
- // only that endpoint can make, and a list guessed here would be one nobody had chosen.
289
- allowOperators: "all"
290
- });
291
-
292
- // src/internal/equal.ts
293
- function sameInteger(a, b) {
294
- const big = typeof a === "bigint" ? a : typeof b === "bigint" ? b : void 0;
295
- const other = typeof a === "bigint" ? b : a;
296
- if (big === void 0) return false;
297
- if (typeof other === "bigint") return big === other;
298
- return typeof other === "number" && Number.isInteger(other) && big === BigInt(other);
299
- }
300
- var MAX_EQUAL_DEPTH = 64;
301
- function alsoBig(literal2) {
302
- return typeof literal2 === "number" && Number.isInteger(literal2) ? BigInt(literal2) : void 0;
303
- }
304
- function equalsLiteral(literal2, now, ignoreCase = false) {
305
- if (literal2 === null) return (value) => value === null;
306
- if (typeof literal2 !== "object") {
307
- if (ignoreCase && typeof literal2 === "string") {
308
- const wanted = literal2.toLowerCase();
309
- return (value) => typeof value === "string" && value.toLowerCase() === wanted;
310
- }
311
- const big = alsoBig(literal2);
312
- if (big !== void 0) return (value) => value === literal2 || value === big;
313
- return (value) => value === literal2;
314
- }
315
- if (isDateLiteral(literal2)) {
316
- const time = resolveDate(literal2.$date, now);
317
- return (value) => toTime(value) === time;
318
- }
319
- return (value) => deepEqual(value, literal2, 0, ignoreCase, now);
320
- }
321
- function valuesEqual(a, b) {
322
- if (a === void 0 || b === void 0) return false;
323
- if (a instanceof Date || b instanceof Date) {
324
- const left = toTime(a);
325
- const right = toTime(b);
326
- return a instanceof Date && b instanceof Date && left === right && !Number.isNaN(left);
327
- }
328
- return deepEqual(a, b, 0);
329
- }
330
- function deepEqual(actual, wanted, depth, ignoreCase = false, now = 0) {
331
- if (actual === wanted) return true;
332
- if (typeof actual === "bigint" || typeof wanted === "bigint") return sameInteger(actual, wanted);
333
- if (actual instanceof Date && wanted instanceof Date) return actual.getTime() === wanted.getTime();
334
- if (depth > MAX_EQUAL_DEPTH) return false;
335
- if (ignoreCase && typeof actual === "string" && typeof wanted === "string") return actual.toLowerCase() === wanted.toLowerCase();
336
- if (wanted === null || typeof wanted !== "object") return false;
337
- if (isDateLiteral(wanted)) return toTime(actual) === resolveDate(wanted.$date, now);
338
- if (actual === null || typeof actual !== "object") return false;
339
- if (Array.isArray(wanted)) {
340
- if (!Array.isArray(actual) || actual.length !== wanted.length) return false;
341
- for (let i = 0; i < wanted.length; i++) if (!deepEqual(actual[i], wanted[i], depth + 1, ignoreCase, now)) return false;
342
- return true;
343
- }
344
- if (Array.isArray(actual) || !isPlainObject(wanted)) return false;
345
- if (actual instanceof Map) {
346
- let size2 = 0;
347
- for (const key in wanted) {
348
- const expected = wanted[key];
349
- if (expected === void 0) continue;
350
- size2++;
351
- if (!actual.has(key) || !deepEqual(actual.get(key), expected, depth + 1, ignoreCase, now)) return false;
352
- }
353
- let present2 = 0;
354
- for (const value of actual.values()) if (value !== void 0) present2++;
355
- return present2 === size2;
356
- }
357
- const record = actual;
358
- let size = 0;
359
- for (const key in wanted) {
360
- const expected = wanted[key];
361
- if (expected === void 0) continue;
362
- size++;
363
- if (!Object.hasOwn(record, key) || !deepEqual(record[key], expected, depth + 1, ignoreCase, now)) return false;
364
- }
365
- let present = 0;
366
- for (const key in record) if (Object.hasOwn(record, key) && record[key] !== void 0) present++;
367
- return present === size;
368
- }
369
-
370
- // src/internal/glob.ts
371
- var ANY = { any: true };
372
- var ONE = { one: true };
373
- function compileGlob(pattern) {
374
- const tokens = tokenize(pattern);
375
- const stars = tokens.includes(ANY);
376
- const questions = tokens.includes(ONE);
377
- if (!stars && !questions) {
378
- const literal2 = tokens.join("");
379
- return (text2) => text2 === literal2;
380
- }
381
- if (!questions) {
382
- const segments = [""];
383
- for (const token of tokens) {
384
- if (token === ANY) segments.push("");
385
- else segments[segments.length - 1] += token;
386
- }
387
- const open = segments[0] === "";
388
- const close = segments[segments.length - 1] === "";
389
- const parts = segments.filter((segment2) => segment2 !== "");
390
- if (parts.length === 0) return () => true;
391
- if (open && close && parts.length === 1) {
392
- const inside = parts[0];
393
- return (text2) => text2.includes(inside);
394
- }
395
- if (!open && close && parts.length === 1) {
396
- const prefix = parts[0];
397
- return (text2) => text2.startsWith(prefix);
398
- }
399
- if (open && !close && parts.length === 1) {
400
- const suffix = parts[0];
401
- return (text2) => text2.endsWith(suffix);
402
- }
403
- return (text2) => scan(text2, parts, open, close);
404
- }
405
- return (text2) => walk2([...text2], tokens);
406
- }
407
- function tokenize(pattern) {
408
- const tokens = [];
409
- let escaped = false;
410
- for (const character of pattern) {
411
- if (escaped) {
412
- tokens.push(character);
413
- escaped = false;
414
- continue;
415
- }
416
- if (character === "\\") {
417
- escaped = true;
418
- continue;
419
- }
420
- if (character === "*") {
421
- if (tokens[tokens.length - 1] !== ANY) tokens.push(ANY);
422
- continue;
423
- }
424
- tokens.push(character === "?" ? ONE : character);
425
- }
426
- if (escaped) tokens.push("\\");
427
- return tokens;
428
- }
429
- function scan(text2, parts, open, close) {
430
- let at = 0;
431
- const last = parts.length - 1;
432
- for (let i = 0; i <= last; i++) {
433
- const part = parts[i];
434
- if (i === 0 && !open) {
435
- if (!text2.startsWith(part)) return false;
436
- at = part.length;
437
- continue;
438
- }
439
- if (i === last && !close) {
440
- return text2.length - part.length >= at && text2.endsWith(part);
441
- }
442
- const found = text2.indexOf(part, at);
443
- if (found === -1) return false;
444
- at = found + part.length;
445
- }
446
- return true;
447
- }
448
- function walk2(characters, tokens) {
449
- let at = 0;
450
- let token = 0;
451
- let star = -1;
452
- let mark = 0;
453
- while (at < characters.length) {
454
- const current = tokens[token];
455
- if (current !== void 0 && (current === ONE || current === characters[at])) {
456
- at++;
457
- token++;
458
- continue;
459
- }
460
- if (current === ANY) {
461
- star = token++;
462
- mark = at;
463
- continue;
464
- }
465
- if (star !== -1) {
466
- token = star + 1;
467
- at = ++mark;
468
- continue;
469
- }
470
- return false;
471
- }
472
- while (tokens[token] === ANY) token++;
473
- return token === tokens.length;
474
- }
475
-
476
- // src/operators.ts
477
- var NEVER = () => false;
478
- function lower(value) {
479
- return value.toLowerCase();
480
- }
481
- function equalsTest(literal2, ignoreCase, at, now) {
482
- checkLiteral(literal2, at);
483
- if (literal2 === null) return (value) => value === null || value === void 0;
484
- return equalsLiteral(literal2, now, ignoreCase);
485
- }
486
- function inTest(list, ignoreCase, at, now) {
487
- if (!Array.isArray(list)) throw new JqlError(`takes a list of values, not ${describe(list)}`, at);
488
- if (list.length === 0) return NEVER;
489
- const primitives = /* @__PURE__ */ new Set();
490
- const complex = [];
491
- let bigints;
492
- let matchesMissing = false;
493
- list.forEach((item, index) => {
494
- checkLiteral(item, `${at}[${index}]`);
495
- if (item === null) matchesMissing = true;
496
- else if (typeof item === "object") complex.push(equalsLiteral(item, now, ignoreCase));
497
- else {
498
- primitives.add(ignoreCase && typeof item === "string" ? lower(item) : item);
499
- const big = alsoBig(item);
500
- if (big !== void 0) (bigints ??= /* @__PURE__ */ new Set()).add(big);
501
- }
502
- });
503
- const fold2 = ignoreCase;
504
- const whole = bigints;
505
- return (value) => {
506
- if (value === void 0 || value === null) return matchesMissing;
507
- if (primitives.has(fold2 && typeof value === "string" ? lower(value) : value)) return true;
508
- if (whole !== void 0 && typeof value === "bigint" && whole.has(value)) return true;
509
- for (let i = 0; i < complex.length; i++) if (complex[i](value)) return true;
510
- return false;
511
- };
512
- }
513
- function orderTest(operator, bound, at, now) {
514
- if (typeof bound === "number") {
515
- if (Number.isNaN(bound)) throw new JqlError("NaN compares false with everything, so this would match nothing", at);
516
- switch (operator) {
517
- case "$gt":
518
- return (value) => (typeof value === "number" || typeof value === "bigint") && value > bound;
519
- case "$gte":
520
- return (value) => (typeof value === "number" || typeof value === "bigint") && value >= bound;
521
- case "$lt":
522
- return (value) => (typeof value === "number" || typeof value === "bigint") && value < bound;
523
- case "$lte":
524
- return (value) => (typeof value === "number" || typeof value === "bigint") && value <= bound;
525
- }
526
- }
527
- if (typeof bound === "string") {
528
- switch (operator) {
529
- case "$gt":
530
- return (value) => typeof value === "string" && value > bound;
531
- case "$gte":
532
- return (value) => typeof value === "string" && value >= bound;
533
- case "$lt":
534
- return (value) => typeof value === "string" && value < bound;
535
- case "$lte":
536
- return (value) => typeof value === "string" && value <= bound;
537
- }
538
- }
539
- if (isDateLiteral(bound)) {
540
- const time = resolveDate(bound.$date, now);
541
- if (Number.isNaN(time)) throw new JqlError(`${JSON.stringify(bound.$date)} is not a date, so every comparison with it would be false`, at);
542
- switch (operator) {
543
- case "$gt":
544
- return (value) => value !== null && value !== void 0 && toTime(value) > time;
545
- case "$gte":
546
- return (value) => value !== null && value !== void 0 && toTime(value) >= time;
547
- case "$lt":
548
- return (value) => value !== null && value !== void 0 && toTime(value) < time;
549
- case "$lte":
550
- return (value) => value !== null && value !== void 0 && toTime(value) <= time;
551
- }
552
- }
553
- throw new JqlError(`compares with a number, a string, a {"$date": \u2026} or a {"$field": \u2026}, not ${describe(bound)}`, at);
554
- }
555
- function stringTest(operator, operand2, ignoreCase, at, maxGlobLength = Number.POSITIVE_INFINITY) {
556
- const list = typeof operand2 === "string" ? [operand2] : operand2;
557
- if (!Array.isArray(list)) throw new JqlError(`takes a string or a list of strings, not ${describe(operand2)}`, at);
558
- if (list.length === 0) return NEVER;
559
- const wanted = list.map((item, index) => {
560
- if (typeof item !== "string") throw new JqlError(`takes strings, not ${describe(item)}`, `${at}[${index}]`);
561
- return ignoreCase ? lower(item) : item;
562
- });
563
- if (operator === "$glob") {
564
- for (const pattern of wanted) {
565
- if (pattern.length > maxGlobLength) throw new JqlError(`the glob is ${pattern.length} characters, past the limit of ${maxGlobLength}`, at);
566
- }
567
- const globs = wanted.map(compileGlob);
568
- if (globs.length === 1) {
569
- const only = globs[0];
570
- return ignoreCase ? (value) => typeof value === "string" && only(lower(value)) : (value) => typeof value === "string" && only(value);
571
- }
572
- return (value) => {
573
- if (typeof value !== "string") return false;
574
- const actual = ignoreCase ? lower(value) : value;
575
- for (let i = 0; i < globs.length; i++) if (globs[i](actual)) return true;
576
- return false;
577
- };
578
- }
579
- const one = (actual, value) => {
580
- switch (operator) {
581
- case "$contains":
582
- return actual.includes(value);
583
- case "$startsWith":
584
- return actual.startsWith(value);
585
- case "$endsWith":
586
- return actual.endsWith(value);
587
- case "$word":
588
- return containsWord(actual, value);
589
- }
590
- };
591
- if (wanted.length === 1) {
592
- const only = wanted[0];
593
- if (operator === "$contains") return ignoreCase ? (value) => typeof value === "string" && lower(value).includes(only) : (value) => typeof value === "string" && value.includes(only);
594
- return (value) => typeof value === "string" && one(ignoreCase ? lower(value) : value, only);
595
- }
596
- return (value) => {
597
- if (typeof value !== "string") return false;
598
- const actual = ignoreCase ? lower(value) : value;
599
- for (let i = 0; i < wanted.length; i++) if (one(actual, wanted[i])) return true;
600
- return false;
601
- };
602
- }
603
- var ALPHANUMERIC = /[\p{L}\p{N}]/u;
604
- function containsWord(actual, wanted) {
605
- if (wanted === "") return false;
606
- const characters = [...wanted];
607
- const startsAlphanumeric = ALPHANUMERIC.test(characters[0]);
608
- const endsAlphanumeric = ALPHANUMERIC.test(characters[characters.length - 1]);
609
- let from = 0;
610
- for (; ; ) {
611
- const at = actual.indexOf(wanted, from);
612
- if (at === -1) return false;
613
- const end = at + wanted.length;
614
- const startsClean = at === 0 || !startsAlphanumeric || !ALPHANUMERIC.test(before(actual, at));
615
- const endsClean = end >= actual.length || !endsAlphanumeric || !ALPHANUMERIC.test(after(actual, end));
616
- if (startsClean && endsClean) return true;
617
- from = at + 1;
618
- }
619
- }
620
- function before(text2, at) {
621
- const code = text2.charCodeAt(at - 1);
622
- return code >= 56320 && code <= 57343 && at >= 2 ? text2.slice(at - 2, at) : text2[at - 1];
623
- }
624
- function after(text2, end) {
625
- const code = text2.charCodeAt(end);
626
- return code >= 55296 && code <= 56319 ? text2.slice(end, end + 2) : text2[end];
627
- }
628
- var OPTION_FLAGS = /* @__PURE__ */ new Set(["i", "m", "s", "u"]);
629
- function parseOptions(options, at) {
630
- if (typeof options !== "string") throw new JqlError(`takes a string of flags such as "i", not ${describe(options)}`, at);
631
- for (const flag of options) {
632
- if (!OPTION_FLAGS.has(flag)) {
633
- const why = flag === "g" || flag === "y" ? ": it makes a pattern stateful, so it would match on every other document" : "";
634
- throw new JqlError(`"${flag}" is not a flag this language takes (i, m, s, u)${why}`, at);
635
- }
636
- }
637
- if (new Set(options).size !== options.length) throw new JqlError(`"${options}" repeats a flag`, at);
638
- return options;
639
- }
640
- function regexTest(pattern, flags, limits, at) {
641
- if (!limits.allowRegex) throw new JqlError("patterns are turned off for this query; $contains, $startsWith, $endsWith and $word cover most of what one is for", at);
642
- if (typeof pattern !== "string") throw new JqlError(`takes the pattern as a string, not ${describe(pattern)}`, at);
643
- if (pattern.length > limits.maxPatternLength) throw new JqlError(`the pattern is ${pattern.length} characters, past the limit of ${limits.maxPatternLength}`, at);
644
- let expression;
645
- try {
646
- expression = new RegExp(pattern, flags);
647
- } catch (error) {
648
- throw new JqlError(`the pattern does not compile: ${error instanceof Error ? error.message : String(error)}`, at);
649
- }
650
- return (value) => typeof value === "string" && expression.test(value);
651
- }
652
- function typeTest(operand2, at) {
653
- const list = typeof operand2 === "string" ? [operand2] : operand2;
654
- if (!Array.isArray(list) || list.length === 0) throw new JqlError(`takes a type name or a non-empty list of them, not ${describe(operand2)}`, at);
655
- const types = list.map((name, index) => {
656
- if (typeof name !== "string" || !TYPE_NAMES.includes(name)) {
657
- throw new JqlError(`${describe(name)} is not a type name (${TYPE_NAMES.join(", ")})${typeof name === "string" ? didYouMean(name, TYPE_NAMES) : ""}`, `${at}[${index}]`);
658
- }
659
- return name;
660
- });
661
- if (types.length === 1) {
662
- const only = types[0];
663
- return (value) => isOfType(value, only);
664
- }
665
- return (value) => types.some((type) => isOfType(value, type));
666
- }
667
- function modTest(operand2, at) {
668
- if (!Array.isArray(operand2) || operand2.length !== 2 || typeof operand2[0] !== "number" || typeof operand2[1] !== "number") {
669
- throw new JqlError(`takes [divisor, remainder], not ${describe(operand2)}`, at);
670
- }
671
- const [divisor, remainder] = operand2;
672
- if (divisor === 0 || !Number.isFinite(divisor)) throw new JqlError("a divisor of zero leaves no remainder to compare, so this would match nothing", at);
673
- const big = Number.isInteger(divisor) ? BigInt(divisor) : void 0;
674
- return (value) => {
675
- if (typeof value === "number") return value % divisor === remainder;
676
- if (typeof value === "bigint") return big !== void 0 && Number(value % big) === remainder;
677
- return false;
678
- };
679
- }
680
- function allTest(list, ignoreCase, at, now) {
681
- if (!Array.isArray(list)) throw new JqlError(`takes a list of values, not ${describe(list)}`, at);
682
- if (list.length === 0) return NEVER;
683
- const tests = list.map((item, index) => {
684
- if (isPlainObject(item) && Object.keys(item).some((key) => key.startsWith("$")) && !isDateLiteral(item)) {
685
- throw new JqlError("takes values, not conditions; use $elemMatch inside $and for that", `${at}[${index}]`);
686
- }
687
- return equalsTest(item, ignoreCase, `${at}[${index}]`, now);
688
- });
689
- return (value) => {
690
- for (const test of tests) {
691
- if (test(value)) continue;
692
- if (!Array.isArray(value)) return false;
693
- let found = false;
694
- for (let i = 0; i < value.length; i++) {
695
- if (test(value[i])) {
696
- found = true;
697
- break;
698
- }
699
- }
700
- if (!found) return false;
701
- }
702
- return true;
703
- };
704
- }
705
- function orderOf(a, b) {
706
- if ((typeof a === "number" || typeof a === "bigint") && (typeof b === "number" || typeof b === "bigint")) {
707
- if (Number.isNaN(a) || Number.isNaN(b)) return void 0;
708
- return a < b ? -1 : a > b ? 1 : 0;
709
- }
710
- if (typeof a === "string" && typeof b === "string") return a < b ? -1 : a > b ? 1 : 0;
711
- if (a instanceof Date && b instanceof Date) {
712
- const left = a.getTime();
713
- const right = b.getTime();
714
- return Number.isNaN(left) || Number.isNaN(right) ? void 0 : left - right;
715
- }
716
- return void 0;
717
- }
718
- function checkLiteral(value, at, depth = 0) {
719
- if (value === null || typeof value === "string" || typeof value === "boolean") return;
720
- if (typeof value === "number") {
721
- if (!Number.isFinite(value)) throw new JqlError(`${String(value)} is not a JSON number`, at);
722
- return;
723
- }
724
- if (depth > 64) throw new JqlError("the literal nests deeper than 64 levels", at);
725
- if (Array.isArray(value)) {
726
- value.forEach((item, index) => checkLiteral(item, `${at}[${index}]`, depth + 1));
727
- return;
728
- }
729
- if (isPlainObject(value)) {
730
- if (isFieldReference(value)) {
731
- throw new JqlError(
732
- `a {"$field": \u2026} reference compares with another field, which $eq, $ne and the ordering operators do; it is not a value that can be held here`,
733
- at
734
- );
735
- }
736
- if (isDateLiteral(value)) {
737
- const date = value.$date;
738
- if (Number.isNaN(resolveDate(date, 0))) {
739
- const relative = isPlainObject(date) ? `; a relative date is {"$ago": "1h"} or {"$ahead": "1h"}, with a count and one of ${DURATION_UNITS.join(", ")}` : "";
740
- throw new JqlError(`${JSON.stringify(date)} is not a date${relative}`, `${at}.$date`);
741
- }
742
- return;
743
- }
744
- for (const key in value) checkLiteral(value[key], `${at}.${key}`, depth + 1);
745
- return;
746
- }
747
- const hint = value instanceof RegExp ? '; write {"$regex": "\u2026"} instead' : value instanceof Date ? '; write {"$date": "\u2026"} instead' : "";
748
- throw new JqlError(`${describe(value)} is not JSON, so a query holding it could not be stored or sent${hint}`, at);
749
- }
750
-
751
- // src/vocabulary.ts
752
- var BAD_NAME = /^\$|\./;
753
- function defineVocabulary() {
754
- return (definition) => build(definition);
755
- }
756
- function checkVocabulary(value, at = "vocabulary") {
757
- if (value === void 0 || value !== null && typeof value === "object" && value.lookup instanceof Map) return value;
758
- throw new JqlError(
759
- `is not a vocabulary, but ${describe(value)}: build one with defineVocabulary()({ fields: \u2026 }) \u2014 the empty parentheses first \u2014 and pass what that returns`,
760
- at
761
- );
762
- }
763
- function build(definition) {
764
- const lookup = /* @__PURE__ */ new Map();
765
- const fields = [];
766
- const claim = (name, field) => {
767
- const key = name.toLowerCase();
768
- if (name === "" || BAD_NAME.test(name)) throw new JqlError(`"${name}" cannot name a field: a field name is not empty, does not start with "$" and has no "."`, "vocabulary");
769
- const holder = lookup.get(key);
770
- if (holder !== void 0) {
771
- throw new JqlError(`"${name}" names both "${holder.name}" and "${field.name}", so a query using it could mean either`, "vocabulary");
772
- }
773
- lookup.set(key, field);
774
- };
775
- for (const [name, spec] of Object.entries(definition.fields)) {
776
- if (spec.path !== void 0 && spec.get !== void 0) {
777
- throw new JqlError(`"${name}" has both a path and a getter; one of them would be ignored, so say which`, `vocabulary.${name}`);
778
- }
779
- if (spec.path === "") throw new JqlError(`"${name}" has an empty path, which reaches nothing`, `vocabulary.${name}`);
780
- const field = {
781
- name,
782
- kind: spec.kind ?? "text",
783
- path: spec.path ?? name,
784
- get: spec.get,
785
- aliases: spec.aliases ?? [],
786
- values: spec.values
787
- };
788
- fields.push(field);
789
- claim(name, field);
790
- for (const alias of field.aliases) claim(alias, field);
791
- }
792
- if (definition.text !== void 0) {
793
- for (const name of definition.text) {
794
- if (!lookup.has(name.toLowerCase())) throw new JqlError(`the text field "${name}" is not a field of this vocabulary, so a bare word would never search it`, "vocabulary.text");
795
- }
796
- }
797
- return {
798
- lookup,
799
- fields,
800
- names: [...lookup.keys()].sort(),
801
- text: definition.text,
802
- strict: definition.strict ?? false
803
- };
804
- }
805
-
806
- // src/core.ts
807
- var EXTENSION_NAME = /^\$x[A-Z][A-Za-z0-9]*$/;
808
- var ALWAYS = { test: () => true, cost: 0 };
809
- var NOTHING = { test: () => false, cost: 0 };
810
- var QUERY_OPERATORS = ["$and", "$or", "$nor", "$not", "$text", "$comment"];
811
- var FIELD_OPERATORS = [
812
- "$eq",
813
- "$ne",
814
- "$gt",
815
- "$gte",
816
- "$lt",
817
- "$lte",
818
- "$in",
819
- "$nin",
820
- "$exists",
821
- "$type",
822
- "$contains",
823
- "$startsWith",
824
- "$endsWith",
825
- "$word",
826
- "$glob",
827
- "$regex",
828
- "$options",
829
- "$mod",
830
- "$size",
831
- "$length",
832
- "$all",
833
- "$elemMatch",
834
- "$not"
835
- ];
836
- var FIELD_OPERATOR_SET = new Set(FIELD_OPERATORS);
837
- var EVERY_OPERATOR = [.../* @__PURE__ */ new Set([...QUERY_OPERATORS, ...FIELD_OPERATORS])];
838
- var CASE_AWARE = /* @__PURE__ */ new Set(["$eq", "$ne", "$in", "$nin", "$all", "$contains", "$startsWith", "$endsWith", "$word", "$glob", "$regex"]);
839
- function compile(query, options = {}) {
840
- if (typeof query === "function") return query;
841
- const limits = options.limits === void 0 ? DEFAULT_LIMITS : { ...DEFAULT_LIMITS, ...options.limits };
842
- const added = extensions(options.operators);
843
- const context = {
844
- vocabulary: checkVocabulary(options.vocabulary),
845
- limits,
846
- now: options.now === void 0 ? Date.now() : options.now(),
847
- operators: added,
848
- allowed: allowlist(limits.allowOperators, added),
849
- nodes: 0
850
- };
851
- const { test } = compileQuery(query, context, "", 0);
852
- if (test === ALWAYS.test) return () => true;
853
- if (test === NOTHING.test) return () => false;
854
- return test;
855
- }
856
- function matches(value, query, options) {
857
- return compile(query, options)(value);
858
- }
859
- function validate(query, options) {
860
- try {
861
- return { valid: true, test: compile(query, options) };
862
- } catch (error) {
863
- if (error instanceof JqlError) return { valid: false, error };
864
- throw error;
865
- }
866
- }
867
- function untyped(query) {
868
- return query;
869
- }
870
- function reachField(name, vocabulary, at) {
871
- return resolveField(name, { vocabulary}, at).reach;
872
- }
873
- var ALWAYS_ALLOWED = /* @__PURE__ */ new Set(["$options", "$comment"]);
874
- var GATEABLE = /* @__PURE__ */ new Set([...FIELD_OPERATORS, ...QUERY_OPERATORS, "$field"]);
875
- function allowlist(names, added) {
876
- if (names === "all") return void 0;
877
- if (!Array.isArray(names)) throw new JqlError(`is a list of operator names or "all", not ${describe(names)}`, "limits.allowOperators");
878
- const out = /* @__PURE__ */ new Set();
879
- for (const name of names) {
880
- if (typeof name !== "string" || !GATEABLE.has(name) && !added.has(name)) {
881
- throw new JqlError(`"${String(name)}" is not an operator, so allowing it allows nothing${typeof name === "string" ? didYouMean(name, [...GATEABLE]) : ""}`, "limits.allowOperators");
882
- }
883
- out.add(name);
884
- }
885
- return out;
886
- }
887
- function permit(key, context, at) {
888
- const allowed = context.allowed;
889
- if (allowed === void 0 || ALWAYS_ALLOWED.has(key) || allowed.has(key)) return;
890
- const listed = [...allowed];
891
- const shown = listed.length > 8 ? `${listed.slice(0, 8).join(", ")}, \u2026` : listed.join(", ");
892
- throw new JqlError(`"${key}" is not an operator this query may use (${shown === "" ? "none" : shown})`, at);
893
- }
894
- var NO_EXTENSIONS = /* @__PURE__ */ new Map();
895
- function extensions(given) {
896
- if (given === void 0 || given.length === 0) return NO_EXTENSIONS;
897
- const out = /* @__PURE__ */ new Map();
898
- for (const definition of given) {
899
- if (!EXTENSION_NAME.test(definition.name)) {
900
- throw new JqlError(`"${definition.name}" cannot name an added operator: the name is $x and a capital, such as "$xCidr", so a query that needs more than standard JQL says so`, "operators");
901
- }
902
- if (out.has(definition.name)) throw new JqlError(`"${definition.name}" is given twice, and the two could not both be it`, "operators");
903
- if (typeof definition.compile !== "function") throw new JqlError(`"${definition.name}" has no compile function, so there is nothing for it to do`, "operators");
904
- out.set(definition.name, definition);
905
- }
906
- return out;
907
- }
908
- function count(context, at) {
909
- context.nodes++;
910
- if (context.nodes > context.limits.maxNodes) throw new JqlError(`the query holds more than ${context.limits.maxNodes} fields and operators`, at);
911
- }
912
- function join(at, key) {
913
- return at === "" ? key : `${at}.${key}`;
914
- }
915
- function compileQuery(query, context, at, depth) {
916
- if (depth > context.limits.maxDepth) throw new JqlError(`the query nests deeper than ${context.limits.maxDepth} levels`, at);
917
- if (!isPlainObject(query)) throw new JqlError(`a query is an object, not ${describe(query)}`, at);
918
- const parts = [];
919
- let self;
920
- for (const key in query) {
921
- const value = query[key];
922
- const here = join(at, key);
923
- if (value === void 0) {
924
- throw new JqlError("the value is undefined; JSON has no undefined, and a condition on nothing would match everything", here);
925
- }
926
- count(context, here);
927
- if (!key.startsWith("$")) {
928
- parts.push(compileField(resolveField(key, context, here), value, context, here, depth));
929
- continue;
930
- }
931
- permit(key, context, here);
932
- switch (key) {
933
- case "$and":
934
- parts.push(allOf(queryList(value, context, here, depth)));
935
- break;
936
- case "$or":
937
- parts.push(anyOf(queryList(value, context, here, depth)));
938
- break;
939
- case "$nor":
940
- parts.push(negate(anyOf(queryList(value, context, here, depth))));
941
- break;
942
- case "$not":
943
- parts.push(negate(compileQuery(value, context, here, depth + 1)));
944
- break;
945
- case "$text":
946
- parts.push(compileText(value, context, here));
947
- break;
948
- case "$comment":
949
- if (typeof value !== "string") throw new JqlError(`a comment is a string, not ${describe(value)}`, here);
950
- break;
951
- default:
952
- if (!FIELD_OPERATOR_SET.has(key)) throw new JqlError(`"${key}" is not an operator${didYouMean(key, EVERY_OPERATOR)}`, here);
953
- self ??= {};
954
- self[key] = value;
955
- }
956
- }
957
- if (self !== void 0) parts.push(compileCondition(SELF, self, context, at, depth));
958
- return allOf(parts);
959
- }
960
- function queryList(value, context, at, depth) {
961
- if (!Array.isArray(value)) throw new JqlError(`takes a list of queries, not ${describe(value)}`, at);
962
- return value.map((item, index) => compileQuery(item, context, `${at}[${index}]`, depth + 1));
963
- }
964
- var SELF = { read: readSelf, probe: void 0, reach: (document, test) => test(document), key: void 0, cost: 0 };
965
- function resolveField(name, context, at) {
966
- const vocabulary = context.vocabulary;
967
- if (vocabulary !== void 0) {
968
- const direct = vocabulary.lookup.get(name.toLowerCase());
969
- if (direct !== void 0) return fieldOf(direct, [], at);
970
- const dot = name.indexOf(".");
971
- if (dot > 0) {
972
- const head = vocabulary.lookup.get(name.slice(0, dot).toLowerCase());
973
- if (head !== void 0) {
974
- const rest = splitPath(name.slice(dot + 1));
975
- if (typeof rest === "string") throw new JqlError(rest, at);
976
- return fieldOf(head, rest, at);
977
- }
978
- }
979
- if (vocabulary.strict) throw new JqlError(`"${name}" is not a field here${didYouMean(name, vocabulary.names)}`, at);
980
- }
981
- const keys = splitPath(name);
982
- if (typeof keys === "string") throw new JqlError(keys, at);
983
- return pathField(keys);
984
- }
985
- function fieldOf(field, rest, at) {
986
- if (field.get !== void 0) {
987
- const get = field.get;
988
- if (rest.length === 0) return { read: get, probe: void 0, reach: (document, test) => test(get(document)), key: void 0, cost: 3 };
989
- return { read: void 0, probe: probeFrom(get, rest), reach: reachFrom(get, rest), key: void 0, cost: 3 + rest.length };
990
- }
991
- const keys = splitPath(field.path);
992
- if (typeof keys === "string") throw new JqlError(keys, at);
993
- return pathField([...keys, ...rest]);
994
- }
995
- function pathField(keys) {
996
- if (keys.length === 1) {
997
- const key = keys[0];
998
- return { read: void 0, probe: probePath(keys), reach: reachPath(keys), key, cost: 0 };
999
- }
1000
- return { read: void 0, probe: probePath(keys), reach: reachPath(keys), key: void 0, cost: keys.length };
1001
- }
1002
- function compileField(field, value, context, at, depth) {
1003
- if (isFieldReference(value)) {
1004
- permit("$field", context, at);
1005
- permit("$eq", context, at);
1006
- return compareFields(field, "$eq", value.$field, false, context, at);
1007
- }
1008
- if (isPlainObject(value) && !isDateLiteral(value)) {
1009
- let operators = 0;
1010
- let names = 0;
1011
- for (const key in value) {
1012
- if (key.startsWith("$")) operators++;
1013
- else names++;
1014
- }
1015
- if (operators > 0 && names > 0) {
1016
- throw new JqlError("mixes operators with field names; an object here is either a condition ({ $gt: 1 }) or a value to compare with ({ a: 1 }), not both", at);
1017
- }
1018
- if (operators > 0) return compileCondition(field, value, context, at, depth + 1);
1019
- }
1020
- permit("$eq", context, at);
1021
- return equality(field, value, false, at, context.now);
1022
- }
1023
- function compileCondition(field, condition2, context, at, depth) {
1024
- const { values: values2, whole } = conditionParts(field, condition2, context, at, depth);
1025
- return combine(field, values2, whole);
1026
- }
1027
- function combine(field, values2, whole) {
1028
- const parts = [...whole];
1029
- if (values2.length > 0) {
1030
- const cost = values2.reduce((sum, value) => sum + value.cost, 0);
1031
- if (field.read !== void 0) {
1032
- const only = values2.length === 1 ? values2[0] : void 0;
1033
- parts.push(only !== void 0 && only.any !== void 0 ? holdsAny(field, only.any, only.negated, cost) : holds(field, allOfValues(values2), cost));
1034
- } else {
1035
- const separate = allOf(values2.map((value) => value.negated ? negate(holds(field, value.test, value.cost)) : holds(field, value.test, value.cost)));
1036
- const probe = field.probe;
1037
- if (probe === void 0) parts.push(separate);
1038
- else {
1039
- const fused = allOfValues(values2);
1040
- const fallback = separate.test;
1041
- parts.push({ test: (document) => {
1042
- const value = probe(document);
1043
- return value === FANOUT ? fallback(document) : fused(value);
1044
- }, cost: separate.cost });
1045
- }
1046
- }
1047
- }
1048
- return allOf(parts);
1049
- }
1050
- function conditionParts(field, condition2, context, at, depth) {
1051
- if (depth > context.limits.maxDepth) throw new JqlError(`the query nests deeper than ${context.limits.maxDepth} levels`, at);
1052
- let flags = "";
1053
- if (condition2.$options !== void 0) {
1054
- flags = parseOptions(condition2.$options, join(at, "$options"));
1055
- const usesCase = Object.keys(condition2).some((key) => CASE_AWARE.has(key));
1056
- if (!usesCase) throw new JqlError("$options has nothing to apply to: it changes $regex and the equality and string operators beside it", join(at, "$options"));
1057
- if (/[msu]/.test(flags) && condition2.$regex === void 0) throw new JqlError(`the flags "${flags.replace("i", "")}" only mean something to $regex, and there is none here`, join(at, "$options"));
1058
- }
1059
- const ignoreCase = flags.includes("i");
1060
- const values2 = [];
1061
- const whole = [];
1062
- const add = (test, cost, negated = false) => {
1063
- values2.push({ test, cost, negated, any: void 0 });
1064
- };
1065
- const addAny = (test, cost, negated = false) => {
1066
- values2.push({ test: elementwise(test), cost, negated, any: test });
1067
- };
1068
- for (const key in condition2) {
1069
- const operand2 = condition2[key];
1070
- const here = join(at, key);
1071
- if (operand2 === void 0) throw new JqlError("the value is undefined; JSON has no undefined, and a condition on nothing would match everything", here);
1072
- count(context, here);
1073
- permit(key, context, here);
1074
- switch (key) {
1075
- case "$options":
1076
- break;
1077
- case "$eq":
1078
- case "$ne": {
1079
- const negated = key === "$ne";
1080
- const reference = referencePath(operand2, here);
1081
- if (reference !== void 0) {
1082
- permit("$field", context, here);
1083
- whole.push(compareFields(field, "$eq", reference, negated, context, here));
1084
- break;
1085
- }
1086
- add(equalsValue(operand2, ignoreCase, here, context.now), operand2 !== null && typeof operand2 === "object" ? 3 : 0, negated);
1087
- break;
1088
- }
1089
- case "$gt":
1090
- case "$gte":
1091
- case "$lt":
1092
- case "$lte":
1093
- {
1094
- const reference = referencePath(operand2, here);
1095
- if (reference !== void 0) {
1096
- permit("$field", context, here);
1097
- whole.push(compareFields(field, key, reference, false, context, here));
1098
- break;
1099
- }
1100
- addAny(orderTest(key, operand2, here, context.now), 1);
1101
- }
1102
- break;
1103
- case "$in":
1104
- addAny(inTest(operand2, ignoreCase, here, context.now), 1);
1105
- break;
1106
- case "$nin":
1107
- addAny(inTest(operand2, ignoreCase, here, context.now), 1, true);
1108
- break;
1109
- case "$exists":
1110
- if (typeof operand2 !== "boolean") throw new JqlError(`takes true or false, not ${describe(operand2)}`, here);
1111
- add(isPresent, 0, !operand2);
1112
- break;
1113
- case "$type":
1114
- addAny(typeTest(operand2, here), 1);
1115
- break;
1116
- case "$contains":
1117
- case "$startsWith":
1118
- case "$endsWith":
1119
- case "$word":
1120
- case "$glob":
1121
- addAny(stringTest(key, operand2, ignoreCase, here, context.limits.maxGlobLength), key === "$word" || key === "$glob" ? 4 : 2);
1122
- break;
1123
- case "$regex":
1124
- addAny(regexTest(operand2, flags, context.limits, here), 5);
1125
- break;
1126
- case "$mod":
1127
- addAny(modTest(operand2, here), 1);
1128
- break;
1129
- case "$size":
1130
- add(sizeTest(operand2, context, here, depth, "array"), 1);
1131
- break;
1132
- case "$length":
1133
- add(sizeTest(operand2, context, here, depth, "anything with a length"), 1);
1134
- break;
1135
- case "$all":
1136
- add(allTest(operand2, ignoreCase, here, context.now), 4);
1137
- break;
1138
- case "$elemMatch": {
1139
- if (!isPlainObject(operand2)) throw new JqlError(`takes a query for one element, not ${describe(operand2)}`, here);
1140
- const element = compileQuery(operand2, context, here, depth + 1);
1141
- const test = element.test;
1142
- add((value) => {
1143
- if (!Array.isArray(value)) return false;
1144
- for (let i = 0; i < value.length; i++) if (test(value[i])) return true;
1145
- return false;
1146
- }, 4 + element.cost);
1147
- break;
1148
- }
1149
- case "$not": {
1150
- if (!isPlainObject(operand2) || isDateLiteral(operand2) || !Object.keys(operand2).every((name) => name.startsWith("$"))) {
1151
- throw new JqlError(`takes a condition such as { "$gt": 5 }, not ${describe(operand2)}; to negate a value, use $ne`, here);
1152
- }
1153
- const inner = conditionParts(field, operand2, context, here, depth + 1);
1154
- if (field.read !== void 0 && inner.whole.length === 0) {
1155
- add(allOfValues(inner.values), inner.values.reduce((sum, value) => sum + value.cost, 0), true);
1156
- break;
1157
- }
1158
- whole.push(negate(combine(field, inner.values, inner.whole)));
1159
- break;
1160
- }
1161
- default: {
1162
- const extension = context.operators.get(key);
1163
- if (extension !== void 0) {
1164
- const test = extension.compile(operand2, here);
1165
- if (typeof test !== "function") throw new JqlError(`"${key}" did not build a test, so there is nothing to run`, here);
1166
- const cost = extension.cost ?? 4;
1167
- if (extension.elementwise === false) add(test, cost);
1168
- else addAny(test, cost);
1169
- break;
1170
- }
1171
- const reason2 = QUERY_OPERATORS.includes(key) ? `"${key}" combines whole queries, so it belongs beside field names rather than inside a field's condition` : EXTENSION_NAME.test(key) ? `"${key}" is an added operator, and this query was compiled without it; pass it in \`operators\`` : `"${key}" is not an operator${didYouMean(key, [...FIELD_OPERATORS, ...context.operators.keys()])}`;
1172
- throw new JqlError(reason2, here);
1173
- }
1174
- }
1175
- }
1176
- return { values: values2, whole };
1177
- }
1178
- function allOfValues(values2) {
1179
- const tests = [...values2].sort((a, b) => a.cost - b.cost).map(({ test, negated }) => negated ? (value) => !test(value) : test);
1180
- if (tests.length === 0) return () => true;
1181
- if (tests.length === 1) return tests[0];
1182
- if (tests.length === 2) {
1183
- const [a, b] = tests;
1184
- return (value) => a(value) && b(value);
1185
- }
1186
- return (value) => {
1187
- for (let i = 0; i < tests.length; i++) if (!tests[i](value)) return false;
1188
- return true;
1189
- };
1190
- }
1191
- var isPresent = (value) => value !== void 0;
1192
- function elementwise(test) {
1193
- return (value) => {
1194
- if (test(value)) return true;
1195
- if (!Array.isArray(value)) return false;
1196
- for (let i = 0; i < value.length; i++) if (test(value[i])) return true;
1197
- return false;
1198
- };
1199
- }
1200
- function holds(field, test, cost) {
1201
- const key = field.key;
1202
- if (key !== void 0) {
1203
- const reach2 = field.reach;
1204
- const plain = !needsGuard(key);
1205
- return {
1206
- test: (document) => {
1207
- if (document === null || typeof document !== "object") return test(void 0);
1208
- if (Array.isArray(document)) return reach2(document, test);
1209
- return test(plain && document.__proto__ === PLAIN ? document[key] : readOwn(document, key));
1210
- },
1211
- cost: field.cost + cost
1212
- };
1213
- }
1214
- const read = field.read;
1215
- if (read === readSelf) return { test, cost: field.cost + cost };
1216
- if (read !== void 0) return { test: (document) => test(read(document)), cost: field.cost + cost };
1217
- const reach = field.reach;
1218
- const probe = field.probe;
1219
- if (probe !== void 0) {
1220
- return {
1221
- test: (document) => {
1222
- const value = probe(document);
1223
- return value === FANOUT ? reach(document, test) : test(value);
1224
- },
1225
- cost: field.cost + cost
1226
- };
1227
- }
1228
- return { test: (document) => reach(document, test), cost: field.cost + cost };
1229
- }
1230
- function holdsAny(field, test, negated, cost) {
1231
- const key = field.key;
1232
- if (key === void 0) {
1233
- const read = field.read;
1234
- const single = (value) => {
1235
- if (test(value)) return true;
1236
- if (!Array.isArray(value)) return false;
1237
- for (let i = 0; i < value.length; i++) if (test(value[i])) return true;
1238
- return false;
1239
- };
1240
- return { test: negated ? (document) => !single(read(document)) : (document) => single(read(document)), cost: field.cost + cost };
1241
- }
1242
- const reach = field.reach;
1243
- const plain = !needsGuard(key);
1244
- const any = (value) => {
1245
- if (test(value)) return true;
1246
- if (!Array.isArray(value)) return false;
1247
- for (let i = 0; i < value.length; i++) if (test(value[i])) return true;
1248
- return false;
1249
- };
1250
- const hit = (document) => {
1251
- if (document === null || typeof document !== "object") return test(void 0);
1252
- if (Array.isArray(document)) return reach(document, any);
1253
- return any(plain && document.__proto__ === PLAIN ? document[key] : readOwn(document, key));
1254
- };
1255
- return { test: negated ? (document) => !hit(document) : hit, cost: field.cost + cost };
1256
- }
1257
- function equalsValue(literal2, ignoreCase, at, now) {
1258
- if (!ignoreCase && (typeof literal2 === "string" || typeof literal2 === "number" || typeof literal2 === "boolean")) {
1259
- checkLiteral(literal2, at);
1260
- const wanted = literal2;
1261
- const big = alsoBig(literal2);
1262
- if (big !== void 0) return (value) => value === wanted || value === big || Array.isArray(value) && (value.includes(wanted) || value.includes(big));
1263
- return (value) => value === wanted || Array.isArray(value) && value.includes(wanted);
1264
- }
1265
- return elementwise(equalsTest(literal2, ignoreCase, at, now));
1266
- }
1267
- function equality(field, literal2, ignoreCase, at, now) {
1268
- const key = field.key;
1269
- if (key !== void 0 && !ignoreCase && (typeof literal2 === "string" || typeof literal2 === "number" || typeof literal2 === "boolean")) {
1270
- checkLiteral(literal2, at);
1271
- const wanted = literal2;
1272
- const reach = field.reach;
1273
- const plain = !needsGuard(key);
1274
- const test = equalsValue(literal2, false, at, now);
1275
- const big = alsoBig(literal2);
1276
- if (big !== void 0) {
1277
- return {
1278
- test: (document) => {
1279
- if (document === null || typeof document !== "object") return false;
1280
- if (Array.isArray(document)) return reach(document, test);
1281
- const value = plain && document.__proto__ === PLAIN ? document[key] : readOwn(document, key);
1282
- return value === wanted || value === big || Array.isArray(value) && (value.includes(wanted) || value.includes(big));
1283
- },
1284
- cost: 0
1285
- };
1286
- }
1287
- return {
1288
- test: (document) => {
1289
- if (document === null || typeof document !== "object") return false;
1290
- if (Array.isArray(document)) return reach(document, test);
1291
- const value = plain && document.__proto__ === PLAIN ? document[key] : readOwn(document, key);
1292
- return value === wanted || Array.isArray(value) && value.includes(wanted);
1293
- },
1294
- cost: 0
1295
- };
1296
- }
1297
- const probe = field.probe;
1298
- if (probe !== void 0 && !ignoreCase && (typeof literal2 === "string" || typeof literal2 === "number" || typeof literal2 === "boolean")) {
1299
- checkLiteral(literal2, at);
1300
- const wanted = literal2;
1301
- const test = equalsValue(literal2, false, at, now);
1302
- const reach = field.reach;
1303
- const big = alsoBig(literal2);
1304
- if (big !== void 0) {
1305
- return {
1306
- test: (document) => {
1307
- const value = probe(document);
1308
- if (value === wanted || value === big) return true;
1309
- if (value === FANOUT) return reach(document, test);
1310
- return Array.isArray(value) && (value.includes(wanted) || value.includes(big));
1311
- },
1312
- cost: field.cost
1313
- };
1314
- }
1315
- return {
1316
- test: (document) => {
1317
- const value = probe(document);
1318
- if (value === wanted) return true;
1319
- if (value === FANOUT) return reach(document, test);
1320
- return Array.isArray(value) && value.includes(wanted);
1321
- },
1322
- cost: field.cost
1323
- };
1324
- }
1325
- return holds(field, equalsValue(literal2, ignoreCase, at, now), literal2 !== null && typeof literal2 === "object" ? 3 : 0);
1326
- }
1327
- function sizeTest(operand2, context, at, depth, measures) {
1328
- const strings = measures !== "array";
1329
- let length;
1330
- if (typeof operand2 === "number") {
1331
- if (!Number.isInteger(operand2) || operand2 < 0) throw new JqlError(`a length is a whole number, not ${operand2}`, at);
1332
- length = (size) => size === operand2;
1333
- } else if (isPlainObject(operand2)) {
1334
- length = compileCondition(SELF, operand2, context, at, depth + 1).test;
1335
- } else throw new JqlError(`takes a number or a condition on one, not ${describe(operand2)}`, at);
1336
- if (strings) return (value) => (typeof value === "string" || Array.isArray(value)) && length(value.length);
1337
- return (value) => Array.isArray(value) && length(value.length);
1338
- }
1339
- function compareFields(field, operator, path, negated, context, at) {
1340
- const other = resolveField(path, context, at);
1341
- const compare = comparer(operator);
1342
- const leftRead = field.read;
1343
- const rightRead = other.read;
1344
- let holdsPair;
1345
- if (leftRead !== void 0 && rightRead !== void 0) {
1346
- holdsPair = (document) => eachOf(leftRead(document), (one) => eachOf(rightRead(document), (two) => compare(one, two)));
1347
- } else {
1348
- const left = field.reach;
1349
- const right = other.reach;
1350
- holdsPair = (document) => left(document, (one) => eachOf(one, (a) => right(document, (two) => eachOf(two, (b) => compare(a, b)))));
1351
- }
1352
- return { test: negated ? (document) => !holdsPair(document) : holdsPair, cost: field.cost + other.cost + 4 };
1353
- }
1354
- function comparer(operator) {
1355
- if (operator === "$eq") return (a, b) => a !== void 0 && b !== void 0 && valuesEqual(a, b);
1356
- return (a, b) => {
1357
- if (a === void 0 || b === void 0) return false;
1358
- const order = orderOf(a, b);
1359
- if (order === void 0) return false;
1360
- switch (operator) {
1361
- case "$gt":
1362
- return order > 0;
1363
- case "$gte":
1364
- return order >= 0;
1365
- case "$lt":
1366
- return order < 0;
1367
- default:
1368
- return order <= 0;
1369
- }
1370
- };
1371
- }
1372
- function referencePath(operand2, at) {
1373
- if (!isPlainObject(operand2) || !("$field" in operand2)) return void 0;
1374
- if (typeof operand2.$field !== "string") throw new JqlError(`a {"$field": \u2026} reference takes the path as a string, not ${describe(operand2.$field)}`, at);
1375
- const beside = Object.keys(operand2).filter((key) => key !== "$field");
1376
- if (beside.length > 0) throw new JqlError(`a {"$field": \u2026} reference holds nothing but the path, and "${beside[0]}" is beside it`, at);
1377
- return operand2.$field;
1378
- }
1379
- function eachOf(value, test) {
1380
- if (test(value)) return true;
1381
- if (!Array.isArray(value)) return false;
1382
- for (let i = 0; i < value.length; i++) if (test(value[i])) return true;
1383
- return false;
1384
- }
1385
- function compileText(value, context, at) {
1386
- let search2;
1387
- let fields;
1388
- let caseSensitive = false;
1389
- if (typeof value === "string") search2 = value;
1390
- else if (isPlainObject(value)) {
1391
- for (const key in value) {
1392
- if (key !== "$search" && key !== "$fields" && key !== "$caseSensitive") {
1393
- throw new JqlError(`"${key}" is not part of a text search ($search, $fields, $caseSensitive)${didYouMean(key, ["$search", "$fields", "$caseSensitive"])}`, join(at, key));
1394
- }
1395
- }
1396
- search2 = value.$search;
1397
- fields = value.$fields;
1398
- caseSensitive = "$caseSensitive" in value ? value.$caseSensitive : false;
1399
- } else throw new JqlError(`takes a phrase or { "$search": \u2026 }, not ${describe(value)}`, at);
1400
- if (typeof search2 !== "string") throw new JqlError(`the phrase is a string, not ${describe(search2)}`, join(at, "$search"));
1401
- if (typeof caseSensitive !== "boolean") throw new JqlError(`takes true or false, not ${describe(caseSensitive)}`, join(at, "$caseSensitive"));
1402
- const names = fields === void 0 ? context.vocabulary?.text : fields;
1403
- const reaches = names === void 0 ? void 0 : textFields(names, context, at);
1404
- const needle = caseSensitive ? search2 : search2.toLowerCase();
1405
- if (needle === "") return ALWAYS;
1406
- const found = caseSensitive ? (text2) => text2.includes(needle) : (text2) => text2.toLowerCase().includes(needle);
1407
- const numeric = /\d/.test(needle);
1408
- const maxDepth = context.limits.maxTextDepth;
1409
- const inValue = (item) => containsText(item, found, numeric, maxDepth);
1410
- if (reaches === void 0) return { test: inValue, cost: 20 };
1411
- return {
1412
- test: (document) => {
1413
- for (let i = 0; i < reaches.length; i++) if (reaches[i](document, inValue)) return true;
1414
- return false;
1415
- },
1416
- cost: 6 + reaches.length * 2
1417
- };
1418
- }
1419
- function textFields(names, context, at) {
1420
- if (!Array.isArray(names) || names.length === 0) throw new JqlError(`takes a non-empty list of field names, not ${describe(names)}`, join(at, "$fields"));
1421
- return names.map((name, index) => {
1422
- if (typeof name !== "string") throw new JqlError(`a field name is a string, not ${describe(name)}`, `${join(at, "$fields")}[${index}]`);
1423
- return resolveField(name, context, `${join(at, "$fields")}[${index}]`).reach;
1424
- });
1425
- }
1426
- function containsText(value, found, numeric, depth) {
1427
- if (typeof value === "string") return found(value);
1428
- if (typeof value === "number" || typeof value === "bigint") return numeric && found(String(value));
1429
- if (value === null || typeof value !== "object" || depth <= 0 || value instanceof Date) return false;
1430
- if (Array.isArray(value)) {
1431
- for (let i = 0; i < value.length; i++) if (containsText(value[i], found, numeric, depth - 1)) return true;
1432
- return false;
1433
- }
1434
- if (value instanceof Map || value instanceof Set) {
1435
- for (const item of value.values()) if (containsText(item, found, numeric, depth - 1)) return true;
1436
- return false;
1437
- }
1438
- const record = value;
1439
- for (const key in record) if (Object.hasOwn(record, key) && containsText(record[key], found, numeric, depth - 1)) return true;
1440
- return false;
1441
- }
1442
- function allOf(parts) {
1443
- const real = parts.filter((part) => part !== ALWAYS);
1444
- if (real.includes(NOTHING)) return NOTHING;
1445
- if (real.length === 0) return ALWAYS;
1446
- if (real.length === 1) return real[0];
1447
- real.sort((a, b) => a.cost - b.cost);
1448
- const cost = real.reduce((sum, part) => sum + part.cost, 0);
1449
- const tests = real.map((part) => part.test);
1450
- if (tests.length === 2) {
1451
- const [a, b] = tests;
1452
- return { test: (document) => a(document) && b(document), cost };
1453
- }
1454
- if (tests.length === 3) {
1455
- const [a, b, c] = tests;
1456
- return { test: (document) => a(document) && b(document) && c(document), cost };
1457
- }
1458
- return {
1459
- test: (document) => {
1460
- for (let i = 0; i < tests.length; i++) if (!tests[i](document)) return false;
1461
- return true;
1462
- },
1463
- cost
1464
- };
1465
- }
1466
- function anyOf(parts) {
1467
- const real = parts.filter((part) => part !== NOTHING);
1468
- if (real.includes(ALWAYS)) return ALWAYS;
1469
- if (real.length === 0) return NOTHING;
1470
- if (real.length === 1) return real[0];
1471
- real.sort((a, b) => a.cost - b.cost);
1472
- const cost = real.reduce((sum, part) => sum + part.cost, 0);
1473
- const tests = real.map((part) => part.test);
1474
- if (tests.length === 2) {
1475
- const [a, b] = tests;
1476
- return { test: (document) => a(document) || b(document), cost };
1477
- }
1478
- return {
1479
- test: (document) => {
1480
- for (let i = 0; i < tests.length; i++) if (tests[i](document)) return true;
1481
- return false;
1482
- },
1483
- cost
1484
- };
1485
- }
1486
- function negate(part) {
1487
- if (part === ALWAYS) return NOTHING;
1488
- if (part === NOTHING) return ALWAYS;
1489
- const test = part.test;
1490
- return { test: (document) => !test(document), cost: part.cost };
1491
- }
1492
-
1493
- // src/internal/record.ts
1494
- function setField(target, key, value) {
1495
- if (key === "__proto__") {
1496
- Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
1497
- return;
1498
- }
1499
- target[key] = value;
1500
- }
1501
-
1502
- // src/collections.ts
1503
- function walk3(source, visit) {
1504
- if (Array.isArray(source)) {
1505
- for (let i = 0; i < source.length; i++) if (visit(source[i])) return i;
1506
- return -1;
1507
- }
1508
- if (source instanceof Map) {
1509
- let i = 0;
1510
- for (const item of source.values()) {
1511
- if (visit(item)) return i;
1512
- i++;
1513
- }
1514
- return -1;
1515
- }
1516
- if (typeof source[Symbol.iterator] === "function") {
1517
- let i = 0;
1518
- for (const item of source) {
1519
- if (visit(item)) return i;
1520
- i++;
1521
- }
1522
- return -1;
1523
- }
1524
- const list = source;
1525
- for (let i = 0; i < list.length; i++) if (visit(list[i])) return i;
1526
- return -1;
1527
- }
1528
- function find(source, query, options) {
1529
- const test = compile(query, options);
1530
- let found;
1531
- walk3(source, (item) => {
1532
- if (!test(item)) return false;
1533
- found = item;
1534
- return true;
1535
- });
1536
- return found;
1537
- }
1538
- function findIndex(source, query, options) {
1539
- return walk3(source, compile(query, options));
1540
- }
1541
- function filter(source, query, options) {
1542
- const test = compile(query, options);
1543
- const out = [];
1544
- walk3(source, (item) => {
1545
- if (test(item)) out.push(item);
1546
- return false;
1547
- });
1548
- return out;
1549
- }
1550
- function count2(source, query, options) {
1551
- const test = compile(query, options);
1552
- let total = 0;
1553
- walk3(source, (item) => {
1554
- if (test(item)) total++;
1555
- return false;
1556
- });
1557
- return total;
1558
- }
1559
- function some(source, query, options) {
1560
- return walk3(source, compile(query, options)) !== -1;
1561
- }
1562
- function every(source, query, options) {
1563
- const test = compile(query, options);
1564
- return walk3(source, (item) => !test(item)) === -1;
1565
- }
1566
- function partition(source, query, options) {
1567
- const test = compile(query, options);
1568
- const yes = [];
1569
- const no = [];
1570
- walk3(source, (item) => {
1571
- (test(item) ? yes : no).push(item);
1572
- return false;
1573
- });
1574
- return [yes, no];
1575
- }
1576
- function filterMap(source, query, options) {
1577
- const test = compile(query, options);
1578
- const out = /* @__PURE__ */ new Map();
1579
- for (const [key, value] of source) if (test(value)) out.set(key, value);
1580
- return out;
1581
- }
1582
- function filterRecord(source, query, options) {
1583
- const test = compile(query, options);
1584
- const out = {};
1585
- for (const key of Object.keys(source)) {
1586
- const value = source[key];
1587
- if (test(value)) setField(out, key, value);
1588
- }
1589
- return out;
1590
- }
1591
- function findEntry(source, query, options) {
1592
- const test = compile(query, options);
1593
- if (source instanceof Map) {
1594
- for (const [key, value] of source) if (test(value)) return [key, value];
1595
- return void 0;
1596
- }
1597
- const record = source;
1598
- for (const key of Object.keys(record)) {
1599
- const value = record[key];
1600
- if (test(value)) return [key, value];
1601
- }
1602
- return void 0;
1603
- }
1604
-
1605
- // src/internal/order.ts
1606
- function rank(value) {
1607
- if (value === void 0 || value === null) return 0;
1608
- switch (typeof value) {
1609
- case "number":
1610
- case "bigint":
1611
- return Number.isNaN(value) ? 0 : 1;
1612
- case "string":
1613
- return 2;
1614
- case "boolean":
1615
- return 4;
1616
- default:
1617
- return value instanceof Date ? 5 : 3;
1618
- }
1619
- }
1620
- function compareValues(a, b) {
1621
- const ra = rank(a);
1622
- const rb = rank(b);
1623
- if (ra !== rb) return ra - rb;
1624
- switch (ra) {
1625
- case 1:
1626
- case 2:
1627
- return a < b ? -1 : a > b ? 1 : 0;
1628
- case 4:
1629
- return a === b ? 0 : a ? 1 : -1;
1630
- case 5:
1631
- return a.getTime() - b.getTime();
1632
- default:
1633
- return 0;
1634
- }
1635
- }
1636
- function sortValue(values2, descending, depth = 0) {
1637
- let best;
1638
- let first = true;
1639
- for (const value of values2) {
1640
- if (Array.isArray(value)) {
1641
- if (value.length === 0 || depth >= 16) continue;
1642
- const inner = sortValue(value, descending, depth + 1);
1643
- if (first || (descending ? compareValues(inner, best) > 0 : compareValues(inner, best) < 0)) best = inner;
1644
- first = false;
1645
- continue;
1646
- }
1647
- if (first || (descending ? compareValues(value, best) > 0 : compareValues(value, best) < 0)) best = value;
1648
- first = false;
1649
- }
1650
- return best;
1651
- }
1652
-
1653
- // src/search.ts
1654
- var REQUEST_KEYS = ["where", "sort", "skip", "limit", "fields", "omit"];
1655
- function search(source, request = {}, options = {}) {
1656
- const plan2 = planRequest(request, options);
1657
- const collect2 = plan2.collect();
1658
- const test = plan2.test;
1659
- each(source, (item, index) => {
1660
- if (test !== void 0 && !test(item)) return false;
1661
- return collect2.offer(item, index);
1662
- });
1663
- return plan2.shape(collect2.finish());
1664
- }
1665
- function planRequest(request, options) {
1666
- if (!isPlainObject(request)) throw new JqlError(`a request is an object, not ${describe(request)}`);
1667
- for (const key of Object.keys(request)) {
1668
- if (!REQUEST_KEYS.includes(key)) throw new JqlError(`"${key}" is not part of a request (${REQUEST_KEYS.join(", ")})${didYouMean(key, REQUEST_KEYS)}`, key);
1669
- }
1670
- const vocabulary = checkVocabulary(options.vocabulary);
1671
- const test = request.where === void 0 ? void 0 : compile(request.where, options);
1672
- const skip = count3(request.skip, "skip") ?? 0;
1673
- const limit = count3(request.limit, "limit");
1674
- const keys = sortKeys(request.sort, vocabulary);
1675
- const project = request.fields === void 0 ? void 0 : projector(request.fields, vocabulary);
1676
- const drop = request.omit === void 0 ? void 0 : redactor(request.omit, vocabulary);
1677
- return {
1678
- collect: () => collector(keys, skip, limit),
1679
- test,
1680
- shape: (items) => {
1681
- const projected = project === void 0 ? items : items.map(project);
1682
- return drop === void 0 ? projected : projected.map(drop);
1683
- }
1684
- };
1685
- }
1686
- function collector(keys, skip, limit) {
1687
- return keys.length === 0 ? inOrder(skip, limit) : ranked(keys, skip, limit);
1688
- }
1689
- function count3(value, name) {
1690
- if (value === void 0) return void 0;
1691
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
1692
- throw new JqlError(`is a whole number of items, zero or more, not ${describe(value)}`, name);
1693
- }
1694
- return value;
1695
- }
1696
- function sortKeys(sort, vocabulary) {
1697
- if (sort === void 0) return [];
1698
- if (!isPlainObject(sort)) throw new JqlError(`is an object of field names to directions, not ${describe(sort)}`, "sort");
1699
- return Object.keys(sort).map((name) => {
1700
- const direction = sort[name];
1701
- const at = `sort.${name}`;
1702
- if (direction !== 1 && direction !== -1 && direction !== "asc" && direction !== "desc") {
1703
- throw new JqlError(`a direction is 1, -1, "asc" or "desc", not ${describe(direction)}`, at);
1704
- }
1705
- return { reach: reachField(name, vocabulary, at), descending: direction === -1 || direction === "desc" };
1706
- });
1707
- }
1708
- function each(source, visit) {
1709
- if (Array.isArray(source)) {
1710
- for (let i2 = 0; i2 < source.length; i2++) if (visit(source[i2], i2)) return;
1711
- return;
1712
- }
1713
- const iterable = source instanceof Map ? source.values() : typeof source[Symbol.iterator] === "function" ? source : void 0;
1714
- if (iterable === void 0) {
1715
- const list = source;
1716
- for (let i2 = 0; i2 < list.length; i2++) if (visit(list[i2], i2)) return;
1717
- return;
1718
- }
1719
- let i = 0;
1720
- for (const item of iterable) if (visit(item, i++)) return;
1721
- }
1722
- function inOrder(skip, limit) {
1723
- const out = [];
1724
- let passed = 0;
1725
- return {
1726
- offer(item) {
1727
- if (limit === 0) return true;
1728
- if (passed < skip) {
1729
- passed++;
1730
- return false;
1731
- }
1732
- out.push(item);
1733
- return limit !== void 0 && out.length >= limit;
1734
- },
1735
- finish: () => out
1736
- };
1737
- }
1738
- function ranked(keys, skip, limit) {
1739
- const compare = (a, b) => {
1740
- for (let i = 0; i < keys.length; i++) {
1741
- const order = compareValues(a.keys[i], b.keys[i]);
1742
- if (order !== 0) return keys[i].descending ? -order : order;
1743
- }
1744
- return a.index - b.index;
1745
- };
1746
- const keep = limit === void 0 ? Number.POSITIVE_INFINITY : skip + limit;
1747
- const heap = [];
1748
- return {
1749
- offer(item, index) {
1750
- if (limit === 0) return true;
1751
- const entry = { item, keys: keys.map((key) => keyOf(item, key)), index };
1752
- if (heap.length < keep) {
1753
- heap.push(entry);
1754
- if (keep !== Number.POSITIVE_INFINITY) siftUp(heap, heap.length - 1, compare);
1755
- } else if (compare(entry, heap[0]) < 0) {
1756
- heap[0] = entry;
1757
- siftDown(heap, 0, compare);
1758
- }
1759
- return false;
1760
- },
1761
- finish() {
1762
- heap.sort(compare);
1763
- return heap.slice(skip).map((entry) => entry.item);
1764
- }
1765
- };
1766
- }
1767
- function keyOf(item, key) {
1768
- const values2 = [];
1769
- key.reach(item, (value) => {
1770
- values2.push(value);
1771
- return false;
1772
- });
1773
- return sortValue(values2, key.descending);
1774
- }
1775
- function siftUp(heap, at, compare) {
1776
- let child = at;
1777
- while (child > 0) {
1778
- const parent = child - 1 >> 1;
1779
- if (compare(heap[child], heap[parent]) <= 0) return;
1780
- [heap[child], heap[parent]] = [heap[parent], heap[child]];
1781
- child = parent;
1782
- }
1783
- }
1784
- function siftDown(heap, at, compare) {
1785
- let parent = at;
1786
- for (; ; ) {
1787
- const left = parent * 2 + 1;
1788
- const right = left + 1;
1789
- let largest = parent;
1790
- if (left < heap.length && compare(heap[left], heap[largest]) > 0) largest = left;
1791
- if (right < heap.length && compare(heap[right], heap[largest]) > 0) largest = right;
1792
- if (largest === parent) return;
1793
- [heap[parent], heap[largest]] = [heap[largest], heap[parent]];
1794
- parent = largest;
1795
- }
1796
- }
1797
- function projector(fields, vocabulary) {
1798
- if (!Array.isArray(fields)) throw new JqlError(`is a list of field names, not ${describe(fields)}`, "fields");
1799
- const tree = /* @__PURE__ */ new Map();
1800
- const computed = [];
1801
- fields.forEach((name, index) => {
1802
- const at = `fields[${index}]`;
1803
- if (typeof name !== "string") throw new JqlError(`a field name is a string, not ${describe(name)}`, at);
1804
- const field = vocabulary?.lookup.get(name.toLowerCase());
1805
- if (field?.get !== void 0) {
1806
- computed.push([field.name, field.get]);
1807
- return;
1808
- }
1809
- const keys = splitPath(field?.path ?? name);
1810
- if (typeof keys === "string") throw new JqlError(keys, at);
1811
- let node2 = tree;
1812
- for (let position = 0; position < keys.length; position++) {
1813
- const key = keys[position];
1814
- const existing = node2.get(key);
1815
- if (existing === true) break;
1816
- if (position === keys.length - 1) {
1817
- node2.set(key, true);
1818
- break;
1819
- }
1820
- if (existing === void 0) {
1821
- const child = /* @__PURE__ */ new Map();
1822
- node2.set(key, child);
1823
- node2 = child;
1824
- } else node2 = existing;
1825
- }
1826
- });
1827
- return (item) => {
1828
- const out = pick(item, tree, 0) ?? {};
1829
- for (const [name, get] of computed) setField(out, name, get(item));
1830
- return out;
1831
- };
1832
- }
1833
- function redactor(omit, vocabulary) {
1834
- if (!Array.isArray(omit)) throw new JqlError(`is a list of field names, not ${describe(omit)}`, "omit");
1835
- const tree = /* @__PURE__ */ new Map();
1836
- omit.forEach((name, index) => {
1837
- const at = `omit[${index}]`;
1838
- if (typeof name !== "string") throw new JqlError(`a field name is a string, not ${describe(name)}`, at);
1839
- const field = vocabulary?.lookup.get(name.toLowerCase());
1840
- const keys = field?.get !== void 0 ? [field.name] : splitPath(field?.path ?? name);
1841
- if (typeof keys === "string") throw new JqlError(keys, at);
1842
- let node2 = tree;
1843
- for (let position = 0; position < keys.length; position++) {
1844
- const key = keys[position];
1845
- if (position === keys.length - 1) {
1846
- node2.set(key, true);
1847
- break;
1848
- }
1849
- const existing = node2.get(key);
1850
- if (existing === true) break;
1851
- if (existing === void 0) {
1852
- const child = /* @__PURE__ */ new Map();
1853
- node2.set(key, child);
1854
- node2 = child;
1855
- } else node2 = existing;
1856
- }
1857
- });
1858
- return (item) => without(item, tree, 0);
1859
- }
1860
- var MAX_REDACT_DEPTH = 512;
1861
- function without(value, tree, depth) {
1862
- if (depth > MAX_REDACT_DEPTH) {
1863
- throw new JqlError(`an item nests deeper than ${MAX_REDACT_DEPTH} levels, so it cannot be redacted; nothing was dropped from it`, "omit");
1864
- }
1865
- if (value === null || typeof value !== "object") return value;
1866
- if (Array.isArray(value)) {
1867
- let changed2 = false;
1868
- const copy = value.map((element) => {
1869
- const kept = without(element, tree, depth + 1);
1870
- if (kept !== element) changed2 = true;
1871
- return kept;
1872
- });
1873
- return changed2 ? copy : value;
1874
- }
1875
- if (value instanceof Map) {
1876
- let changed2 = false;
1877
- const copy = /* @__PURE__ */ new Map();
1878
- for (const [key, held] of value) {
1879
- const sub = typeof key === "string" ? tree.get(key) : void 0;
1880
- if (sub === true) {
1881
- changed2 = true;
1882
- continue;
1883
- }
1884
- const kept = sub === void 0 ? held : without(held, sub, depth + 1);
1885
- if (kept !== held) changed2 = true;
1886
- copy.set(key, kept);
1887
- }
1888
- return changed2 ? copy : value;
1889
- }
1890
- const record = value;
1891
- const keys = Object.keys(record);
1892
- if (!keys.some((key) => tree.has(key))) return value;
1893
- const out = {};
1894
- let changed = false;
1895
- for (const key of keys) {
1896
- const sub = tree.get(key);
1897
- if (sub === true) {
1898
- changed = true;
1899
- continue;
1900
- }
1901
- const held = record[key];
1902
- const kept = sub === void 0 ? held : without(held, sub, depth + 1);
1903
- if (kept !== held) changed = true;
1904
- setField(out, key, kept);
1905
- }
1906
- return changed ? out : value;
1907
- }
1908
- function pick(value, tree, depth) {
1909
- if (value === null || typeof value !== "object" || depth > MAX_PATH_SEGMENTS) return void 0;
1910
- const out = {};
1911
- for (const [key, sub] of tree) {
1912
- const found = readOwn(value, key);
1913
- if (found === void 0) continue;
1914
- if (sub === true) setField(out, key, found);
1915
- else if (Array.isArray(found)) setField(out, key, found.map((element) => pick(element, sub, depth + 1)).filter((element) => element !== void 0));
1916
- else {
1917
- const inner = pick(found, sub, depth + 1);
1918
- if (inner !== void 0) setField(out, key, inner);
1919
- }
1920
- }
1921
- return out;
1922
- }
3
+ var chunk2ZMIVDES_cjs = require('./chunk-2ZMIVDES.cjs');
4
+ var chunkEJFHVGBC_cjs = require('./chunk-EJFHVGBC.cjs');
5
+ require('./chunk-ITPY6VTV.cjs');
6
+ var chunk74QKHM6Y_cjs = require('./chunk-74QKHM6Y.cjs');
1923
7
 
1924
8
  // src/group.ts
1925
9
  function group(source, by, options = {}) {
1926
- if (typeof by !== "string") throw new JqlError(`a group is named by a field, not ${describe(by)}`, "by");
10
+ if (typeof by !== "string") throw new chunk74QKHM6Y_cjs.JqlError(`a group is named by a field, not ${chunk74QKHM6Y_cjs.describe(by)}`, "by");
1927
11
  if (options.limit !== void 0 && (!Number.isInteger(options.limit) || options.limit < 0)) {
1928
- throw new JqlError(`is a whole number of groups, zero or more, not ${describe(options.limit)}`, "limit");
12
+ throw new chunk74QKHM6Y_cjs.JqlError(`is a whole number of groups, zero or more, not ${chunk74QKHM6Y_cjs.describe(options.limit)}`, "limit");
1929
13
  }
1930
14
  if (options.items !== void 0 && typeof options.items !== "boolean" && (!Number.isInteger(options.items) || options.items < 0)) {
1931
- throw new JqlError(`is true, false, or how many items to keep, not ${describe(options.items)}`, "items");
15
+ throw new chunk74QKHM6Y_cjs.JqlError(`is true, false, or how many items to keep, not ${chunk74QKHM6Y_cjs.describe(options.items)}`, "items");
1932
16
  }
1933
- const reach = reachField(by, checkVocabulary(options.vocabulary), "by");
1934
- const test = options.where === void 0 ? void 0 : compile(options.where, options);
17
+ const reach = chunk2ZMIVDES_cjs.reachField(by, chunkEJFHVGBC_cjs.checkVocabulary(options.vocabulary), "by");
18
+ const test = options.where === void 0 ? void 0 : chunk2ZMIVDES_cjs.compile(options.where, options);
1935
19
  const keep = options.items === true ? Number.POSITIVE_INFINITY : options.items === void 0 || options.items === false ? 0 : options.items;
1936
20
  const groups = /* @__PURE__ */ new Map();
1937
21
  const keys = [];
@@ -1960,7 +44,7 @@ function group(source, by, options = {}) {
1960
44
  for (let i = 0; i < list.length; i++) visit(list[i]);
1961
45
  }
1962
46
  const byKey = options.sort === "key";
1963
- const found = [...groups.values()].sort((a, b) => byKey ? compareValues(a.key, b.key) : b.count - a.count || compareValues(a.key, b.key));
47
+ const found = [...groups.values()].sort((a, b) => byKey ? chunk2ZMIVDES_cjs.compareValues(a.key, b.key) : b.count - a.count || chunk2ZMIVDES_cjs.compareValues(a.key, b.key));
1964
48
  const limited = options.limit === void 0 ? found : found.slice(0, options.limit);
1965
49
  return limited.map((held) => keep > 0 ? { key: held.key, count: held.count, items: held.items } : { key: held.key, count: held.count });
1966
50
  }
@@ -1978,21 +62,21 @@ function collect(value, into) {
1978
62
  }
1979
63
 
1980
64
  // src/explain.ts
1981
- var FIELD_OPERATOR_SET2 = new Set(FIELD_OPERATORS);
65
+ var FIELD_OPERATOR_SET = new Set(chunk2ZMIVDES_cjs.FIELD_OPERATORS);
1982
66
  function explain(query, item, options = {}) {
1983
67
  return node(query, item, "", options);
1984
68
  }
1985
69
  function matchedBy(clause, item, options) {
1986
- return compile(clause, options)(item);
70
+ return chunk2ZMIVDES_cjs.compile(clause, options)(item);
1987
71
  }
1988
72
  function node(clause, item, at, options) {
1989
- if (typeof clause === "function" || !isPlainObject(clause)) {
73
+ if (typeof clause === "function" || !chunk74QKHM6Y_cjs.isPlainObject(clause)) {
1990
74
  return leaf(clause, item, at, options, typeof clause === "function" ? "a predicate of your own" : "the whole query");
1991
75
  }
1992
76
  const keys = Object.keys(clause);
1993
77
  if (keys.length === 0) return { matched: true, at, clause, because: "an empty query matches everything" };
1994
78
  if (keys.length > 1) {
1995
- const self = keys.filter((key2) => key2 !== "$not" && FIELD_OPERATOR_SET2.has(key2));
79
+ const self = keys.filter((key2) => key2 !== "$not" && FIELD_OPERATOR_SET.has(key2));
1996
80
  const rest = keys.filter((key2) => !self.includes(key2));
1997
81
  const parts = rest.map((key2) => node({ [key2]: clause[key2] }, item, at, options));
1998
82
  if (self.length > 0) {
@@ -2004,7 +88,7 @@ function node(clause, item, at, options) {
2004
88
  }
2005
89
  const key = keys[0];
2006
90
  const value = clause[key];
2007
- const here = join2(at, key);
91
+ const here = join(at, key);
2008
92
  switch (key) {
2009
93
  case "$and":
2010
94
  case "$or":
@@ -2024,10 +108,10 @@ function node(clause, item, at, options) {
2024
108
  };
2025
109
  }
2026
110
  }
2027
- if (!key.startsWith("$") && isPlainObject(value) && !isFieldReference(value) && Object.keys(value).length > 1 && Object.keys(value).every((name) => name.startsWith("$"))) {
111
+ if (!key.startsWith("$") && chunk74QKHM6Y_cjs.isPlainObject(value) && !chunk74QKHM6Y_cjs.isFieldReference(value) && Object.keys(value).length > 1 && Object.keys(value).every((name) => name.startsWith("$"))) {
2028
112
  const operators = Object.keys(value).filter((name) => name !== "$options");
2029
113
  const flags = value.$options === void 0 ? {} : { $options: value.$options };
2030
- const parts = operators.map((name) => leaf({ [key]: { [name]: value[name], ...CASE_AWARE.has(name) ? flags : {} } }, item, join2(here, name), options, key));
114
+ const parts = operators.map((name) => leaf({ [key]: { [name]: value[name], ...chunk2ZMIVDES_cjs.CASE_AWARE.has(name) ? flags : {} } }, item, join(here, name), options, key));
2031
115
  return branch(clause, here, parts, "and");
2032
116
  }
2033
117
  return leaf(clause, item, here, options, key);
@@ -2046,13 +130,13 @@ function leaf(clause, item, at, options, key) {
2046
130
  function reason(clause, item, options, key) {
2047
131
  if (key === "$text") return matchedBy(clause, item, options) ? "the item holds that text" : "no value of the item holds that text";
2048
132
  if (key === "$comment") return "a comment decides nothing";
2049
- if (key.startsWith("$") && FIELD_OPERATOR_SET2.has(key)) return `the item itself is ${values(item === void 0 ? [] : [item])}`;
2050
- if (!isPlainObject(clause)) return "the clause was run as given";
133
+ if (key.startsWith("$") && FIELD_OPERATOR_SET.has(key)) return `the item itself is ${values(item === void 0 ? [] : [item])}`;
134
+ if (!chunk74QKHM6Y_cjs.isPlainObject(clause)) return "the clause was run as given";
2051
135
  const path = Object.keys(clause)[0];
2052
136
  if (path === void 0 || path.startsWith("$")) return "the clause was run as given";
2053
137
  const found = [];
2054
138
  try {
2055
- reachField(path, options.vocabulary, path)(item, (value) => {
139
+ chunk2ZMIVDES_cjs.reachField(path, options.vocabulary, path)(item, (value) => {
2056
140
  if (found.length < 4) found.push(value);
2057
141
  return false;
2058
142
  });
@@ -2076,7 +160,7 @@ function shorten(value) {
2076
160
  }
2077
161
  return text2.length > 60 ? `${text2.slice(0, 60)}\u2026` : text2;
2078
162
  }
2079
- function join2(at, key) {
163
+ function join(at, key) {
2080
164
  return at === "" ? key : `${at}.${key}`;
2081
165
  }
2082
166
 
@@ -2086,15 +170,15 @@ var QUERIES = /* @__PURE__ */ new Set(["$elemMatch"]);
2086
170
  var LOGIC = /* @__PURE__ */ new Set(["$and", "$or", "$nor"]);
2087
171
  function canonical(query, options) {
2088
172
  if (typeof query === "function") throw new TypeError("a compiled predicate has no canonical form: it is code, not a query");
2089
- compile(query, options);
173
+ chunk2ZMIVDES_cjs.compile(query, options);
2090
174
  return rewrite(query);
2091
175
  }
2092
176
  function fingerprint(query, options) {
2093
177
  return checksum(JSON.stringify(canonical(query, options)) ?? "");
2094
178
  }
2095
179
  function rewrite(value) {
2096
- if (!isPlainObject(value)) return value;
2097
- if (isDateLiteral(value) || isFieldReference(value)) return value;
180
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value)) return value;
181
+ if (chunk74QKHM6Y_cjs.isDateLiteral(value) || chunk74QKHM6Y_cjs.isFieldReference(value)) return value;
2098
182
  const out = {};
2099
183
  const keys = Object.keys(value).sort().filter((key) => key !== "$comment");
2100
184
  const alone = keys.length === 1;
@@ -2129,7 +213,7 @@ function fold(out) {
2129
213
  const lifted = {};
2130
214
  const kept = [];
2131
215
  for (const part of parts) {
2132
- const keys = isPlainObject(part) ? Object.keys(part) : void 0;
216
+ const keys = chunk74QKHM6Y_cjs.isPlainObject(part) ? Object.keys(part) : void 0;
2133
217
  if (keys === void 0 || keys.length === 0 || keys.some((key) => taken.has(key))) {
2134
218
  kept.push(part);
2135
219
  continue;
@@ -2148,7 +232,7 @@ function fold(out) {
2148
232
  return sorted;
2149
233
  }
2150
234
  function condition(value) {
2151
- if (isPlainObject(value) && !isDateLiteral(value) && !isFieldReference(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => key.startsWith("$"))) {
235
+ if (chunk74QKHM6Y_cjs.isPlainObject(value) && !chunk74QKHM6Y_cjs.isDateLiteral(value) && !chunk74QKHM6Y_cjs.isFieldReference(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => key.startsWith("$"))) {
2152
236
  const out = {};
2153
237
  for (const key of Object.keys(value).sort()) out[key] = key === "$not" ? condition(value[key]) : operand(key, value[key]);
2154
238
  return out;
@@ -2163,18 +247,18 @@ function operand(key, value) {
2163
247
  return types.length === 1 ? types[0] : types;
2164
248
  }
2165
249
  if (key === "$options" && typeof value === "string") return [...value].sort().join("");
2166
- if ((key === "$size" || key === "$length") && isPlainObject(value)) return condition(value);
250
+ if ((key === "$size" || key === "$length") && chunk74QKHM6Y_cjs.isPlainObject(value)) return condition(value);
2167
251
  return literal(value);
2168
252
  }
2169
253
  function literal(value) {
2170
254
  if (Array.isArray(value)) return value.map(literal);
2171
- if (!isPlainObject(value) || isDateLiteral(value) || isFieldReference(value)) return value;
255
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value) || chunk74QKHM6Y_cjs.isDateLiteral(value) || chunk74QKHM6Y_cjs.isFieldReference(value)) return value;
2172
256
  const out = {};
2173
257
  for (const key of Object.keys(value).sort()) out[key] = literal(value[key]);
2174
258
  return out;
2175
259
  }
2176
260
  function text(value) {
2177
- const search2 = typeof value === "string" ? { $search: value } : isPlainObject(value) ? value : void 0;
261
+ const search2 = typeof value === "string" ? { $search: value } : chunk74QKHM6Y_cjs.isPlainObject(value) ? value : void 0;
2178
262
  if (search2 === void 0) return value;
2179
263
  const out = { $search: search2.$search };
2180
264
  if (Array.isArray(search2.$fields)) out.$fields = unique(search2.$fields);
@@ -2185,7 +269,7 @@ function flatten(key, parts) {
2185
269
  if (key === "$nor") return [...parts];
2186
270
  const out = [];
2187
271
  for (const part of parts) {
2188
- const inner = isPlainObject(part) && Object.keys(part).length === 1 ? part[key] : void 0;
272
+ const inner = chunk74QKHM6Y_cjs.isPlainObject(part) && Object.keys(part).length === 1 ? part[key] : void 0;
2189
273
  if (Array.isArray(inner)) out.push(...flatten(key, inner));
2190
274
  else out.push(part);
2191
275
  }
@@ -2216,10 +300,10 @@ function checksum(text2) {
2216
300
  }
2217
301
 
2218
302
  // src/plan.ts
2219
- var KNOWN = /* @__PURE__ */ new Set([...FIELD_OPERATORS, ...QUERY_OPERATORS, "$field"]);
303
+ var KNOWN = /* @__PURE__ */ new Set([...chunk2ZMIVDES_cjs.FIELD_OPERATORS, ...chunk2ZMIVDES_cjs.QUERY_OPERATORS, "$field"]);
2220
304
  function plan(query, capabilities, options = {}) {
2221
305
  if (typeof query === "function") throw new TypeError("a compiled predicate cannot be split: it is code, not a query");
2222
- const verdict = validate(query, options);
306
+ const verdict = chunk2ZMIVDES_cjs.validate(query, options);
2223
307
  if (!verdict.valid) throw verdict.error;
2224
308
  const now = options.now === void 0 ? Date.now() : options.now();
2225
309
  const vocabulary = options.vocabulary;
@@ -2246,8 +330,8 @@ function plan(query, capabilities, options = {}) {
2246
330
  }
2247
331
  }
2248
332
  return {
2249
- pushed: join3(pushed),
2250
- remaining: join3(stays),
333
+ pushed: join2(pushed),
334
+ remaining: join2(stays),
2251
335
  complete: stays.length === 0,
2252
336
  kept
2253
337
  };
@@ -2259,7 +343,7 @@ function conjuncts(query, at) {
2259
343
  if (key === "$comment") continue;
2260
344
  if (key === "$and" && Array.isArray(value)) {
2261
345
  value.forEach((part, index) => {
2262
- if (isPlainObject(part)) out.push(...conjuncts(part, `${here}[${index}]`));
346
+ if (chunk74QKHM6Y_cjs.isPlainObject(part)) out.push(...conjuncts(part, `${here}[${index}]`));
2263
347
  });
2264
348
  continue;
2265
349
  }
@@ -2267,7 +351,7 @@ function conjuncts(query, at) {
2267
351
  }
2268
352
  return out;
2269
353
  }
2270
- function join3(parts) {
354
+ function join2(parts) {
2271
355
  if (parts.length === 0) return void 0;
2272
356
  const query = parts.length === 1 ? parts[0] : { $and: parts };
2273
357
  return query;
@@ -2289,7 +373,7 @@ function unpushableOperator(key, value, context, at) {
2289
373
  case "$and":
2290
374
  if (!Array.isArray(value)) return "the clause is malformed";
2291
375
  for (const part of value) {
2292
- if (!isPlainObject(part)) return "the clause is malformed";
376
+ if (!chunk74QKHM6Y_cjs.isPlainObject(part)) return "the clause is malformed";
2293
377
  const why = unpushable(part, context);
2294
378
  if (why !== void 0) return why;
2295
379
  }
@@ -2301,7 +385,7 @@ function unpushableOperator(key, value, context, at) {
2301
385
  if (!context.or && key === "$nor") return "the store cannot answer an $or";
2302
386
  if (!Array.isArray(value) || value.length === 0) return "the clause is malformed";
2303
387
  for (const part of value) {
2304
- if (!isPlainObject(part)) return "the clause is malformed";
388
+ if (!chunk74QKHM6Y_cjs.isPlainObject(part)) return "the clause is malformed";
2305
389
  const why = unpushable(part, context);
2306
390
  if (why !== void 0) return why;
2307
391
  }
@@ -2309,7 +393,7 @@ function unpushableOperator(key, value, context, at) {
2309
393
  }
2310
394
  case "$not": {
2311
395
  if (!context.not) return "the store cannot answer a negation";
2312
- if (!isPlainObject(value)) return "the clause is malformed";
396
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value)) return "the clause is malformed";
2313
397
  return unpushable(value, context);
2314
398
  }
2315
399
  case "$text":
@@ -2323,8 +407,8 @@ function unpushableField(name, value, context, at) {
2323
407
  if (field?.get !== void 0) return `"${name}" is computed here, so the store has no such field`;
2324
408
  const stored = storedName(name, context);
2325
409
  if (context.fields !== "all" && !context.fields.has(stored)) return `the store cannot filter on "${stored}"`;
2326
- if (isFieldReference(value)) return allows(context, "$field") ? void 0 : "the store cannot compare two fields";
2327
- if (!isPlainObject(value) || isDateLiteral(value)) {
410
+ if (chunk74QKHM6Y_cjs.isFieldReference(value)) return allows(context, "$field") ? void 0 : "the store cannot compare two fields";
411
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value) || chunk74QKHM6Y_cjs.isDateLiteral(value)) {
2328
412
  if (!allows(context, "$eq")) return 'the store cannot answer "$eq"';
2329
413
  return accepted(context, stored, { $eq: value });
2330
414
  }
@@ -2341,14 +425,14 @@ function unpushableField(name, value, context, at) {
2341
425
  return "the store cannot answer a negation";
2342
426
  }
2343
427
  const operand2 = value[key];
2344
- if (isFieldReference(operand2) && !allows(context, "$field")) return "the store cannot compare two fields";
428
+ if (chunk74QKHM6Y_cjs.isFieldReference(operand2) && !allows(context, "$field")) return "the store cannot compare two fields";
2345
429
  if (key === "$elemMatch") {
2346
- if (!isPlainObject(operand2)) return "the clause is malformed";
430
+ if (!chunk74QKHM6Y_cjs.isPlainObject(operand2)) return "the clause is malformed";
2347
431
  const why = unpushable(operand2, context);
2348
432
  if (why !== void 0) return why;
2349
433
  }
2350
434
  if (key === "$not") {
2351
- if (!isPlainObject(operand2)) return "the clause is malformed";
435
+ if (!chunk74QKHM6Y_cjs.isPlainObject(operand2)) return "the clause is malformed";
2352
436
  const why = unpushableField(name, operand2, context);
2353
437
  if (why !== void 0) return why;
2354
438
  }
@@ -2363,7 +447,7 @@ function allows(context, operator) {
2363
447
  return context.operators === "all" || context.operators.has(operator);
2364
448
  }
2365
449
  function resolve(value, context) {
2366
- if (!isPlainObject(value)) return value;
450
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value)) return value;
2367
451
  const out = {};
2368
452
  for (const [key, held] of Object.entries(value)) {
2369
453
  switch (key) {
@@ -2387,8 +471,8 @@ function resolve(value, context) {
2387
471
  return out;
2388
472
  }
2389
473
  function resolveCondition(value, context) {
2390
- if (!isPlainObject(value)) return resolveLiteral(value, context);
2391
- if (isDateLiteral(value) || isFieldReference(value)) return resolveOperand("$eq", value, context);
474
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value)) return resolveLiteral(value, context);
475
+ if (chunk74QKHM6Y_cjs.isDateLiteral(value) || chunk74QKHM6Y_cjs.isFieldReference(value)) return resolveOperand("$eq", value, context);
2392
476
  const keys = Object.keys(value);
2393
477
  if (keys.length === 0 || !keys.every((key) => key.startsWith("$"))) return resolveLiteral(value, context);
2394
478
  const out = {};
@@ -2398,20 +482,20 @@ function resolveCondition(value, context) {
2398
482
  function resolveOperand(key, operand2, context) {
2399
483
  if (key === "$elemMatch") return resolve(operand2, context);
2400
484
  if (key === "$not") return resolveCondition(operand2, context);
2401
- if (isFieldReference(operand2)) return { $field: storedName(operand2.$field, context) };
2402
- if (Array.isArray(operand2)) return operand2.map((item) => isFieldReference(item) ? { $field: storedName(item.$field, context) } : resolveLiteral(item, context));
485
+ if (chunk74QKHM6Y_cjs.isFieldReference(operand2)) return { $field: storedName(operand2.$field, context) };
486
+ if (Array.isArray(operand2)) return operand2.map((item) => chunk74QKHM6Y_cjs.isFieldReference(item) ? { $field: storedName(item.$field, context) } : resolveLiteral(item, context));
2403
487
  return resolveLiteral(operand2, context);
2404
488
  }
2405
489
  function resolveText(value, context) {
2406
- if (!isPlainObject(value) || !Array.isArray(value.$fields)) return value;
490
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value) || !Array.isArray(value.$fields)) return value;
2407
491
  return { ...value, $fields: value.$fields.map((name) => typeof name === "string" ? storedName(name, context) : name) };
2408
492
  }
2409
493
  function resolveLiteral(value, context) {
2410
494
  if (Array.isArray(value)) return value.map((item) => resolveLiteral(item, context));
2411
- if (!isPlainObject(value)) return value;
2412
- if (isDateLiteral(value)) {
2413
- const time = resolveDate(value.$date, context.now);
2414
- if (Number.isNaN(time)) throw new JqlError(`${JSON.stringify(value.$date)} is not a date`);
495
+ if (!chunk74QKHM6Y_cjs.isPlainObject(value)) return value;
496
+ if (chunk74QKHM6Y_cjs.isDateLiteral(value)) {
497
+ const time = chunk74QKHM6Y_cjs.resolveDate(value.$date, context.now);
498
+ if (Number.isNaN(time)) throw new chunk74QKHM6Y_cjs.JqlError(`${JSON.stringify(value.$date)} is not a date`);
2415
499
  return { $date: time };
2416
500
  }
2417
501
  const out = {};
@@ -2452,7 +536,7 @@ async function* iterate(source) {
2452
536
  for (let i = 0; i < list.length; i++) yield list[i];
2453
537
  }
2454
538
  async function* filterStream(source, query, options) {
2455
- const test = compile(query, options);
539
+ const test = chunk2ZMIVDES_cjs.compile(query, options);
2456
540
  for await (const item of iterate(source)) if (test(item)) yield item;
2457
541
  }
2458
542
  async function findAsync(source, query, options) {
@@ -2466,22 +550,22 @@ async function filterAsync(source, query, options) {
2466
550
  }
2467
551
  async function countAsync(source, query, options) {
2468
552
  let total = 0;
2469
- const test = compile(query, options);
553
+ const test = chunk2ZMIVDES_cjs.compile(query, options);
2470
554
  for await (const item of iterate(source)) if (test(item)) total++;
2471
555
  return total;
2472
556
  }
2473
557
  async function someAsync(source, query, options) {
2474
- const test = compile(query, options);
558
+ const test = chunk2ZMIVDES_cjs.compile(query, options);
2475
559
  for await (const item of iterate(source)) if (test(item)) return true;
2476
560
  return false;
2477
561
  }
2478
562
  async function everyAsync(source, query, options) {
2479
- const test = compile(query, options);
563
+ const test = chunk2ZMIVDES_cjs.compile(query, options);
2480
564
  for await (const item of iterate(source)) if (!test(item)) return false;
2481
565
  return true;
2482
566
  }
2483
567
  async function searchAsync(source, request = {}, options = {}) {
2484
- const plan2 = planRequest(request, options);
568
+ const plan2 = chunk2ZMIVDES_cjs.planRequest(request, options);
2485
569
  const collect2 = plan2.collect();
2486
570
  let index = 0;
2487
571
  for await (const item of iterate(source)) {
@@ -2492,38 +576,101 @@ async function searchAsync(source, request = {}, options = {}) {
2492
576
  return plan2.shape(collect2.finish());
2493
577
  }
2494
578
 
2495
- exports.DEFAULT_LIMITS = DEFAULT_LIMITS;
2496
- exports.FIELD_OPERATORS = FIELD_OPERATORS;
2497
- exports.JqlError = JqlError;
2498
- exports.QUERY_OPERATORS = QUERY_OPERATORS;
2499
- exports.UNTRUSTED_LIMITS = UNTRUSTED_LIMITS;
579
+ Object.defineProperty(exports, "DEFAULT_LIMITS", {
580
+ enumerable: true,
581
+ get: function () { return chunk2ZMIVDES_cjs.DEFAULT_LIMITS; }
582
+ });
583
+ Object.defineProperty(exports, "FIELD_OPERATORS", {
584
+ enumerable: true,
585
+ get: function () { return chunk2ZMIVDES_cjs.FIELD_OPERATORS; }
586
+ });
587
+ Object.defineProperty(exports, "QUERY_OPERATORS", {
588
+ enumerable: true,
589
+ get: function () { return chunk2ZMIVDES_cjs.QUERY_OPERATORS; }
590
+ });
591
+ Object.defineProperty(exports, "UNTRUSTED_LIMITS", {
592
+ enumerable: true,
593
+ get: function () { return chunk2ZMIVDES_cjs.UNTRUSTED_LIMITS; }
594
+ });
595
+ Object.defineProperty(exports, "compile", {
596
+ enumerable: true,
597
+ get: function () { return chunk2ZMIVDES_cjs.compile; }
598
+ });
599
+ Object.defineProperty(exports, "count", {
600
+ enumerable: true,
601
+ get: function () { return chunk2ZMIVDES_cjs.count; }
602
+ });
603
+ Object.defineProperty(exports, "every", {
604
+ enumerable: true,
605
+ get: function () { return chunk2ZMIVDES_cjs.every; }
606
+ });
607
+ Object.defineProperty(exports, "filter", {
608
+ enumerable: true,
609
+ get: function () { return chunk2ZMIVDES_cjs.filter; }
610
+ });
611
+ Object.defineProperty(exports, "filterMap", {
612
+ enumerable: true,
613
+ get: function () { return chunk2ZMIVDES_cjs.filterMap; }
614
+ });
615
+ Object.defineProperty(exports, "filterRecord", {
616
+ enumerable: true,
617
+ get: function () { return chunk2ZMIVDES_cjs.filterRecord; }
618
+ });
619
+ Object.defineProperty(exports, "find", {
620
+ enumerable: true,
621
+ get: function () { return chunk2ZMIVDES_cjs.find; }
622
+ });
623
+ Object.defineProperty(exports, "findEntry", {
624
+ enumerable: true,
625
+ get: function () { return chunk2ZMIVDES_cjs.findEntry; }
626
+ });
627
+ Object.defineProperty(exports, "findIndex", {
628
+ enumerable: true,
629
+ get: function () { return chunk2ZMIVDES_cjs.findIndex; }
630
+ });
631
+ Object.defineProperty(exports, "matches", {
632
+ enumerable: true,
633
+ get: function () { return chunk2ZMIVDES_cjs.matches; }
634
+ });
635
+ Object.defineProperty(exports, "partition", {
636
+ enumerable: true,
637
+ get: function () { return chunk2ZMIVDES_cjs.partition; }
638
+ });
639
+ Object.defineProperty(exports, "search", {
640
+ enumerable: true,
641
+ get: function () { return chunk2ZMIVDES_cjs.search; }
642
+ });
643
+ Object.defineProperty(exports, "some", {
644
+ enumerable: true,
645
+ get: function () { return chunk2ZMIVDES_cjs.some; }
646
+ });
647
+ Object.defineProperty(exports, "untyped", {
648
+ enumerable: true,
649
+ get: function () { return chunk2ZMIVDES_cjs.untyped; }
650
+ });
651
+ Object.defineProperty(exports, "validate", {
652
+ enumerable: true,
653
+ get: function () { return chunk2ZMIVDES_cjs.validate; }
654
+ });
655
+ Object.defineProperty(exports, "defineVocabulary", {
656
+ enumerable: true,
657
+ get: function () { return chunkEJFHVGBC_cjs.defineVocabulary; }
658
+ });
659
+ Object.defineProperty(exports, "JqlError", {
660
+ enumerable: true,
661
+ get: function () { return chunk74QKHM6Y_cjs.JqlError; }
662
+ });
2500
663
  exports.canonical = canonical;
2501
- exports.compile = compile;
2502
- exports.count = count2;
2503
664
  exports.countAsync = countAsync;
2504
- exports.defineVocabulary = defineVocabulary;
2505
- exports.every = every;
2506
665
  exports.everyAsync = everyAsync;
2507
666
  exports.explain = explain;
2508
- exports.filter = filter;
2509
667
  exports.filterAsync = filterAsync;
2510
- exports.filterMap = filterMap;
2511
- exports.filterRecord = filterRecord;
2512
668
  exports.filterStream = filterStream;
2513
- exports.find = find;
2514
669
  exports.findAsync = findAsync;
2515
- exports.findEntry = findEntry;
2516
- exports.findIndex = findIndex;
2517
670
  exports.fingerprint = fingerprint;
2518
671
  exports.group = group;
2519
- exports.matches = matches;
2520
- exports.partition = partition;
2521
672
  exports.plan = plan;
2522
- exports.search = search;
2523
673
  exports.searchAsync = searchAsync;
2524
- exports.some = some;
2525
674
  exports.someAsync = someAsync;
2526
- exports.untyped = untyped;
2527
- exports.validate = validate;
2528
675
  //# sourceMappingURL=index.cjs.map
2529
676
  //# sourceMappingURL=index.cjs.map