@tellaro/tql 1.4.3 → 2.0.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/dist/index.js +67 -64
- package/dist/src/builder.d.ts +6 -0
- package/dist/src/completionProvider.js +276 -195
- package/dist/src/complexityAnalyzer.js +41 -32
- package/dist/src/index.d.ts +2 -2
- package/dist/src/parser.d.ts +193 -1
- package/dist/src/parser.js +614 -127
- package/dist/src/semanticPreview.d.ts +23 -0
- package/dist/src/semanticPreview.js +111 -41
- package/dist/src/tokenizer.d.ts +134 -5
- package/dist/src/tokenizer.js +129 -110
- package/dist/src/types.d.ts +86 -4
- package/dist/src/validator.d.ts +101 -1
- package/dist/src/validator.js +391 -152
- package/dist/tql.css +1 -1
- package/dist/vue/TqlAutocomplete.vue.js +2 -2
- package/dist/vue/TqlChart.vue.js +1 -1
- package/dist/vue/TqlInput.vue.js +2 -2
- package/dist/vue/TqlInput.vue2.js +273 -254
- package/package.json +128 -128
|
@@ -11,6 +11,28 @@ export declare class SemanticPreview {
|
|
|
11
11
|
private extractFromBinary;
|
|
12
12
|
private extractFromUnary;
|
|
13
13
|
private extractFromGroup;
|
|
14
|
+
/**
|
|
15
|
+
* `field [not] ANY value` -- the collection operator IS the operator this preview reports.
|
|
16
|
+
*
|
|
17
|
+
* Recursing straight into `expr.condition` (what this did) hands the wrapped comparison to
|
|
18
|
+
* `extractFromComparison`, which reports the INNER operator -- `eq` by default, because
|
|
19
|
+
* both grammars default the optional inner operator to `eq`. So `f any true`, `f not any
|
|
20
|
+
* true` and `f none true` all reported `eq`: the collection operator vanished and, on the
|
|
21
|
+
* negated spellings, the preview stated the logical opposite of the query.
|
|
22
|
+
*/
|
|
23
|
+
private extractFromCollection;
|
|
24
|
+
/**
|
|
25
|
+
* The operator string a collection expression renders as.
|
|
26
|
+
*
|
|
27
|
+
* The shape is the one `not contains` and `not in` already use: negation lives in the
|
|
28
|
+
* operator NAME (`not_contains`, `not_in`), not in a separate flag the formatter has to
|
|
29
|
+
* remember to read. `collectionOperatorSpelling` derives `any` / `not_any` from the
|
|
30
|
+
* parser's own spelling table, so this cannot drift from what the parser accepts.
|
|
31
|
+
*
|
|
32
|
+
* An inner operator other than the implicit `eq` is appended (`any gt`), because
|
|
33
|
+
* `f any gt 5` and `f any 5` are different queries.
|
|
34
|
+
*/
|
|
35
|
+
private collectionOperatorLabel;
|
|
14
36
|
private extractFromComparison;
|
|
15
37
|
/**
|
|
16
38
|
* Get field name and mutators from field reference or mutator expression
|
|
@@ -31,6 +53,7 @@ export declare class SemanticPreview {
|
|
|
31
53
|
private buildBinaryNode;
|
|
32
54
|
private buildUnaryNode;
|
|
33
55
|
private buildComparisonNode;
|
|
56
|
+
private buildCollectionNode;
|
|
34
57
|
private buildGroupNode;
|
|
35
58
|
}
|
|
36
59
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { parseTql as f } from "./parser.js";
|
|
1
|
+
import { parseTql as f, collectionOperatorSpelling as g } from "./parser.js";
|
|
2
2
|
import { analyzeComplexity as m } from "./complexityAnalyzer.js";
|
|
3
|
-
class
|
|
3
|
+
class o {
|
|
4
4
|
/**
|
|
5
5
|
* Generate a complete preview for a TQL query
|
|
6
6
|
*/
|
|
7
7
|
generatePreview(t) {
|
|
8
|
-
const r = f(t), i = m(t), n = [],
|
|
8
|
+
const r = f(t), i = m(t), n = [], c = {};
|
|
9
9
|
if (!r.ast)
|
|
10
10
|
return {
|
|
11
11
|
fields: [],
|
|
@@ -15,15 +15,15 @@ class u {
|
|
|
15
15
|
uniqueFields: [],
|
|
16
16
|
operatorSummary: {}
|
|
17
17
|
};
|
|
18
|
-
this.extractFieldUsage(r.ast, n,
|
|
19
|
-
const a = this.buildLogicTree(r.ast),
|
|
18
|
+
this.extractFieldUsage(r.ast, n, c);
|
|
19
|
+
const a = this.buildLogicTree(r.ast), s = [...new Set(n.map((u) => u.name))];
|
|
20
20
|
return {
|
|
21
21
|
fields: n,
|
|
22
22
|
logicTree: a,
|
|
23
23
|
complexity: i,
|
|
24
24
|
fieldCount: n.length,
|
|
25
|
-
uniqueFields:
|
|
26
|
-
operatorSummary:
|
|
25
|
+
uniqueFields: s,
|
|
26
|
+
operatorSummary: c
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -40,6 +40,12 @@ class u {
|
|
|
40
40
|
case "comparison":
|
|
41
41
|
this.extractFromComparison(t, r, i);
|
|
42
42
|
break;
|
|
43
|
+
// `field ANY value` -- the field and operator this preview describes are inside the
|
|
44
|
+
// wrapped comparison. Without this arm the `default` below swallowed it and the
|
|
45
|
+
// preview reported a collection query as touching no fields at all.
|
|
46
|
+
case "collection":
|
|
47
|
+
this.extractFromCollection(t, r, i);
|
|
48
|
+
break;
|
|
43
49
|
case "group":
|
|
44
50
|
this.extractFromGroup(t, r, i);
|
|
45
51
|
break;
|
|
@@ -54,16 +60,60 @@ class u {
|
|
|
54
60
|
extractFromGroup(t, r, i) {
|
|
55
61
|
this.extractFieldUsage(t.expression, r, i);
|
|
56
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* `field [not] ANY value` -- the collection operator IS the operator this preview reports.
|
|
65
|
+
*
|
|
66
|
+
* Recursing straight into `expr.condition` (what this did) hands the wrapped comparison to
|
|
67
|
+
* `extractFromComparison`, which reports the INNER operator -- `eq` by default, because
|
|
68
|
+
* both grammars default the optional inner operator to `eq`. So `f any true`, `f not any
|
|
69
|
+
* true` and `f none true` all reported `eq`: the collection operator vanished and, on the
|
|
70
|
+
* negated spellings, the preview stated the logical opposite of the query.
|
|
71
|
+
*/
|
|
72
|
+
extractFromCollection(t, r, i) {
|
|
73
|
+
if (t.condition.type !== "comparison") {
|
|
74
|
+
this.extractFieldUsage(t.condition, r, i);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const n = t.condition, c = this.collectionOperatorLabel(t, n);
|
|
78
|
+
i[c] = (i[c] || 0) + 1;
|
|
79
|
+
const a = this.getFieldInfo(n.field);
|
|
80
|
+
r.push({
|
|
81
|
+
name: a.name,
|
|
82
|
+
operator: c,
|
|
83
|
+
value: this.extractValue(n.value),
|
|
84
|
+
// The inner operator decides HOW each element is compared; the collection operator
|
|
85
|
+
// decides WHICH elements have to match. `f any gt 5` is a range match over elements.
|
|
86
|
+
matchType: this.determineMatchType(n.operator.toLowerCase(), n.value),
|
|
87
|
+
mutators: a.mutators,
|
|
88
|
+
start: t.start,
|
|
89
|
+
end: t.end
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The operator string a collection expression renders as.
|
|
94
|
+
*
|
|
95
|
+
* The shape is the one `not contains` and `not in` already use: negation lives in the
|
|
96
|
+
* operator NAME (`not_contains`, `not_in`), not in a separate flag the formatter has to
|
|
97
|
+
* remember to read. `collectionOperatorSpelling` derives `any` / `not_any` from the
|
|
98
|
+
* parser's own spelling table, so this cannot drift from what the parser accepts.
|
|
99
|
+
*
|
|
100
|
+
* An inner operator other than the implicit `eq` is appended (`any gt`), because
|
|
101
|
+
* `f any gt 5` and `f any 5` are different queries.
|
|
102
|
+
*/
|
|
103
|
+
collectionOperatorLabel(t, r) {
|
|
104
|
+
const i = g(t.operator, t.negated), n = r.operator.toLowerCase();
|
|
105
|
+
return n === "eq" ? i : `${i} ${n}`;
|
|
106
|
+
}
|
|
57
107
|
extractFromComparison(t, r, i) {
|
|
58
108
|
const n = t.operator.toLowerCase();
|
|
59
109
|
i[n] = (i[n] || 0) + 1;
|
|
60
|
-
const
|
|
110
|
+
const c = this.getFieldInfo(t.field), a = this.determineMatchType(n, t.value), s = this.extractValue(t.value);
|
|
61
111
|
r.push({
|
|
62
|
-
name:
|
|
112
|
+
name: c.name,
|
|
63
113
|
operator: n,
|
|
64
|
-
value:
|
|
114
|
+
value: s,
|
|
65
115
|
matchType: a,
|
|
66
|
-
mutators:
|
|
116
|
+
mutators: c.mutators,
|
|
67
117
|
start: t.start,
|
|
68
118
|
end: t.end
|
|
69
119
|
});
|
|
@@ -123,6 +173,12 @@ class u {
|
|
|
123
173
|
return this.buildUnaryNode(t);
|
|
124
174
|
case "comparison":
|
|
125
175
|
return this.buildComparisonNode(t);
|
|
176
|
+
// `field ANY value` -- one leaf, carrying the COLLECTION operator. Returning
|
|
177
|
+
// `buildLogicTree(expr.condition)` (what this did) returned the wrapped comparison,
|
|
178
|
+
// whose operator is the inner `eq` -- so the preview rendered `f not any true` as
|
|
179
|
+
// `f eq true`, the logical opposite of the query it was describing.
|
|
180
|
+
case "collection":
|
|
181
|
+
return this.buildCollectionNode(t);
|
|
126
182
|
case "group":
|
|
127
183
|
return this.buildGroupNode(t);
|
|
128
184
|
default:
|
|
@@ -164,6 +220,20 @@ class u {
|
|
|
164
220
|
end: t.end
|
|
165
221
|
};
|
|
166
222
|
}
|
|
223
|
+
buildCollectionNode(t) {
|
|
224
|
+
if (t.condition.type !== "comparison")
|
|
225
|
+
return this.buildLogicTree(t.condition);
|
|
226
|
+
const r = t.condition, i = this.getFieldInfo(r.field);
|
|
227
|
+
return {
|
|
228
|
+
type: "comparison",
|
|
229
|
+
field: i.name,
|
|
230
|
+
operator: this.collectionOperatorLabel(t, r),
|
|
231
|
+
value: this.extractValue(r.value),
|
|
232
|
+
mutators: i.mutators,
|
|
233
|
+
start: t.start,
|
|
234
|
+
end: t.end
|
|
235
|
+
};
|
|
236
|
+
}
|
|
167
237
|
buildGroupNode(t) {
|
|
168
238
|
return {
|
|
169
239
|
type: "group",
|
|
@@ -173,30 +243,30 @@ class u {
|
|
|
173
243
|
};
|
|
174
244
|
}
|
|
175
245
|
}
|
|
246
|
+
function b(e) {
|
|
247
|
+
return new o().generatePreview(e);
|
|
248
|
+
}
|
|
176
249
|
function T(e) {
|
|
177
|
-
return new
|
|
250
|
+
return new o().generatePreview(e).fields;
|
|
178
251
|
}
|
|
179
|
-
function
|
|
180
|
-
return new
|
|
252
|
+
function F(e) {
|
|
253
|
+
return new o().generatePreview(e).logicTree;
|
|
181
254
|
}
|
|
182
255
|
function $(e) {
|
|
183
|
-
return new
|
|
256
|
+
return new o().generatePreview(e).uniqueFields;
|
|
184
257
|
}
|
|
185
|
-
function
|
|
186
|
-
return new
|
|
187
|
-
}
|
|
188
|
-
function F(e) {
|
|
189
|
-
return new u().generatePreview(e).operatorSummary;
|
|
258
|
+
function L(e) {
|
|
259
|
+
return new o().generatePreview(e).operatorSummary;
|
|
190
260
|
}
|
|
191
261
|
function h(e) {
|
|
192
262
|
if (e.type === "comparison") {
|
|
193
|
-
const t = e.mutators?.length ? ` | ${e.mutators.join(" | ")}` : "", r =
|
|
263
|
+
const t = e.mutators?.length ? ` | ${e.mutators.join(" | ")}` : "", r = d(e.value);
|
|
194
264
|
return `${e.field}${t} ${e.operator} ${r}`;
|
|
195
265
|
}
|
|
196
266
|
return e.type === "NOT" && e.children?.length === 1 ? `NOT (${h(e.children[0])})` : e.type === "group" && e.children?.length === 1 ? `(${h(e.children[0])})` : (e.type === "AND" || e.type === "OR") && e.children ? e.children.map(h).join(` ${e.type} `) : "";
|
|
197
267
|
}
|
|
198
|
-
function
|
|
199
|
-
return e === null ? "null" : e === void 0 ? "" : typeof e == "string" ? `"${e}"` : Array.isArray(e) ? `[${e.map(
|
|
268
|
+
function d(e) {
|
|
269
|
+
return e === null ? "null" : e === void 0 ? "" : typeof e == "string" ? `"${e}"` : Array.isArray(e) ? `[${e.map(d).join(", ")}]` : String(e);
|
|
200
270
|
}
|
|
201
271
|
function N(e, t = "") {
|
|
202
272
|
if (!e)
|
|
@@ -206,35 +276,35 @@ function N(e, t = "") {
|
|
|
206
276
|
`);
|
|
207
277
|
}
|
|
208
278
|
function l(e, t, r, i) {
|
|
209
|
-
const n = i ? "└── " : "├── ",
|
|
279
|
+
const n = i ? "└── " : "├── ", c = i ? " " : "│ ";
|
|
210
280
|
if (e.type === "comparison") {
|
|
211
|
-
const a = e.mutators?.length ? ` | ${e.mutators.join(" | ")}` : "",
|
|
212
|
-
t.push(`${r}${n}${e.field}${a} ${e.operator} ${
|
|
213
|
-
} else e.type === "NOT" ? (t.push(`${r}${n}NOT`), e.children?.length && l(e.children[0], t, r +
|
|
214
|
-
const
|
|
215
|
-
l(a, t, r +
|
|
281
|
+
const a = e.mutators?.length ? ` | ${e.mutators.join(" | ")}` : "", s = d(e.value);
|
|
282
|
+
t.push(`${r}${n}${e.field}${a} ${e.operator} ${s}`);
|
|
283
|
+
} else e.type === "NOT" ? (t.push(`${r}${n}NOT`), e.children?.length && l(e.children[0], t, r + c, !0)) : e.type === "group" ? (t.push(`${r}${n}GROUP`), e.children?.length && l(e.children[0], t, r + c, !0)) : e.children && (t.push(`${r}${n}${e.type}`), e.children.forEach((a, s) => {
|
|
284
|
+
const u = s === e.children.length - 1;
|
|
285
|
+
l(a, t, r + c, u);
|
|
216
286
|
}));
|
|
217
287
|
}
|
|
218
|
-
function d(e) {
|
|
219
|
-
return e ? e.type === "comparison" ? [e] : e.children ? e.children.flatMap(d) : [] : [];
|
|
220
|
-
}
|
|
221
288
|
function y(e) {
|
|
289
|
+
return e ? e.type === "comparison" ? [e] : e.children ? e.children.flatMap(y) : [] : [];
|
|
290
|
+
}
|
|
291
|
+
function p(e) {
|
|
222
292
|
if (!e)
|
|
223
293
|
return 0;
|
|
224
294
|
if (!e.children || e.children.length === 0)
|
|
225
295
|
return 1;
|
|
226
|
-
const t = e.children.map(
|
|
296
|
+
const t = e.children.map(p);
|
|
227
297
|
return 1 + Math.max(...t);
|
|
228
298
|
}
|
|
229
299
|
export {
|
|
230
|
-
|
|
231
|
-
|
|
300
|
+
o as SemanticPreview,
|
|
301
|
+
y as flattenLogicTree,
|
|
232
302
|
N as formatLogicTreeAscii,
|
|
233
303
|
h as formatLogicTreeNode,
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
304
|
+
b as generatePreview,
|
|
305
|
+
T as getFieldUsage,
|
|
306
|
+
F as getLogicTree,
|
|
307
|
+
p as getLogicTreeDepth,
|
|
308
|
+
L as getOperatorSummary,
|
|
309
|
+
$ as getUniqueFields
|
|
240
310
|
};
|
package/dist/src/tokenizer.d.ts
CHANGED
|
@@ -2,10 +2,25 @@ import { TqlAggregationFunction, TqlCollectionOperator, TqlComparisonOperator, T
|
|
|
2
2
|
/**
|
|
3
3
|
* All comparison operators supported by TQL.
|
|
4
4
|
* Includes negated variants using both `not_` prefix and `!` prefix.
|
|
5
|
+
*
|
|
6
|
+
* Checked against both engines by `tests/catalogParity.spec.ts`, which derives the operator
|
|
7
|
+
* sets from `tql/src/parser/grammar.pest` and `src/tql/parser_components/grammar.py` at test
|
|
8
|
+
* time. Adding a name here that neither engine accepts fails that test.
|
|
5
9
|
*/
|
|
6
10
|
export declare const COMPARISON_OPERATORS: TqlComparisonOperator[];
|
|
7
11
|
/**
|
|
8
12
|
* Symbol-based operators mapped to their word equivalents.
|
|
13
|
+
*
|
|
14
|
+
* `==` is deliberately absent. TQL's equality symbol is a SINGLE `=`
|
|
15
|
+
* (`eq_op = { ^"eq" | "=" }` in tql/src/parser/grammar.pest), and the Python parser
|
|
16
|
+
* rejects `==` outright with "Invalid operator '==' ... Use '=' for equality"
|
|
17
|
+
* (src/tql/parser_components/error_analyzer.py). Mapping it to `eq` here made the editor
|
|
18
|
+
* green-light a query that fails the moment it is run — the inverse, and worse, of a false
|
|
19
|
+
* red squiggle: the user gets no warning until execution.
|
|
20
|
+
*
|
|
21
|
+
* The tokenizer still lexes `==` as one operator token (see `scanSymbolOperator`) so the
|
|
22
|
+
* parser can name it in a single targeted error rather than splintering it into `=` + `=`
|
|
23
|
+
* and emitting a cascade.
|
|
9
24
|
*/
|
|
10
25
|
export declare const SYMBOL_OPERATORS: Record<string, TqlComparisonOperator>;
|
|
11
26
|
/**
|
|
@@ -13,23 +28,137 @@ export declare const SYMBOL_OPERATORS: Record<string, TqlComparisonOperator>;
|
|
|
13
28
|
*/
|
|
14
29
|
export declare const NEGATION_SYMBOL_OPERATORS: Record<string, TqlComparisonOperator>;
|
|
15
30
|
export declare const LOGICAL_OPERATORS: TqlLogicalOperator[];
|
|
31
|
+
/**
|
|
32
|
+
* Symbolic spellings of the three logical operators, mapped to their canonical words.
|
|
33
|
+
*
|
|
34
|
+
* All three are declared in the engine grammars alongside the words, in the SAME rule:
|
|
35
|
+
* `and_op = @{ ^"and" ~ word_end | "&&" }`, `or_op = @{ ^"or" ~ word_end | "||" }` and
|
|
36
|
+
* `not_op = @{ ^"not" ~ word_end | "!" }` (`tql/src/parser/grammar.pest`); Python's
|
|
37
|
+
* `_setup_operators` builds the same alternations. So `a eq 1 && b eq 2` is not a
|
|
38
|
+
* convenience this package invented — it is one of two spellings of one operator, and both
|
|
39
|
+
* engines produce an IDENTICAL AST for the two.
|
|
40
|
+
*
|
|
41
|
+
* This package accepted neither. `&&` lexed as two `unknown` tokens and `||` as two `pipe`
|
|
42
|
+
* tokens, so a query both engines run was reported as `Unexpected token '&'` — a false red
|
|
43
|
+
* on syntax the product documents.
|
|
44
|
+
*
|
|
45
|
+
* Single `&` and single `|` are deliberately NOT here. Neither engine accepts them
|
|
46
|
+
* (`a eq 1 & b eq 2` raises `TQLSyntaxError at position 7` in Python, measured), and `|` is
|
|
47
|
+
* TQL's mutator pipe, so folding it into OR would silently reinterpret `f | lowercase`.
|
|
48
|
+
*/
|
|
49
|
+
export declare const SYMBOL_LOGICAL_OPERATORS: Record<string, TqlLogicalOperator>;
|
|
16
50
|
export declare const COLLECTION_OPERATORS: TqlCollectionOperator[];
|
|
17
51
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
52
|
+
* The mutator names this package offers for autocomplete.
|
|
53
|
+
*
|
|
54
|
+
* This list is NOT self-evidently in agreement with the engines, and for most of its life
|
|
55
|
+
* it was not: the docstring said "Synchronized with Python/Rust implementations" while it
|
|
56
|
+
* was synchronized with Rust only, and four names here — `geoip`, `is_loopback`,
|
|
57
|
+
* `is_multicast`, `is_link_local` — are rejected by the Python evaluator, which is what the
|
|
58
|
+
* backend query API runs.
|
|
59
|
+
*
|
|
60
|
+
* That claim is now checked rather than asserted. `tests/registryParity.spec.ts` reads the
|
|
61
|
+
* Rust dispatch table, Rust's `MUTATOR_NAMES`, Python's `ALLOWED_MUTATORS` and the
|
|
62
|
+
* `TqlMutator` union FROM SOURCE and asserts set equality across all five surfaces, with
|
|
63
|
+
* the four known divergences pinned by name so they fail if they change in either
|
|
64
|
+
* direction. Editing this list without editing the engines fails that test.
|
|
65
|
+
*
|
|
66
|
+
* Comparison operators and type hints get the same treatment in
|
|
67
|
+
* `tests/catalogParity.spec.ts`. Do not restore a bare "synchronized with X" comment
|
|
68
|
+
* anywhere here: an invariant nothing enforces reads exactly like one that is enforced.
|
|
20
69
|
*/
|
|
21
70
|
export declare const MUTATORS: TqlMutator[];
|
|
71
|
+
/**
|
|
72
|
+
* The mutators that answer a BOOLEAN, so `field | <name>` with no operator is a FILTER.
|
|
73
|
+
*
|
|
74
|
+
* ## Why this is a named set and not four characters of `startsWith("is_")`
|
|
75
|
+
*
|
|
76
|
+
* `1c1d74d` made `ip | is_private` mean `ip | is_private eq true` in both engines. Before
|
|
77
|
+
* it, the bare form meant `exists` — it matched every record that HAS an `ip` field at all,
|
|
78
|
+
* while reading as a filter. That is the worst shape in this codebase: a clause that cannot
|
|
79
|
+
* fail loudly, it just quietly stops filtering and keeps returning plausible results.
|
|
80
|
+
* `1c1d74d` retires it as a documented breaking change.
|
|
81
|
+
*
|
|
82
|
+
* Both engines DERIVE the set rather than listing it, and both got there after being burned
|
|
83
|
+
* by a list:
|
|
84
|
+
*
|
|
85
|
+
* - **Rust** — `Mutator::returns_boolean` is a trait method defaulting to `false`; the
|
|
86
|
+
* parser asks `mutators::returns_boolean(name)` and enumerates nothing.
|
|
87
|
+
* - **Python** — `BOOLEAN_PREDICATE_MUTATORS` in `src/tql/mutator_classification.py`, one
|
|
88
|
+
* frozenset. It used to be a literal `["is_private", "is_global"]` written out in THREE
|
|
89
|
+
* places in `parser.py`, and when `is_loopback` / `is_multicast` / `is_link_local` were
|
|
90
|
+
* added they reached none of them — so two of five predicates filtered and three
|
|
91
|
+
* silently did not.
|
|
92
|
+
*
|
|
93
|
+
* This package cannot import either, so it holds the only hand-written copy in the product.
|
|
94
|
+
* That is a liability, and `tests/booleanPredicateSugar.spec.ts` is the mitigation: it reads
|
|
95
|
+
* Rust's `returns_boolean` overrides and Python's frozenset FROM SOURCE and asserts all
|
|
96
|
+
* three name the same five. Adding a predicate to an engine without adding it here fails
|
|
97
|
+
* that spec, and so does the reverse. Do not edit this list on its own.
|
|
98
|
+
*
|
|
99
|
+
* Note that `any` and `all` also yield booleans but are NOT here: they are collection
|
|
100
|
+
* operators, this package lexes them as `collectionOp`, and neither engine's predicate set
|
|
101
|
+
* contains them. Their output type is declared separately in `completionProvider.ts`.
|
|
102
|
+
*/
|
|
103
|
+
export declare const BOOLEAN_PREDICATE_MUTATORS: TqlMutator[];
|
|
104
|
+
/** Membership form of {@link BOOLEAN_PREDICATE_MUTATORS}, for parser hot paths. */
|
|
105
|
+
export declare const BOOLEAN_PREDICATE_MUTATOR_SET: ReadonlySet<string>;
|
|
22
106
|
/**
|
|
23
107
|
* All aggregation functions supported by TQL.
|
|
24
|
-
*
|
|
108
|
+
*
|
|
109
|
+
* Unlike MUTATORS, COMPARISON_OPERATORS and TYPE_HINTS, this one is NOT derived from the
|
|
110
|
+
* engines: neither exposes an aggregation registry to read — the surface is spread across
|
|
111
|
+
* `stats_evaluator` branches on both sides. `tests/catalogParity.spec.ts` asserts only that
|
|
112
|
+
* this list covers a transcribed core set, which is a floor and not a parity guarantee.
|
|
25
113
|
*/
|
|
26
114
|
export declare const AGGREGATION_FUNCTIONS: TqlAggregationFunction[];
|
|
27
115
|
/**
|
|
28
|
-
* Type hints for field type specification.
|
|
116
|
+
* Type hints for field type specification: `field::ip eq "10.0.0.1"`.
|
|
117
|
+
*
|
|
118
|
+
* Derived-and-checked, not transcribed. `tests/catalogParity.spec.ts` reads the Rust
|
|
119
|
+
* `type_name` rule out of `grammar.pest` and Python's `KNOWN_TYPE_HINTS` out of
|
|
120
|
+
* `src/tql/evaluator_components/field_access.py` — the set Python's grammar interpolates —
|
|
121
|
+
* and asserts exact three-way equality minus an explicit pin list. Adding a name here that
|
|
122
|
+
* neither engine accepts fails that test, and so does dropping one that both accept.
|
|
123
|
+
*
|
|
124
|
+
* The two engines now accept the SAME sixteen names, so this list is that set rather than a
|
|
125
|
+
* union papering over a disagreement. It was a union until `a12d842`: Rust's `type_name`
|
|
126
|
+
* omitted `date`, `geo`, `object` and `ip`, deliberately, because Rust parsed a type hint
|
|
127
|
+
* and read it nowhere and adding names to a layer that consumes none turns a loud parse
|
|
128
|
+
* error into a silent no-op. That commit made the Rust evaluator honour hints and then
|
|
129
|
+
* widened the rule, and the four pins recording the gap went red and were deleted.
|
|
130
|
+
*
|
|
131
|
+
* `ip` is the one to know about: a fully-implemented Python coercion branch — format
|
|
132
|
+
* validation, CIDR handling for the `cidr` operator, its own error message — that no query
|
|
133
|
+
* could reach in either engine until `b338476`, and which this package could not classify.
|
|
29
134
|
*/
|
|
30
135
|
export declare const TYPE_HINTS: TqlTypeHint[];
|
|
31
136
|
/**
|
|
32
|
-
*
|
|
137
|
+
* Chart types accepted after `=>` in a stats pipeline: `| stats count() by host => bar`.
|
|
138
|
+
*
|
|
139
|
+
* ## What enforces this list, and what does not
|
|
140
|
+
*
|
|
141
|
+
* It is a REAL contract, and against exactly one engine. The Python grammar declares
|
|
142
|
+
* `self.viz_types = one_of("bar barchart horizontal_bar ...", caseless=True)`
|
|
143
|
+
* (`src/tql/parser_components/grammar.py`) — a CLOSED set, so the backend query API rejects
|
|
144
|
+
* a chart type that is not in it (`=> zzznotaviz` raises `TQLSyntaxError`, measured). A name
|
|
145
|
+
* added here and not there is a name the editor completes and the API refuses, which is the
|
|
146
|
+
* same defect `field::geo` and `not_any` were.
|
|
147
|
+
*
|
|
148
|
+
* Rust is permissive by comparison: `viz_hint = { "=>" ~ identifier ~ viz_params? }`
|
|
149
|
+
* (`tql/src/parser/grammar.pest`) accepts ANY identifier, so it validates nothing and cannot
|
|
150
|
+
* be the authority here. That asymmetry is a live Rust/Python divergence, pinned in
|
|
151
|
+
* `tests/catalogParity.spec.ts` rather than resolved in this package.
|
|
152
|
+
*
|
|
153
|
+
* Within `js/` the list drives two things and neither validates: `classifyIdentifier` uses it
|
|
154
|
+
* for the `visualization` token class (syntax highlighting), and `getVizCompletions` for
|
|
155
|
+
* autocomplete. `parseVizHintString` in `builder.ts` casts whatever it is given to
|
|
156
|
+
* `TqlVisualizationType` without checking membership — see its own note. So a wrong name is
|
|
157
|
+
* caught by the Python parser at execution and by nothing before it.
|
|
158
|
+
*
|
|
159
|
+
* Do not restore a bare "Visualization types for stats pipeline" comment here. A list whose
|
|
160
|
+
* enforcement is unstated reads exactly like a list with none, and this one has real
|
|
161
|
+
* enforcement in a place a reader of this file would not think to look.
|
|
33
162
|
*/
|
|
34
163
|
export declare const VISUALIZATION_TYPES: TqlVisualizationType[];
|
|
35
164
|
/**
|