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