@wral/studio.ui.search-filter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -0
- package/dist/define.mjs +11 -0
- package/dist/define.standalone.js +1603 -0
- package/dist/index.mjs +17 -0
- package/dist/model.mjs +582 -0
- package/dist/search-filter-B-aiJCKp.js +453 -0
- package/package.json +40 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { S as O } from "./search-filter-B-aiJCKp.js";
|
|
2
|
+
import { DATE_OPS as a, DEFAULT_BOOLEANS as t, DEFAULT_OPERATORS as l, NUM_OPS as o, TEXT_OPS as E, URL_OPS as P, VIDEO_OPS as _, createQueryModel as T, equivalent as i, publicationPreset as A, resolveLabels as L, validateSyntax as s } from "./model.mjs";
|
|
3
|
+
export {
|
|
4
|
+
a as DATE_OPS,
|
|
5
|
+
t as DEFAULT_BOOLEANS,
|
|
6
|
+
l as DEFAULT_OPERATORS,
|
|
7
|
+
o as NUM_OPS,
|
|
8
|
+
O as SearchFilter,
|
|
9
|
+
E as TEXT_OPS,
|
|
10
|
+
P as URL_OPS,
|
|
11
|
+
_ as VIDEO_OPS,
|
|
12
|
+
T as createQueryModel,
|
|
13
|
+
i as equivalent,
|
|
14
|
+
A as publicationPreset,
|
|
15
|
+
L as resolveLabels,
|
|
16
|
+
s as validateSyntax
|
|
17
|
+
};
|
package/dist/model.mjs
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
const C = {
|
|
2
|
+
fields: {
|
|
3
|
+
tag: {
|
|
4
|
+
label: "Tag",
|
|
5
|
+
path: "tags.name",
|
|
6
|
+
type: "text",
|
|
7
|
+
hint: "e.g. UNC sports"
|
|
8
|
+
},
|
|
9
|
+
title: {
|
|
10
|
+
label: "Headline",
|
|
11
|
+
path: "metadata.title",
|
|
12
|
+
type: "text",
|
|
13
|
+
hint: "e.g. hurricane"
|
|
14
|
+
},
|
|
15
|
+
body: {
|
|
16
|
+
label: "Summary",
|
|
17
|
+
path: "metadata.description",
|
|
18
|
+
type: "text",
|
|
19
|
+
hint: "e.g. storm damage"
|
|
20
|
+
},
|
|
21
|
+
author: {
|
|
22
|
+
label: "Author",
|
|
23
|
+
path: "metadata.author",
|
|
24
|
+
type: "text",
|
|
25
|
+
hint: "e.g. Brian Murphy"
|
|
26
|
+
},
|
|
27
|
+
uri: {
|
|
28
|
+
label: "Article URL",
|
|
29
|
+
path: "uri",
|
|
30
|
+
type: "url",
|
|
31
|
+
hint: "e.g. https://www.wral.com/sports/"
|
|
32
|
+
},
|
|
33
|
+
site: {
|
|
34
|
+
label: "Site",
|
|
35
|
+
path: "site",
|
|
36
|
+
type: "text",
|
|
37
|
+
hint: "e.g. highschoolot.com"
|
|
38
|
+
},
|
|
39
|
+
date: {
|
|
40
|
+
label: "Published",
|
|
41
|
+
path: "metadata.articlePublishedTime",
|
|
42
|
+
type: "date"
|
|
43
|
+
},
|
|
44
|
+
updated: {
|
|
45
|
+
label: "Updated",
|
|
46
|
+
path: "metadata.articleModifiedTime",
|
|
47
|
+
type: "date"
|
|
48
|
+
},
|
|
49
|
+
// combined hero-video field: "has a video" tests
|
|
50
|
+
// _exists_:metadata.ogVideo, the duration ops filter
|
|
51
|
+
// metadata.ogVideoDuration (seconds).
|
|
52
|
+
video: {
|
|
53
|
+
label: "Has hero video",
|
|
54
|
+
path: "metadata.ogVideo",
|
|
55
|
+
type: "video",
|
|
56
|
+
durationPath: "metadata.ogVideoDuration",
|
|
57
|
+
hint: "duration in seconds, e.g. 60"
|
|
58
|
+
},
|
|
59
|
+
// the default search field: a bare term with no `field:` prefix,
|
|
60
|
+
// matching the backend's full-text default. Used for legacy
|
|
61
|
+
// bare-phrase queries.
|
|
62
|
+
any: {
|
|
63
|
+
label: "Any field",
|
|
64
|
+
path: "",
|
|
65
|
+
type: "text",
|
|
66
|
+
hint: "e.g. hurricane"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
defaults: {
|
|
70
|
+
field: "title",
|
|
71
|
+
conditional: {
|
|
72
|
+
if: { field: "tag", op: "term" },
|
|
73
|
+
then: { field: "uri", op: "under", negate: !0 },
|
|
74
|
+
else: { field: "uri", op: "under" }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
labels: {
|
|
78
|
+
itemNoun: "story",
|
|
79
|
+
itemNounPlural: "stories"
|
|
80
|
+
}
|
|
81
|
+
}, Y = [
|
|
82
|
+
{ id: "phrase", label: "contains the phrase" },
|
|
83
|
+
{ id: "term", label: "matches the word" },
|
|
84
|
+
{ id: "starts", label: "starts with" },
|
|
85
|
+
{ id: "fuzzy", label: "sounds like (fuzzy)" },
|
|
86
|
+
{ id: "exists", label: "has any value" }
|
|
87
|
+
], ee = [
|
|
88
|
+
{ id: "is", label: "is exactly" },
|
|
89
|
+
{ id: "under", label: "is anywhere under" }
|
|
90
|
+
], te = [
|
|
91
|
+
{ id: "after", label: "is on or after" },
|
|
92
|
+
{ id: "before", label: "is on or before" },
|
|
93
|
+
{ id: "between", label: "is between" }
|
|
94
|
+
], ne = [
|
|
95
|
+
{ id: "gte", label: "is at least" },
|
|
96
|
+
{ id: "lte", label: "is at most" },
|
|
97
|
+
{ id: "between", label: "is between" }
|
|
98
|
+
], ie = [
|
|
99
|
+
{ id: "exists", label: "has a video" },
|
|
100
|
+
{ id: "longer", label: "is longer than (sec)" },
|
|
101
|
+
{ id: "shorter", label: "is shorter than (sec)" },
|
|
102
|
+
{ id: "between", label: "duration between (sec)" }
|
|
103
|
+
], P = {
|
|
104
|
+
text: Y,
|
|
105
|
+
url: ee,
|
|
106
|
+
date: te,
|
|
107
|
+
number: ne,
|
|
108
|
+
video: ie
|
|
109
|
+
}, H = [
|
|
110
|
+
{ id: "AND", label: "all" },
|
|
111
|
+
{ id: "OR", label: "any" }
|
|
112
|
+
], w = (t) => {
|
|
113
|
+
throw new Error(`search-filter: ${t}`);
|
|
114
|
+
};
|
|
115
|
+
function V(t, i, e) {
|
|
116
|
+
const r = new Set(P[i].map((o) => o.id));
|
|
117
|
+
return (!Array.isArray(t) || !t.length) && w(`${e} must be a non-empty array of { id, label }`), t.map((o) => ((!o || !r.has(o.id)) && w(`${e} has unknown ${i} operator id "${o && o.id}" (known: ${[...r].join(", ")})`), { id: o.id, label: o.label || o.id }));
|
|
118
|
+
}
|
|
119
|
+
function oe(t, i = {}) {
|
|
120
|
+
const e = Object.keys(t || {});
|
|
121
|
+
e.length || w("the fields catalog is empty");
|
|
122
|
+
const r = {};
|
|
123
|
+
for (const o of e) {
|
|
124
|
+
const l = t[o] || {}, a = l.type || "text";
|
|
125
|
+
P[a] || w(`field "${o}" has unknown type "${a}" (known: ${Object.keys(P).join(", ")})`), typeof l.path != "string" && w(`field "${o}" needs a string path ('' targets the backend's default field)`), a === "video" && !l.durationPath && w(`field "${o}" is type video and needs a durationPath`);
|
|
126
|
+
const c = l.ops ? V(l.ops, a, `field "${o}" ops`) : i[a] ? V(i[a], a, `operators.${a}`) : P[a];
|
|
127
|
+
r[o] = {
|
|
128
|
+
label: l.label || o,
|
|
129
|
+
path: l.path,
|
|
130
|
+
type: a,
|
|
131
|
+
hint: l.hint || "",
|
|
132
|
+
durationPath: l.durationPath || "",
|
|
133
|
+
ops: c
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return r;
|
|
137
|
+
}
|
|
138
|
+
function re(t) {
|
|
139
|
+
if (t == null) return H;
|
|
140
|
+
const i = new Set(H.map((e) => e.id));
|
|
141
|
+
return (!Array.isArray(t) || !t.length) && w("booleans must be a non-empty array of { id, label }"), t.map((e) => ((!e || !i.has(e.id)) && w(`unknown boolean operator "${e && e.id}" (known: AND, OR)`), { id: e.id, label: e.label || e.id }));
|
|
142
|
+
}
|
|
143
|
+
let le = 0;
|
|
144
|
+
const A = () => "n" + ++le, S = (t) => String(t).replace(/(["\\])/g, "\\$1"), U = (t) => S(t).replace(/\s+/g, "\\ ");
|
|
145
|
+
function L(t) {
|
|
146
|
+
const i = [];
|
|
147
|
+
let e = 0;
|
|
148
|
+
const r = t.length;
|
|
149
|
+
for (; e < r; ) {
|
|
150
|
+
const o = t[e];
|
|
151
|
+
if (o === " " || o === " " || o === `
|
|
152
|
+
`) {
|
|
153
|
+
e++;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (o === "(" || o === ")") {
|
|
157
|
+
i.push(o), e++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
let l = "";
|
|
161
|
+
for (; e < r; ) {
|
|
162
|
+
const a = t[e];
|
|
163
|
+
if (a === "\\" && e + 1 < r) {
|
|
164
|
+
l += a + t[e + 1], e += 2;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (a === " " || a === "(" || a === ")") break;
|
|
168
|
+
if (a === '"') {
|
|
169
|
+
for (l += a, e++; e < r; ) {
|
|
170
|
+
if (l += t[e], t[e] === '"' && t[e - 1] !== "\\") {
|
|
171
|
+
e++;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
e++;
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (a === "[") {
|
|
179
|
+
for (l += a, e++; e < r; ) {
|
|
180
|
+
if (l += t[e], t[e] === "]") {
|
|
181
|
+
e++;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
e++;
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
l += a, e++;
|
|
189
|
+
}
|
|
190
|
+
l === "AND" || l === "OR" || l === "NOT" ? i.push(l) : l === "&&" ? i.push("AND") : l === "||" ? i.push("OR") : i.push({ term: l });
|
|
191
|
+
}
|
|
192
|
+
return i;
|
|
193
|
+
}
|
|
194
|
+
function z(t, i) {
|
|
195
|
+
if (t.startsWith("[")) {
|
|
196
|
+
const l = t.match(/^\[(.+) TO (.+)\]$/) || [null, "*", "*"], a = l[1], c = l[2];
|
|
197
|
+
return a === "*" ? { op: i === "number" ? "lte" : "before", value: c } : c === "*" ? { op: i === "number" ? "gte" : "after", value: a } : { op: "between", value: a, value2: c };
|
|
198
|
+
}
|
|
199
|
+
if (t.startsWith('"'))
|
|
200
|
+
return {
|
|
201
|
+
op: i === "url" ? "under" : "phrase",
|
|
202
|
+
value: t.slice(1, -1).replace(/\\(.)/g, "$1")
|
|
203
|
+
};
|
|
204
|
+
let e = t, r = "";
|
|
205
|
+
return e.endsWith("*") ? (r = "*", e = e.slice(0, -1)) : e.endsWith("~") && (r = "~", e = e.slice(0, -1)), e = e.replace(/\\ /g, " ").replace(/\\(.)/g, "$1"), { op: i === "url" ? "under" : r === "*" ? "starts" : r === "~" ? "fuzzy" : "term", value: e };
|
|
206
|
+
}
|
|
207
|
+
function se(t, i) {
|
|
208
|
+
let e = 0;
|
|
209
|
+
const r = () => t[e], o = () => t[e++];
|
|
210
|
+
function l() {
|
|
211
|
+
let $ = !1;
|
|
212
|
+
for (; r() === "NOT"; )
|
|
213
|
+
$ = !$, o();
|
|
214
|
+
let h;
|
|
215
|
+
if (r() === "(")
|
|
216
|
+
o(), h = c(), r() === ")" && o();
|
|
217
|
+
else {
|
|
218
|
+
const g = o();
|
|
219
|
+
if (!g || typeof g == "string")
|
|
220
|
+
throw new Error("Unexpected token");
|
|
221
|
+
h = i(g);
|
|
222
|
+
}
|
|
223
|
+
return $ && (h.negate = !h.negate), h;
|
|
224
|
+
}
|
|
225
|
+
function a() {
|
|
226
|
+
const $ = l(), h = [$];
|
|
227
|
+
for (; ; ) {
|
|
228
|
+
const g = r();
|
|
229
|
+
if (g === "AND")
|
|
230
|
+
o(), h.push(l());
|
|
231
|
+
else if (g !== void 0 && g !== ")" && g !== "OR") h.push(l());
|
|
232
|
+
else break;
|
|
233
|
+
}
|
|
234
|
+
return h.length === 1 ? $ : {
|
|
235
|
+
id: A(),
|
|
236
|
+
kind: "group",
|
|
237
|
+
op: "AND",
|
|
238
|
+
negate: !1,
|
|
239
|
+
children: h
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function c() {
|
|
243
|
+
const $ = a(), h = [$];
|
|
244
|
+
for (; r() === "OR"; )
|
|
245
|
+
o(), h.push(a());
|
|
246
|
+
return h.length === 1 ? $ : {
|
|
247
|
+
id: A(),
|
|
248
|
+
kind: "group",
|
|
249
|
+
op: "OR",
|
|
250
|
+
negate: !1,
|
|
251
|
+
children: h
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const v = c();
|
|
255
|
+
if (e < t.length) throw new Error("Unexpected trailing tokens");
|
|
256
|
+
return v;
|
|
257
|
+
}
|
|
258
|
+
function ae(t, i) {
|
|
259
|
+
let e = "", r = t;
|
|
260
|
+
return r.startsWith("-") && (e = "-", r = r.slice(1)), M.has(r) || /^[A-Za-z_][\w.$]*:/.test(r) ? t : e + i + ":" + r;
|
|
261
|
+
}
|
|
262
|
+
function E(t) {
|
|
263
|
+
const i = (r) => r && typeof r == "object", e = [];
|
|
264
|
+
for (let r = 0; r < t.length; r++) {
|
|
265
|
+
const o = t[r], l = i(o) && /^(-?)([A-Za-z_][\w.$]*):$/.exec(o.term);
|
|
266
|
+
if (l && t[r + 1] === "(") {
|
|
267
|
+
let a = 0, c = r + 1;
|
|
268
|
+
for (; c < t.length; c++)
|
|
269
|
+
if (t[c] === "(") a++;
|
|
270
|
+
else if (t[c] === ")" && --a === 0) break;
|
|
271
|
+
if (c < t.length) {
|
|
272
|
+
l[1] === "-" && e.push("NOT"), e.push("(");
|
|
273
|
+
for (const v of E(t.slice(r + 2, c)))
|
|
274
|
+
e.push(i(v) ? { term: ae(v.term, l[2]) } : v);
|
|
275
|
+
e.push(")"), r = c;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
e.push(o);
|
|
280
|
+
}
|
|
281
|
+
return e;
|
|
282
|
+
}
|
|
283
|
+
function me(t) {
|
|
284
|
+
let i = 0, e = 0;
|
|
285
|
+
for (const r of t)
|
|
286
|
+
if (r === "(" ? i++ : r === ")" ? i-- : r === '"' && e++, i < 0) break;
|
|
287
|
+
return i !== 0 ? "Unbalanced parentheses." : e % 2 !== 0 ? "Unbalanced quotes." : "";
|
|
288
|
+
}
|
|
289
|
+
const M = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
|
|
290
|
+
function ue(t) {
|
|
291
|
+
const i = t.indexOf(":");
|
|
292
|
+
return i < 0 ? null : { field: t.slice(0, i), value: t.slice(i + 1) };
|
|
293
|
+
}
|
|
294
|
+
function de(t) {
|
|
295
|
+
const i = ue(t);
|
|
296
|
+
if (!i) return t;
|
|
297
|
+
let e = i.value;
|
|
298
|
+
if (e.length > 1 && e.startsWith('"') && e.endsWith('"')) {
|
|
299
|
+
const r = e.slice(1, -1);
|
|
300
|
+
r && !/\s/.test(r) && (e = r);
|
|
301
|
+
}
|
|
302
|
+
return i.field + ":" + e;
|
|
303
|
+
}
|
|
304
|
+
function fe(t) {
|
|
305
|
+
let i = t.slice();
|
|
306
|
+
for (let e = !0; e; ) {
|
|
307
|
+
e = !1;
|
|
308
|
+
for (let r = 0; r + 2 < i.length; r++)
|
|
309
|
+
if (i[r] === "(" && i[r + 2] === ")" && i[r + 1] !== "(" && i[r + 1] !== ")") {
|
|
310
|
+
i.splice(r, 3, i[r + 1]), e = !0;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
if (!e && i.length >= 2 && i[0] === "(" && i[i.length - 1] === ")") {
|
|
314
|
+
let r = 0, o = !0;
|
|
315
|
+
for (let l = 0; l < i.length; l++)
|
|
316
|
+
if (i[l] === "(") r++;
|
|
317
|
+
else if (i[l] === ")" && --r === 0 && l !== i.length - 1) {
|
|
318
|
+
o = !1;
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
o && (i = i.slice(1, -1), e = !0);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return i;
|
|
325
|
+
}
|
|
326
|
+
function ce(t) {
|
|
327
|
+
return t[0] === "!" ? "-" + t.slice(1) : t;
|
|
328
|
+
}
|
|
329
|
+
function D(t) {
|
|
330
|
+
const i = E(L(t)).map((o) => typeof o == "string" ? o : o.term).map(ce), e = [];
|
|
331
|
+
for (let o = 0; o < i.length; o++) {
|
|
332
|
+
const l = i[o];
|
|
333
|
+
if (l === "NOT" && o + 1 < i.length && i[o + 1] !== "(" && !M.has(i[o + 1])) {
|
|
334
|
+
const a = i[++o];
|
|
335
|
+
e.push(a.startsWith("-") ? a.slice(1) : "-" + a);
|
|
336
|
+
} else
|
|
337
|
+
e.push(l);
|
|
338
|
+
}
|
|
339
|
+
return fe(
|
|
340
|
+
e.filter((o) => o !== "AND").map(de)
|
|
341
|
+
).join(" ");
|
|
342
|
+
}
|
|
343
|
+
function pe(t) {
|
|
344
|
+
const i = (o) => o === "AND" || o === "OR" || o === "NOT", e = (o) => o === ")" || !i(o) && o !== "(", r = (o) => o === "(" || !i(o) && o !== ")" && o[0] !== "-" && o[0] !== "!" && o[0] !== "+";
|
|
345
|
+
for (let o = 0; o + 1 < t.length; o++)
|
|
346
|
+
if (e(t[o]) && r(t[o + 1])) return !0;
|
|
347
|
+
return !1;
|
|
348
|
+
}
|
|
349
|
+
function ge(t, i) {
|
|
350
|
+
if (t === i) return !0;
|
|
351
|
+
try {
|
|
352
|
+
return D(t || "") === D(i || "");
|
|
353
|
+
} catch {
|
|
354
|
+
return !1;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function $e(t = {}) {
|
|
358
|
+
const i = t.fields == null, e = oe(
|
|
359
|
+
t.fields ?? C.fields,
|
|
360
|
+
t.operators
|
|
361
|
+
), r = re(t.booleans), o = new Set(r.map((n) => n.id)), l = t.defaults ?? (i ? C.defaults : null), a = Object.keys(e), c = (n) => a.find((s) => e[s].path === n), v = (n, s) => e[n].ops.some((u) => u.id === s), $ = (n, s) => {
|
|
362
|
+
n && (e[n.field] || w(`${s} names unknown field "${n.field}"`), n.op && !v(n.field, n.op) && w(`${s} uses operator "${n.op}" not offered for field "${n.field}"`));
|
|
363
|
+
};
|
|
364
|
+
l?.field && !e[l.field] && w(`defaults.field names unknown field "${l.field}"`), $(l?.conditional?.if, "defaults.conditional.if"), $(l?.conditional?.then, "defaults.conditional.then"), $(l?.conditional?.else, "defaults.conditional.else");
|
|
365
|
+
const h = l?.field || a[0], g = (n = h, s = {}) => ({
|
|
366
|
+
id: A(),
|
|
367
|
+
kind: "rule",
|
|
368
|
+
field: n,
|
|
369
|
+
op: e[n].ops[0].id,
|
|
370
|
+
value: "",
|
|
371
|
+
value2: "",
|
|
372
|
+
negate: !1,
|
|
373
|
+
boost: "",
|
|
374
|
+
...s
|
|
375
|
+
}), O = (n = r[0].id, s = null) => ({
|
|
376
|
+
id: A(),
|
|
377
|
+
kind: "group",
|
|
378
|
+
op: n,
|
|
379
|
+
negate: !1,
|
|
380
|
+
children: s || [g()]
|
|
381
|
+
}), R = (n) => n ? g(n.field, {
|
|
382
|
+
...n.op ? { op: n.op } : {},
|
|
383
|
+
...n.negate ? { negate: !0 } : {}
|
|
384
|
+
}) : g(), Q = () => ({
|
|
385
|
+
id: A(),
|
|
386
|
+
kind: "conditional",
|
|
387
|
+
cond: O("AND", [R(l?.conditional?.if)]),
|
|
388
|
+
then: O("AND", [R(l?.conditional?.then)]),
|
|
389
|
+
els: O("AND", [R(l?.conditional?.else)])
|
|
390
|
+
}), G = () => O("AND", [R(l?.conditional?.else)]);
|
|
391
|
+
function j(n) {
|
|
392
|
+
const s = e[n.field], u = s.path;
|
|
393
|
+
if (s.type === "video") {
|
|
394
|
+
let m = "";
|
|
395
|
+
if (n.op === "exists")
|
|
396
|
+
m = `_exists_:${u}`;
|
|
397
|
+
else {
|
|
398
|
+
const y = (n.value || "").trim(), k = (n.value2 || "").trim();
|
|
399
|
+
n.op === "longer" ? m = y && `${s.durationPath}:[${y} TO *]` : n.op === "shorter" ? m = y && `${s.durationPath}:[* TO ${y}]` : n.op === "between" && (m = y && k && `${s.durationPath}:[${y} TO ${k}]`);
|
|
400
|
+
}
|
|
401
|
+
return m ? n.negate ? "-" + m : m : "";
|
|
402
|
+
}
|
|
403
|
+
const d = u ? `${u}:` : "", f = (n.value || "").trim(), x = (n.value2 || "").trim();
|
|
404
|
+
let p = "";
|
|
405
|
+
if (s.type === "url") {
|
|
406
|
+
if (!f) return "";
|
|
407
|
+
p = n.op === "is" ? `${u}.keyword:"${S(f)}"` : `${d}"${S(f)}"`;
|
|
408
|
+
} else if (s.type === "date" || s.type === "number")
|
|
409
|
+
if (n.op === "between") {
|
|
410
|
+
if (!f || !x) return "";
|
|
411
|
+
p = `${d}[${f} TO ${x}]`;
|
|
412
|
+
} else if (n.op === "after" || n.op === "gte") {
|
|
413
|
+
if (!f) return "";
|
|
414
|
+
p = `${d}[${f} TO *]`;
|
|
415
|
+
} else {
|
|
416
|
+
if (!f) return "";
|
|
417
|
+
p = `${d}[* TO ${f}]`;
|
|
418
|
+
}
|
|
419
|
+
else if (n.op === "exists") {
|
|
420
|
+
if (!u) return "";
|
|
421
|
+
p = `_exists_:${u}`;
|
|
422
|
+
} else {
|
|
423
|
+
if (!f) return "";
|
|
424
|
+
n.op === "phrase" ? p = `${d}"${S(f)}"` : n.op === "term" ? p = `${d}${U(f)}` : n.op === "starts" ? p = `${d}${U(f)}*` : n.op === "fuzzy" && (p = `${d}${U(f)}~`);
|
|
425
|
+
}
|
|
426
|
+
return p ? (n.boost && Number(n.boost) > 0 && n.op !== "exists" && (p += `^${n.boost}`), n.negate && (p = "-" + p), p) : "";
|
|
427
|
+
}
|
|
428
|
+
function Z(n) {
|
|
429
|
+
return n.kind === "rule" ? j(n) : n.kind === "conditional" ? I(n) : T(n);
|
|
430
|
+
}
|
|
431
|
+
function T(n, s = !1) {
|
|
432
|
+
const u = n.children.map(Z).filter(Boolean);
|
|
433
|
+
if (u.length === 0) return "";
|
|
434
|
+
const d = u.join(` ${n.op} `);
|
|
435
|
+
let f = u.length > 1 && !s ? `(${d})` : d;
|
|
436
|
+
return n.negate && (f = u.length > 1 ? `NOT (${d})` : `NOT ${d}`), f;
|
|
437
|
+
}
|
|
438
|
+
function I(n) {
|
|
439
|
+
const s = T(n.cond), u = T(n.then), d = n.els ? T(n.els) : "";
|
|
440
|
+
if (!s) return u || "";
|
|
441
|
+
const f = u ? `(${s} AND ${u})` : `(${s})`;
|
|
442
|
+
return d ? `(${f} OR (NOT (${s}) AND ${d}))` : f;
|
|
443
|
+
}
|
|
444
|
+
function W(n) {
|
|
445
|
+
return T(n, !0) || "";
|
|
446
|
+
}
|
|
447
|
+
function N(n, s) {
|
|
448
|
+
if (s.op && !v(n, s.op))
|
|
449
|
+
throw new Error(`Unsupported operator for ${n}: ${s.op}`);
|
|
450
|
+
return g(n, s);
|
|
451
|
+
}
|
|
452
|
+
function J(n) {
|
|
453
|
+
let s = n.term, u = !1;
|
|
454
|
+
s[0] === "-" || s[0] === "!" ? (u = !0, s = s.slice(1)) : s[0] === "+" && (s = s.slice(1));
|
|
455
|
+
let d = "";
|
|
456
|
+
const f = s.match(/\^(\d+(?:\.\d+)?)$/);
|
|
457
|
+
f && (d = f[1], s = s.slice(0, -f[0].length));
|
|
458
|
+
const x = s.indexOf(":");
|
|
459
|
+
if (x < 0) {
|
|
460
|
+
const b = c("");
|
|
461
|
+
if (!b) throw new Error(`No default field for bare term: ${s}`);
|
|
462
|
+
return N(b, {
|
|
463
|
+
...z(s, e[b].type),
|
|
464
|
+
negate: u,
|
|
465
|
+
boost: d
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
const p = s.slice(0, x), m = s.slice(x + 1);
|
|
469
|
+
if (p === "_exists_") {
|
|
470
|
+
const b = c(m.replace(/^"(.*)"$/, "$1"));
|
|
471
|
+
if (!b) throw new Error(`Unknown field: ${m}`);
|
|
472
|
+
return N(b, { op: "exists", negate: u });
|
|
473
|
+
}
|
|
474
|
+
const y = a.find((b) => e[b].type === "video" && e[b].durationPath === p);
|
|
475
|
+
if (y && m.startsWith("[")) {
|
|
476
|
+
const { op: b, value: X, value2: q } = z(m, "number");
|
|
477
|
+
return N(y, { op: b === "gte" ? "longer" : b === "lte" ? "shorter" : "between", value: X, value2: q || "", negate: u });
|
|
478
|
+
}
|
|
479
|
+
const k = a.find((b) => e[b].type === "url" && p === e[b].path + ".keyword");
|
|
480
|
+
if (k) {
|
|
481
|
+
const b = m.startsWith('"') ? m.slice(1, -1).replace(/\\(.)/g, "$1") : m;
|
|
482
|
+
return N(k, { op: "is", value: b, negate: u });
|
|
483
|
+
}
|
|
484
|
+
const _ = c(p);
|
|
485
|
+
if (!_) throw new Error(`Unknown field: ${p}`);
|
|
486
|
+
return N(_, {
|
|
487
|
+
...z(m, e[_].type),
|
|
488
|
+
negate: u,
|
|
489
|
+
boost: d
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
function B(n) {
|
|
493
|
+
if (!n || !n.trim()) return O(void 0, []);
|
|
494
|
+
const s = se(E(L(n)), J);
|
|
495
|
+
return s.kind === "group" ? s : O(void 0, [s]);
|
|
496
|
+
}
|
|
497
|
+
const F = (n) => n.kind !== "group" || o.has(n.op) && n.children.every(F);
|
|
498
|
+
function K(n) {
|
|
499
|
+
if (!n || !n.trim()) return !0;
|
|
500
|
+
try {
|
|
501
|
+
const s = E(L(n)).map((d) => typeof d == "string" ? d : d.term);
|
|
502
|
+
if (pe(s)) return !1;
|
|
503
|
+
const u = B(n);
|
|
504
|
+
return F(u) ? D(W(u)) === D(n) : !1;
|
|
505
|
+
} catch {
|
|
506
|
+
return !1;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
fields: e,
|
|
511
|
+
fieldKeys: a,
|
|
512
|
+
groupOps: r,
|
|
513
|
+
defaultField: h,
|
|
514
|
+
// conditionals desugar to OR-of-ANDs, so they're only on offer
|
|
515
|
+
// when both joiners are
|
|
516
|
+
supportsConditionals: o.has("AND") && o.has("OR"),
|
|
517
|
+
newRule: g,
|
|
518
|
+
newGroup: O,
|
|
519
|
+
newConditional: Q,
|
|
520
|
+
newElse: G,
|
|
521
|
+
ruleToLucene: j,
|
|
522
|
+
groupToLucene: T,
|
|
523
|
+
condToLucene: I,
|
|
524
|
+
toLucene: W,
|
|
525
|
+
parseLucene: B,
|
|
526
|
+
roundTrips: K
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
const he = (t) => t && t[0].toUpperCase() + t.slice(1);
|
|
530
|
+
function we(t = {}) {
|
|
531
|
+
const i = t.itemNoun || "story", e = t.itemNounPlural || (t.itemNoun ? t.itemNoun + "s" : "stories");
|
|
532
|
+
return {
|
|
533
|
+
itemNoun: i,
|
|
534
|
+
itemNounPlural: e,
|
|
535
|
+
intro: `Describe the ${e} you want in plain language — the query writes itself.`,
|
|
536
|
+
rawUnsupported: "This query uses syntax the visual editor can't represent, so it's shown as raw text.",
|
|
537
|
+
rawButton: "Raw Query",
|
|
538
|
+
visualButton: "Query Builder",
|
|
539
|
+
rawSynced: "Synced.",
|
|
540
|
+
rawSaved: "Saved as raw text — the visual builder can't represent this query. Adjust it to a supported form to switch back.",
|
|
541
|
+
matchPrefix: `${he(e)} must match`,
|
|
542
|
+
matchSuffix: "of these rules",
|
|
543
|
+
empty: `No rules yet, so every ${i} can appear. Add a rule to narrow the collection.`,
|
|
544
|
+
addRule: "Rule",
|
|
545
|
+
addRuleTip: 'Add one condition, like Title contains "storm".',
|
|
546
|
+
addConditional: "If/then",
|
|
547
|
+
addConditionalTip: `Apply conditions only to ${e} that match a test first.`,
|
|
548
|
+
actsHelpRule: "adds a single condition",
|
|
549
|
+
actsHelpConditional: `applies conditions only to certain ${e}`,
|
|
550
|
+
conditionalTitle: "IF / THEN",
|
|
551
|
+
conditionalIf: `If a ${i} matches`,
|
|
552
|
+
conditionalThen: "then include only when",
|
|
553
|
+
conditionalElse: "otherwise include only when",
|
|
554
|
+
removeElse: "remove",
|
|
555
|
+
addElse: "Otherwise branch",
|
|
556
|
+
addSubRule: "Rule",
|
|
557
|
+
addSubRuleTip: "Add another condition to this list.",
|
|
558
|
+
include: "Include",
|
|
559
|
+
exclude: "Exclude",
|
|
560
|
+
ruleTag: "Rule",
|
|
561
|
+
between: "and",
|
|
562
|
+
// sic: "a values." matches the original builder's rendered string
|
|
563
|
+
// (`…a value${plural ? 's' : ''}.`) byte-for-byte
|
|
564
|
+
pendingOne: "Ignored until you enter a value.",
|
|
565
|
+
pendingBoth: "Ignored until you enter a values.",
|
|
566
|
+
...t
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
export {
|
|
570
|
+
te as DATE_OPS,
|
|
571
|
+
H as DEFAULT_BOOLEANS,
|
|
572
|
+
P as DEFAULT_OPERATORS,
|
|
573
|
+
ne as NUM_OPS,
|
|
574
|
+
Y as TEXT_OPS,
|
|
575
|
+
ee as URL_OPS,
|
|
576
|
+
ie as VIDEO_OPS,
|
|
577
|
+
$e as createQueryModel,
|
|
578
|
+
ge as equivalent,
|
|
579
|
+
C as publicationPreset,
|
|
580
|
+
we as resolveLabels,
|
|
581
|
+
me as validateSyntax
|
|
582
|
+
};
|