@osqd/jql 0.1.1 → 0.1.2

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