@osqd/jql 0.1.1

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 (115) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/LICENSE +102 -0
  3. package/README.md +84 -0
  4. package/bin/jql.mjs +5 -0
  5. package/conformance/cases.json +290 -0
  6. package/dist/array.d.ts +11 -0
  7. package/dist/async.d.ts +44 -0
  8. package/dist/canonical.d.ts +18 -0
  9. package/dist/cjs/array.d.ts +11 -0
  10. package/dist/cjs/async.d.ts +44 -0
  11. package/dist/cjs/canonical.d.ts +18 -0
  12. package/dist/cjs/cli.d.ts +15 -0
  13. package/dist/cjs/collections.d.ts +34 -0
  14. package/dist/cjs/core.d.ts +117 -0
  15. package/dist/cjs/errors.d.ts +17 -0
  16. package/dist/cjs/explain.d.ts +30 -0
  17. package/dist/cjs/global.d.ts +90 -0
  18. package/dist/cjs/group.d.ts +47 -0
  19. package/dist/cjs/index.d.ts +25 -0
  20. package/dist/cjs/internal/closest.d.ts +9 -0
  21. package/dist/cjs/internal/duration.d.ts +15 -0
  22. package/dist/cjs/internal/equal.d.ts +34 -0
  23. package/dist/cjs/internal/glob.d.ts +30 -0
  24. package/dist/cjs/internal/order.d.ts +24 -0
  25. package/dist/cjs/internal/path.d.ts +109 -0
  26. package/dist/cjs/internal/record.d.ts +18 -0
  27. package/dist/cjs/internal/values.d.ts +41 -0
  28. package/dist/cjs/limits.d.ts +64 -0
  29. package/dist/cjs/operators.d.ts +81 -0
  30. package/dist/cjs/package.json +3 -0
  31. package/dist/cjs/plan.d.ts +79 -0
  32. package/dist/cjs/search.d.ts +42 -0
  33. package/dist/cjs/targets/mongo.d.ts +55 -0
  34. package/dist/cjs/text/index.d.ts +12 -0
  35. package/dist/cjs/text/parse.d.ts +91 -0
  36. package/dist/cjs/text/suggest.d.ts +16 -0
  37. package/dist/cjs/text/write.d.ts +34 -0
  38. package/dist/cjs/types.d.ts +236 -0
  39. package/dist/cjs/vocabulary.d.ts +106 -0
  40. package/dist/cli.d.ts +15 -0
  41. package/dist/cli.js +2729 -0
  42. package/dist/cli.js.map +1 -0
  43. package/dist/collections.d.ts +34 -0
  44. package/dist/core.d.ts +117 -0
  45. package/dist/errors.d.ts +17 -0
  46. package/dist/explain.d.ts +30 -0
  47. package/dist/global.cjs +1953 -0
  48. package/dist/global.cjs.map +1 -0
  49. package/dist/global.d.ts +90 -0
  50. package/dist/global.js +1950 -0
  51. package/dist/global.js.map +1 -0
  52. package/dist/group.d.ts +47 -0
  53. package/dist/index.cjs +2529 -0
  54. package/dist/index.cjs.map +1 -0
  55. package/dist/index.d.ts +25 -0
  56. package/dist/index.js +2495 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/internal/closest.d.ts +9 -0
  59. package/dist/internal/duration.d.ts +15 -0
  60. package/dist/internal/equal.d.ts +34 -0
  61. package/dist/internal/glob.d.ts +30 -0
  62. package/dist/internal/order.d.ts +24 -0
  63. package/dist/internal/path.d.ts +109 -0
  64. package/dist/internal/record.d.ts +18 -0
  65. package/dist/internal/values.d.ts +41 -0
  66. package/dist/limits.d.ts +64 -0
  67. package/dist/mongo.cjs +357 -0
  68. package/dist/mongo.cjs.map +1 -0
  69. package/dist/mongo.js +354 -0
  70. package/dist/mongo.js.map +1 -0
  71. package/dist/operators.d.ts +81 -0
  72. package/dist/plan.d.ts +79 -0
  73. package/dist/search.d.ts +42 -0
  74. package/dist/targets/mongo.d.ts +55 -0
  75. package/dist/text/index.d.ts +12 -0
  76. package/dist/text/parse.d.ts +91 -0
  77. package/dist/text/suggest.d.ts +16 -0
  78. package/dist/text/write.d.ts +34 -0
  79. package/dist/text.cjs +674 -0
  80. package/dist/text.cjs.map +1 -0
  81. package/dist/text.js +667 -0
  82. package/dist/text.js.map +1 -0
  83. package/dist/types.d.ts +236 -0
  84. package/dist/vocabulary.d.ts +106 -0
  85. package/docs/course/01-first-query.md +217 -0
  86. package/docs/course/02-operators.md +285 -0
  87. package/docs/course/03-arrays-and-paths.md +239 -0
  88. package/docs/course/04-combining.md +221 -0
  89. package/docs/course/05-dates.md +214 -0
  90. package/docs/course/06-typed-queries.md +240 -0
  91. package/docs/course/07-requests.md +261 -0
  92. package/docs/course/08-grouping.md +210 -0
  93. package/docs/course/09-explaining.md +171 -0
  94. package/docs/course/10-vocabulary.md +276 -0
  95. package/docs/course/11-the-search-box.md +349 -0
  96. package/docs/course/12-untrusted.md +257 -0
  97. package/docs/course/13-saved-filters.md +199 -0
  98. package/docs/course/14-streams-and-cli.md +276 -0
  99. package/docs/course/15-pushdown.md +240 -0
  100. package/docs/course/16-extending.md +199 -0
  101. package/docs/course/index.md +185 -0
  102. package/docs/design/decisions.md +198 -0
  103. package/docs/design/performance.md +102 -0
  104. package/docs/guides/adopting.md +81 -0
  105. package/docs/guides/pushdown.md +147 -0
  106. package/docs/guides/typescript.md +115 -0
  107. package/docs/guides/untrusted-input.md +86 -0
  108. package/docs/index.md +102 -0
  109. package/docs/reference/api.md +266 -0
  110. package/docs/reference/cli.md +103 -0
  111. package/docs/reference/index.md +12 -0
  112. package/docs/reference/specification.md +549 -0
  113. package/docs/reference/text-syntax.md +152 -0
  114. package/docs/start/quick-start.md +84 -0
  115. package/package.json +136 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2529 @@
1
+ 'use strict';
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
+ }
1923
+
1924
+ // src/group.ts
1925
+ function group(source, by, options = {}) {
1926
+ if (typeof by !== "string") throw new JqlError(`a group is named by a field, not ${describe(by)}`, "by");
1927
+ 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");
1929
+ }
1930
+ 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");
1932
+ }
1933
+ const reach = reachField(by, checkVocabulary(options.vocabulary), "by");
1934
+ const test = options.where === void 0 ? void 0 : compile(options.where, options);
1935
+ const keep = options.items === true ? Number.POSITIVE_INFINITY : options.items === void 0 || options.items === false ? 0 : options.items;
1936
+ const groups = /* @__PURE__ */ new Map();
1937
+ const keys = [];
1938
+ const visit = (item) => {
1939
+ if (test !== void 0 && !test(item)) return;
1940
+ keys.length = 0;
1941
+ reach(item, (value) => {
1942
+ collect(value, keys);
1943
+ return false;
1944
+ });
1945
+ for (const key of keys) {
1946
+ let held = groups.get(key);
1947
+ if (held === void 0) {
1948
+ held = { key, count: 0, items: [] };
1949
+ groups.set(key, held);
1950
+ }
1951
+ held.count++;
1952
+ if (held.items.length < keep) held.items.push(item);
1953
+ }
1954
+ };
1955
+ if (Array.isArray(source)) for (let i = 0; i < source.length; i++) visit(source[i]);
1956
+ else if (source instanceof Map) for (const item of source.values()) visit(item);
1957
+ else if (typeof source[Symbol.iterator] === "function") for (const item of source) visit(item);
1958
+ else {
1959
+ const list = source;
1960
+ for (let i = 0; i < list.length; i++) visit(list[i]);
1961
+ }
1962
+ 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));
1964
+ const limited = options.limit === void 0 ? found : found.slice(0, options.limit);
1965
+ return limited.map((held) => keep > 0 ? { key: held.key, count: held.count, items: held.items } : { key: held.key, count: held.count });
1966
+ }
1967
+ function collect(value, into) {
1968
+ if (Array.isArray(value)) {
1969
+ if (value.length === 0) {
1970
+ if (!into.includes(null)) into.push(null);
1971
+ return;
1972
+ }
1973
+ for (const element of value) collect(element, into);
1974
+ return;
1975
+ }
1976
+ const key = value === void 0 || value === null || typeof value === "object" ? null : value;
1977
+ if (!into.includes(key)) into.push(key);
1978
+ }
1979
+
1980
+ // src/explain.ts
1981
+ var FIELD_OPERATOR_SET2 = new Set(FIELD_OPERATORS);
1982
+ function explain(query, item, options = {}) {
1983
+ return node(query, item, "", options);
1984
+ }
1985
+ function matchedBy(clause, item, options) {
1986
+ return compile(clause, options)(item);
1987
+ }
1988
+ function node(clause, item, at, options) {
1989
+ if (typeof clause === "function" || !isPlainObject(clause)) {
1990
+ return leaf(clause, item, at, options, typeof clause === "function" ? "a predicate of your own" : "the whole query");
1991
+ }
1992
+ const keys = Object.keys(clause);
1993
+ if (keys.length === 0) return { matched: true, at, clause, because: "an empty query matches everything" };
1994
+ if (keys.length > 1) {
1995
+ const self = keys.filter((key2) => key2 !== "$not" && FIELD_OPERATOR_SET2.has(key2));
1996
+ const rest = keys.filter((key2) => !self.includes(key2));
1997
+ const parts = rest.map((key2) => node({ [key2]: clause[key2] }, item, at, options));
1998
+ if (self.length > 0) {
1999
+ const whole = {};
2000
+ for (const key2 of self) whole[key2] = clause[key2];
2001
+ parts.push(leaf(whole, item, at, options, self[0]));
2002
+ }
2003
+ return branch(clause, at, parts, "and");
2004
+ }
2005
+ const key = keys[0];
2006
+ const value = clause[key];
2007
+ const here = join2(at, key);
2008
+ switch (key) {
2009
+ case "$and":
2010
+ case "$or":
2011
+ case "$nor": {
2012
+ if (!Array.isArray(value)) break;
2013
+ const parts = value.map((part, index) => node(part, item, `${here}[${index}]`, options));
2014
+ return branch(clause, here, parts, key === "$and" ? "and" : key === "$or" ? "or" : "nor");
2015
+ }
2016
+ case "$not": {
2017
+ const inner = node(value, item, here, options);
2018
+ return {
2019
+ matched: !inner.matched,
2020
+ at: here,
2021
+ clause,
2022
+ because: inner.matched ? "what it negates holds" : "what it negates does not hold",
2023
+ parts: [inner]
2024
+ };
2025
+ }
2026
+ }
2027
+ if (!key.startsWith("$") && isPlainObject(value) && !isFieldReference(value) && Object.keys(value).length > 1 && Object.keys(value).every((name) => name.startsWith("$"))) {
2028
+ const operators = Object.keys(value).filter((name) => name !== "$options");
2029
+ 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));
2031
+ return branch(clause, here, parts, "and");
2032
+ }
2033
+ return leaf(clause, item, here, options, key);
2034
+ }
2035
+ function branch(clause, at, parts, kind) {
2036
+ const held = parts.filter((part) => part.matched).length;
2037
+ const matched = kind === "and" ? held === parts.length : kind === "or" ? held > 0 : held === 0;
2038
+ const many = parts.length === 1 ? "part" : "parts";
2039
+ const because = kind === "nor" ? `${held} of ${parts.length} ${many} hold, and none may` : `${held} of ${parts.length} ${many} hold${kind === "or" ? ", and one is enough" : ""}`;
2040
+ return { matched, at, clause, because, parts };
2041
+ }
2042
+ function leaf(clause, item, at, options, key) {
2043
+ const matched = matchedBy(clause, item, options);
2044
+ return { matched, at, clause, because: reason(clause, item, options, key) };
2045
+ }
2046
+ function reason(clause, item, options, key) {
2047
+ if (key === "$text") return matchedBy(clause, item, options) ? "the item holds that text" : "no value of the item holds that text";
2048
+ 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";
2051
+ const path = Object.keys(clause)[0];
2052
+ if (path === void 0 || path.startsWith("$")) return "the clause was run as given";
2053
+ const found = [];
2054
+ try {
2055
+ reachField(path, options.vocabulary, path)(item, (value) => {
2056
+ if (found.length < 4) found.push(value);
2057
+ return false;
2058
+ });
2059
+ } catch {
2060
+ return "the clause was run as given";
2061
+ }
2062
+ return `${path} is ${values(found)}`;
2063
+ }
2064
+ function values(found) {
2065
+ if (found.length === 0 || found.length === 1 && found[0] === void 0) return "missing";
2066
+ const written = found.map((value) => value === void 0 ? "missing" : shorten(value));
2067
+ return written.length === 1 ? written[0] : `each of ${written.join(", ")}`;
2068
+ }
2069
+ function shorten(value) {
2070
+ if (value instanceof Date) return value.toISOString();
2071
+ let text2;
2072
+ try {
2073
+ text2 = JSON.stringify(value) ?? String(value);
2074
+ } catch {
2075
+ return "a value that cannot be written out";
2076
+ }
2077
+ return text2.length > 60 ? `${text2.slice(0, 60)}\u2026` : text2;
2078
+ }
2079
+ function join2(at, key) {
2080
+ return at === "" ? key : `${at}.${key}`;
2081
+ }
2082
+
2083
+ // src/canonical.ts
2084
+ var SETS = /* @__PURE__ */ new Set(["$in", "$nin", "$all", "$contains", "$startsWith", "$endsWith", "$word", "$glob"]);
2085
+ var QUERIES = /* @__PURE__ */ new Set(["$elemMatch"]);
2086
+ var LOGIC = /* @__PURE__ */ new Set(["$and", "$or", "$nor"]);
2087
+ function canonical(query, options) {
2088
+ if (typeof query === "function") throw new TypeError("a compiled predicate has no canonical form: it is code, not a query");
2089
+ compile(query, options);
2090
+ return rewrite(query);
2091
+ }
2092
+ function fingerprint(query, options) {
2093
+ return checksum(JSON.stringify(canonical(query, options)) ?? "");
2094
+ }
2095
+ function rewrite(value) {
2096
+ if (!isPlainObject(value)) return value;
2097
+ if (isDateLiteral(value) || isFieldReference(value)) return value;
2098
+ const out = {};
2099
+ const keys = Object.keys(value).sort().filter((key) => key !== "$comment");
2100
+ const alone = keys.length === 1;
2101
+ for (const key of keys) {
2102
+ const held = value[key];
2103
+ if (LOGIC.has(key) && Array.isArray(held)) {
2104
+ const parts = flatten(key, held).map(rewrite).sort(byText);
2105
+ if (parts.length === 1 && key !== "$nor" && alone) return parts[0];
2106
+ out[key] = parts;
2107
+ continue;
2108
+ }
2109
+ if (key === "$not") {
2110
+ out[key] = rewrite(held);
2111
+ continue;
2112
+ }
2113
+ if (key === "$text") {
2114
+ out[key] = text(held);
2115
+ continue;
2116
+ }
2117
+ if (key.startsWith("$")) {
2118
+ out[key] = operand(key, held);
2119
+ continue;
2120
+ }
2121
+ out[key] = condition(held);
2122
+ }
2123
+ return fold(out);
2124
+ }
2125
+ function fold(out) {
2126
+ const parts = out.$and;
2127
+ if (!Array.isArray(parts) || parts.length === 0) return out;
2128
+ const taken = new Set(Object.keys(out).filter((key) => key !== "$and"));
2129
+ const lifted = {};
2130
+ const kept = [];
2131
+ for (const part of parts) {
2132
+ const keys = isPlainObject(part) ? Object.keys(part) : void 0;
2133
+ if (keys === void 0 || keys.length === 0 || keys.some((key) => taken.has(key))) {
2134
+ kept.push(part);
2135
+ continue;
2136
+ }
2137
+ for (const key of keys) {
2138
+ taken.add(key);
2139
+ lifted[key] = part[key];
2140
+ }
2141
+ }
2142
+ if (Object.keys(lifted).length === 0) return out;
2143
+ const merged = { ...lifted };
2144
+ for (const [key, value] of Object.entries(out)) if (key !== "$and") merged[key] = value;
2145
+ if (kept.length > 0) merged.$and = kept;
2146
+ const sorted = {};
2147
+ for (const key of Object.keys(merged).sort()) sorted[key] = merged[key];
2148
+ return sorted;
2149
+ }
2150
+ function condition(value) {
2151
+ if (isPlainObject(value) && !isDateLiteral(value) && !isFieldReference(value) && Object.keys(value).length > 0 && Object.keys(value).every((key) => key.startsWith("$"))) {
2152
+ const out = {};
2153
+ for (const key of Object.keys(value).sort()) out[key] = key === "$not" ? condition(value[key]) : operand(key, value[key]);
2154
+ return out;
2155
+ }
2156
+ return { $eq: literal(value) };
2157
+ }
2158
+ function operand(key, value) {
2159
+ if (SETS.has(key) && Array.isArray(value)) return unique(value.map(literal));
2160
+ if (QUERIES.has(key)) return rewrite(value);
2161
+ if (key === "$type" && Array.isArray(value)) {
2162
+ const types = unique(value);
2163
+ return types.length === 1 ? types[0] : types;
2164
+ }
2165
+ if (key === "$options" && typeof value === "string") return [...value].sort().join("");
2166
+ if ((key === "$size" || key === "$length") && isPlainObject(value)) return condition(value);
2167
+ return literal(value);
2168
+ }
2169
+ function literal(value) {
2170
+ if (Array.isArray(value)) return value.map(literal);
2171
+ if (!isPlainObject(value) || isDateLiteral(value) || isFieldReference(value)) return value;
2172
+ const out = {};
2173
+ for (const key of Object.keys(value).sort()) out[key] = literal(value[key]);
2174
+ return out;
2175
+ }
2176
+ function text(value) {
2177
+ const search2 = typeof value === "string" ? { $search: value } : isPlainObject(value) ? value : void 0;
2178
+ if (search2 === void 0) return value;
2179
+ const out = { $search: search2.$search };
2180
+ if (Array.isArray(search2.$fields)) out.$fields = unique(search2.$fields);
2181
+ if (search2.$caseSensitive === true) out.$caseSensitive = true;
2182
+ return out;
2183
+ }
2184
+ function flatten(key, parts) {
2185
+ if (key === "$nor") return [...parts];
2186
+ const out = [];
2187
+ for (const part of parts) {
2188
+ const inner = isPlainObject(part) && Object.keys(part).length === 1 ? part[key] : void 0;
2189
+ if (Array.isArray(inner)) out.push(...flatten(key, inner));
2190
+ else out.push(part);
2191
+ }
2192
+ return out;
2193
+ }
2194
+ function byText(a, b) {
2195
+ const left = JSON.stringify(a) ?? "";
2196
+ const right = JSON.stringify(b) ?? "";
2197
+ return left < right ? -1 : left > right ? 1 : 0;
2198
+ }
2199
+ function unique(values2) {
2200
+ const seen = /* @__PURE__ */ new Map();
2201
+ for (const value of values2) {
2202
+ const written = JSON.stringify(value) ?? String(value);
2203
+ if (!seen.has(written)) seen.set(written, value);
2204
+ }
2205
+ return [...seen.values()].sort(byText);
2206
+ }
2207
+ function checksum(text2) {
2208
+ let low = 2166136261;
2209
+ let high = 16777619;
2210
+ for (let i = 0; i < text2.length; i++) {
2211
+ const code = text2.charCodeAt(i);
2212
+ low = Math.imul(low ^ code, 16777619) >>> 0;
2213
+ high = Math.imul(high ^ code + i, 2246822507) >>> 0;
2214
+ }
2215
+ return low.toString(16).padStart(8, "0") + high.toString(16).padStart(8, "0");
2216
+ }
2217
+
2218
+ // src/plan.ts
2219
+ var KNOWN = /* @__PURE__ */ new Set([...FIELD_OPERATORS, ...QUERY_OPERATORS, "$field"]);
2220
+ function plan(query, capabilities, options = {}) {
2221
+ 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);
2223
+ if (!verdict.valid) throw verdict.error;
2224
+ const now = options.now === void 0 ? Date.now() : options.now();
2225
+ const vocabulary = options.vocabulary;
2226
+ const fields = capabilities.fields ?? "all";
2227
+ const operators = capabilities.operators ?? "all";
2228
+ const context = {
2229
+ vocabulary,
2230
+ now,
2231
+ fields: fields === "all" ? "all" : new Set(fields),
2232
+ operators: operators === "all" ? "all" : new Set(operators),
2233
+ or: capabilities.or ?? false,
2234
+ not: capabilities.not ?? false,
2235
+ accepts: capabilities.accepts
2236
+ };
2237
+ const pushed = [];
2238
+ const stays = [];
2239
+ const kept = [];
2240
+ for (const { clause, at } of conjuncts(query, "")) {
2241
+ const why = unpushable(clause, context);
2242
+ if (why === void 0) pushed.push(resolve(clause, context));
2243
+ else {
2244
+ stays.push(clause);
2245
+ kept.push({ at, clause, why });
2246
+ }
2247
+ }
2248
+ return {
2249
+ pushed: join3(pushed),
2250
+ remaining: join3(stays),
2251
+ complete: stays.length === 0,
2252
+ kept
2253
+ };
2254
+ }
2255
+ function conjuncts(query, at) {
2256
+ const out = [];
2257
+ for (const [key, value] of Object.entries(query)) {
2258
+ const here = at === "" ? key : `${at}.${key}`;
2259
+ if (key === "$comment") continue;
2260
+ if (key === "$and" && Array.isArray(value)) {
2261
+ value.forEach((part, index) => {
2262
+ if (isPlainObject(part)) out.push(...conjuncts(part, `${here}[${index}]`));
2263
+ });
2264
+ continue;
2265
+ }
2266
+ out.push({ clause: { [key]: value }, at: here });
2267
+ }
2268
+ return out;
2269
+ }
2270
+ function join3(parts) {
2271
+ if (parts.length === 0) return void 0;
2272
+ const query = parts.length === 1 ? parts[0] : { $and: parts };
2273
+ return query;
2274
+ }
2275
+ function unpushable(clause, context, at) {
2276
+ for (const [key, value] of Object.entries(clause)) {
2277
+ if (key.startsWith("$")) {
2278
+ const why2 = unpushableOperator(key, value, context);
2279
+ if (why2 !== void 0) return why2;
2280
+ continue;
2281
+ }
2282
+ const why = unpushableField(key, value, context);
2283
+ if (why !== void 0) return why;
2284
+ }
2285
+ return void 0;
2286
+ }
2287
+ function unpushableOperator(key, value, context, at) {
2288
+ switch (key) {
2289
+ case "$and":
2290
+ if (!Array.isArray(value)) return "the clause is malformed";
2291
+ for (const part of value) {
2292
+ if (!isPlainObject(part)) return "the clause is malformed";
2293
+ const why = unpushable(part, context);
2294
+ if (why !== void 0) return why;
2295
+ }
2296
+ return void 0;
2297
+ case "$or":
2298
+ case "$nor": {
2299
+ if (!context.or && key === "$or") return "the store cannot answer an $or";
2300
+ if (!context.not && key === "$nor") return "the store cannot answer a negation";
2301
+ if (!context.or && key === "$nor") return "the store cannot answer an $or";
2302
+ if (!Array.isArray(value) || value.length === 0) return "the clause is malformed";
2303
+ for (const part of value) {
2304
+ if (!isPlainObject(part)) return "the clause is malformed";
2305
+ const why = unpushable(part, context);
2306
+ if (why !== void 0) return why;
2307
+ }
2308
+ return void 0;
2309
+ }
2310
+ case "$not": {
2311
+ if (!context.not) return "the store cannot answer a negation";
2312
+ if (!isPlainObject(value)) return "the clause is malformed";
2313
+ return unpushable(value, context);
2314
+ }
2315
+ case "$text":
2316
+ return allows(context, "$text") ? void 0 : "the store cannot answer a text search";
2317
+ default:
2318
+ return `the store cannot test the item itself with "${key}"`;
2319
+ }
2320
+ }
2321
+ function unpushableField(name, value, context, at) {
2322
+ const field = context.vocabulary?.lookup.get(name.toLowerCase());
2323
+ if (field?.get !== void 0) return `"${name}" is computed here, so the store has no such field`;
2324
+ const stored = storedName(name, context);
2325
+ 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)) {
2328
+ if (!allows(context, "$eq")) return 'the store cannot answer "$eq"';
2329
+ return accepted(context, stored, { $eq: value });
2330
+ }
2331
+ const keys = Object.keys(value);
2332
+ if (!keys.every((key) => key.startsWith("$"))) {
2333
+ if (!allows(context, "$eq")) return 'the store cannot answer "$eq"';
2334
+ return accepted(context, stored, { $eq: value });
2335
+ }
2336
+ for (const key of keys) {
2337
+ if (key === "$options" || key === "$comment") continue;
2338
+ if (!KNOWN.has(key)) return `"${key}" is an added operator, which only this engine has`;
2339
+ if (!allows(context, key)) return `the store cannot answer "${key}"`;
2340
+ if ((key === "$ne" || key === "$nin" || key === "$not" || key === "$exists" && value[key] === false) && !context.not) {
2341
+ return "the store cannot answer a negation";
2342
+ }
2343
+ const operand2 = value[key];
2344
+ if (isFieldReference(operand2) && !allows(context, "$field")) return "the store cannot compare two fields";
2345
+ if (key === "$elemMatch") {
2346
+ if (!isPlainObject(operand2)) return "the clause is malformed";
2347
+ const why = unpushable(operand2, context);
2348
+ if (why !== void 0) return why;
2349
+ }
2350
+ if (key === "$not") {
2351
+ if (!isPlainObject(operand2)) return "the clause is malformed";
2352
+ const why = unpushableField(name, operand2, context);
2353
+ if (why !== void 0) return why;
2354
+ }
2355
+ }
2356
+ return accepted(context, stored, value);
2357
+ }
2358
+ function accepted(context, field, condition2) {
2359
+ if (context.accepts === void 0 || context.accepts(field, condition2)) return void 0;
2360
+ return "the store cannot answer this condition's values";
2361
+ }
2362
+ function allows(context, operator) {
2363
+ return context.operators === "all" || context.operators.has(operator);
2364
+ }
2365
+ function resolve(value, context) {
2366
+ if (!isPlainObject(value)) return value;
2367
+ const out = {};
2368
+ for (const [key, held] of Object.entries(value)) {
2369
+ switch (key) {
2370
+ case "$and":
2371
+ case "$or":
2372
+ case "$nor":
2373
+ out[key] = Array.isArray(held) ? held.map((part) => resolve(part, context)) : held;
2374
+ break;
2375
+ case "$not":
2376
+ out[key] = resolve(held, context);
2377
+ break;
2378
+ case "$text":
2379
+ out[key] = resolveText(held, context);
2380
+ break;
2381
+ default:
2382
+ if (key.startsWith("$")) out[key] = resolveOperand(key, held, context);
2383
+ else out[storedName(key, context)] = resolveCondition(held, context);
2384
+ break;
2385
+ }
2386
+ }
2387
+ return out;
2388
+ }
2389
+ function resolveCondition(value, context) {
2390
+ if (!isPlainObject(value)) return resolveLiteral(value, context);
2391
+ if (isDateLiteral(value) || isFieldReference(value)) return resolveOperand("$eq", value, context);
2392
+ const keys = Object.keys(value);
2393
+ if (keys.length === 0 || !keys.every((key) => key.startsWith("$"))) return resolveLiteral(value, context);
2394
+ const out = {};
2395
+ for (const key of keys) out[key] = resolveOperand(key, value[key], context);
2396
+ return out;
2397
+ }
2398
+ function resolveOperand(key, operand2, context) {
2399
+ if (key === "$elemMatch") return resolve(operand2, context);
2400
+ 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));
2403
+ return resolveLiteral(operand2, context);
2404
+ }
2405
+ function resolveText(value, context) {
2406
+ if (!isPlainObject(value) || !Array.isArray(value.$fields)) return value;
2407
+ return { ...value, $fields: value.$fields.map((name) => typeof name === "string" ? storedName(name, context) : name) };
2408
+ }
2409
+ function resolveLiteral(value, context) {
2410
+ 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`);
2415
+ return { $date: time };
2416
+ }
2417
+ const out = {};
2418
+ for (const [key, held] of Object.entries(value)) out[key] = resolveLiteral(held, context);
2419
+ return out;
2420
+ }
2421
+ function storedName(key, context) {
2422
+ if (key.startsWith("$") || context.vocabulary === void 0) return key;
2423
+ const field = context.vocabulary.lookup.get(key.toLowerCase());
2424
+ if (field !== void 0) return field.path;
2425
+ const dot = key.indexOf(".");
2426
+ if (dot > 0) {
2427
+ const head = context.vocabulary.lookup.get(key.slice(0, dot).toLowerCase());
2428
+ if (head !== void 0 && head.get === void 0) return `${head.path}${key.slice(dot)}`;
2429
+ }
2430
+ return key;
2431
+ }
2432
+
2433
+ // src/async.ts
2434
+ async function* iterate(source) {
2435
+ if (Array.isArray(source)) {
2436
+ for (let i = 0; i < source.length; i++) yield source[i];
2437
+ return;
2438
+ }
2439
+ if (source instanceof Map) {
2440
+ for (const item of source.values()) yield item;
2441
+ return;
2442
+ }
2443
+ if (typeof source[Symbol.asyncIterator] === "function") {
2444
+ for await (const item of source) yield item;
2445
+ return;
2446
+ }
2447
+ if (typeof source[Symbol.iterator] === "function") {
2448
+ for (const item of source) yield item;
2449
+ return;
2450
+ }
2451
+ const list = source;
2452
+ for (let i = 0; i < list.length; i++) yield list[i];
2453
+ }
2454
+ async function* filterStream(source, query, options) {
2455
+ const test = compile(query, options);
2456
+ for await (const item of iterate(source)) if (test(item)) yield item;
2457
+ }
2458
+ async function findAsync(source, query, options) {
2459
+ for await (const item of filterStream(source, query, options)) return item;
2460
+ return void 0;
2461
+ }
2462
+ async function filterAsync(source, query, options) {
2463
+ const out = [];
2464
+ for await (const item of filterStream(source, query, options)) out.push(item);
2465
+ return out;
2466
+ }
2467
+ async function countAsync(source, query, options) {
2468
+ let total = 0;
2469
+ const test = compile(query, options);
2470
+ for await (const item of iterate(source)) if (test(item)) total++;
2471
+ return total;
2472
+ }
2473
+ async function someAsync(source, query, options) {
2474
+ const test = compile(query, options);
2475
+ for await (const item of iterate(source)) if (test(item)) return true;
2476
+ return false;
2477
+ }
2478
+ async function everyAsync(source, query, options) {
2479
+ const test = compile(query, options);
2480
+ for await (const item of iterate(source)) if (!test(item)) return false;
2481
+ return true;
2482
+ }
2483
+ async function searchAsync(source, request = {}, options = {}) {
2484
+ const plan2 = planRequest(request, options);
2485
+ const collect2 = plan2.collect();
2486
+ let index = 0;
2487
+ for await (const item of iterate(source)) {
2488
+ const position = index++;
2489
+ if (plan2.test !== void 0 && !plan2.test(item)) continue;
2490
+ if (collect2.offer(item, position)) break;
2491
+ }
2492
+ return plan2.shape(collect2.finish());
2493
+ }
2494
+
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;
2500
+ exports.canonical = canonical;
2501
+ exports.compile = compile;
2502
+ exports.count = count2;
2503
+ exports.countAsync = countAsync;
2504
+ exports.defineVocabulary = defineVocabulary;
2505
+ exports.every = every;
2506
+ exports.everyAsync = everyAsync;
2507
+ exports.explain = explain;
2508
+ exports.filter = filter;
2509
+ exports.filterAsync = filterAsync;
2510
+ exports.filterMap = filterMap;
2511
+ exports.filterRecord = filterRecord;
2512
+ exports.filterStream = filterStream;
2513
+ exports.find = find;
2514
+ exports.findAsync = findAsync;
2515
+ exports.findEntry = findEntry;
2516
+ exports.findIndex = findIndex;
2517
+ exports.fingerprint = fingerprint;
2518
+ exports.group = group;
2519
+ exports.matches = matches;
2520
+ exports.partition = partition;
2521
+ exports.plan = plan;
2522
+ exports.search = search;
2523
+ exports.searchAsync = searchAsync;
2524
+ exports.some = some;
2525
+ exports.someAsync = someAsync;
2526
+ exports.untyped = untyped;
2527
+ exports.validate = validate;
2528
+ //# sourceMappingURL=index.cjs.map
2529
+ //# sourceMappingURL=index.cjs.map