@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
package/dist/src/tokenizer.js
CHANGED
|
@@ -52,7 +52,6 @@ const l = [
|
|
|
52
52
|
"not_all",
|
|
53
53
|
"not_none"
|
|
54
54
|
], h = {
|
|
55
|
-
"==": "eq",
|
|
56
55
|
"=": "eq",
|
|
57
56
|
"!=": "ne",
|
|
58
57
|
">": "gt",
|
|
@@ -78,7 +77,11 @@ const l = [
|
|
|
78
77
|
"!any": "not_any",
|
|
79
78
|
"!all": "not_all",
|
|
80
79
|
"!none": "not_none"
|
|
81
|
-
},
|
|
80
|
+
}, p = ["AND", "OR", "NOT"], b = {
|
|
81
|
+
"&&": "AND",
|
|
82
|
+
"||": "OR",
|
|
83
|
+
"!": "NOT"
|
|
84
|
+
}, d = ["ANY", "ALL", "NONE"], k = [
|
|
82
85
|
// String mutators
|
|
83
86
|
"lowercase",
|
|
84
87
|
"uppercase",
|
|
@@ -117,6 +120,14 @@ const l = [
|
|
|
117
120
|
"min",
|
|
118
121
|
"max"
|
|
119
122
|
], _ = [
|
|
123
|
+
"is_private",
|
|
124
|
+
"is_global",
|
|
125
|
+
"is_loopback",
|
|
126
|
+
"is_multicast",
|
|
127
|
+
"is_link_local"
|
|
128
|
+
], A = new Set(
|
|
129
|
+
_
|
|
130
|
+
), f = [
|
|
120
131
|
// Counting
|
|
121
132
|
"count",
|
|
122
133
|
"unique_count",
|
|
@@ -145,7 +156,7 @@ const l = [
|
|
|
145
156
|
"values",
|
|
146
157
|
"unique",
|
|
147
158
|
"distinct"
|
|
148
|
-
],
|
|
159
|
+
], m = [
|
|
149
160
|
"string",
|
|
150
161
|
"str",
|
|
151
162
|
"number",
|
|
@@ -160,8 +171,9 @@ const l = [
|
|
|
160
171
|
"array",
|
|
161
172
|
"list",
|
|
162
173
|
"object",
|
|
163
|
-
"geo"
|
|
164
|
-
|
|
174
|
+
"geo",
|
|
175
|
+
"ip"
|
|
176
|
+
], T = [
|
|
165
177
|
"bar",
|
|
166
178
|
"barchart",
|
|
167
179
|
"horizontal_bar",
|
|
@@ -184,23 +196,23 @@ const l = [
|
|
|
184
196
|
"nested_donut",
|
|
185
197
|
"chord",
|
|
186
198
|
"auto"
|
|
187
|
-
],
|
|
188
|
-
class
|
|
199
|
+
], g = ["by", "as", "null", "true", "false", "stats", "top", "bottom"];
|
|
200
|
+
class w {
|
|
189
201
|
input;
|
|
190
202
|
position;
|
|
191
203
|
line;
|
|
192
204
|
column;
|
|
193
205
|
tokens;
|
|
194
|
-
constructor(
|
|
195
|
-
this.input =
|
|
206
|
+
constructor(e) {
|
|
207
|
+
this.input = e ?? "", this.position = 0, this.line = 1, this.column = 1, this.tokens = [];
|
|
196
208
|
}
|
|
197
209
|
/**
|
|
198
210
|
* Tokenize the entire input string
|
|
199
211
|
*/
|
|
200
212
|
tokenize() {
|
|
201
213
|
for (this.tokens = [], this.position = 0, this.line = 1, this.column = 1; !this.isAtEnd(); ) {
|
|
202
|
-
const
|
|
203
|
-
|
|
214
|
+
const e = this.scanToken();
|
|
215
|
+
e && this.tokens.push(e);
|
|
204
216
|
}
|
|
205
217
|
return this.tokens;
|
|
206
218
|
}
|
|
@@ -210,42 +222,46 @@ class g {
|
|
|
210
222
|
scanToken() {
|
|
211
223
|
if (this.isWhitespace(this.peek()))
|
|
212
224
|
return this.scanWhitespace();
|
|
213
|
-
const
|
|
214
|
-
|
|
225
|
+
const e = this.position, n = this.line, i = this.column, t = this.advance();
|
|
226
|
+
if ((t === "&" || t === "|") && this.peek() === t)
|
|
227
|
+
return this.advance(), this.makeToken("logicalOp", t + t, e, n, i);
|
|
228
|
+
switch (t) {
|
|
215
229
|
case "(":
|
|
216
230
|
case ")":
|
|
217
|
-
return this.makeToken("paren",
|
|
231
|
+
return this.makeToken("paren", t, e, n, i);
|
|
218
232
|
case "[":
|
|
219
233
|
case "]":
|
|
220
|
-
return this.makeToken("bracket",
|
|
234
|
+
return this.makeToken("bracket", t, e, n, i);
|
|
221
235
|
case ",":
|
|
222
|
-
return this.makeToken("comma",
|
|
236
|
+
return this.makeToken("comma", t, e, n, i);
|
|
223
237
|
case "|":
|
|
224
|
-
return this.makeToken("pipe",
|
|
238
|
+
return this.makeToken("pipe", t, e, n, i);
|
|
225
239
|
}
|
|
226
|
-
return
|
|
240
|
+
return t === "=" && this.peek() === ">" ? (this.advance(), this.makeToken("arrow", "=>", e, n, i)) : t === ":" && this.peek() === ":" ? (this.advance(), this.makeToken("doubleColon", "::", e, n, i)) : t === '"' || t === "'" ? this.scanString(t, e, n, i) : this.isDigit(t) || t === "-" && this.isDigit(this.peek()) ? this.scanNumber(e, n, i) : this.isOperatorChar(t) ? this.scanSymbolOperator(e, n, i) : this.isIdentifierStart(t) ? this.scanIdentifier(e, n, i) : this.makeToken("unknown", t, e, n, i);
|
|
227
241
|
}
|
|
228
242
|
/**
|
|
229
243
|
* Scan whitespace characters
|
|
230
244
|
*/
|
|
231
245
|
scanWhitespace() {
|
|
232
|
-
const
|
|
233
|
-
let
|
|
246
|
+
const e = this.position, n = this.line, i = this.column;
|
|
247
|
+
let t = "";
|
|
234
248
|
for (; !this.isAtEnd() && this.isWhitespace(this.peek()); ) {
|
|
235
249
|
const s = this.advance();
|
|
236
|
-
|
|
250
|
+
t += s;
|
|
237
251
|
}
|
|
238
|
-
return this.makeToken("whitespace",
|
|
252
|
+
return this.makeToken("whitespace", t, e, n, i);
|
|
239
253
|
}
|
|
240
254
|
/**
|
|
241
255
|
* Scan a string literal (single or double quoted)
|
|
242
256
|
*/
|
|
243
|
-
scanString(
|
|
257
|
+
scanString(e, n, i, t) {
|
|
244
258
|
let s = "";
|
|
245
|
-
const r =
|
|
246
|
-
for (; !this.isAtEnd() && this.peek() !==
|
|
247
|
-
if (this.peek() === "\\")
|
|
248
|
-
if (this.advance(),
|
|
259
|
+
const r = e;
|
|
260
|
+
for (; !this.isAtEnd() && this.peek() !== e; )
|
|
261
|
+
if (this.peek() === "\\")
|
|
262
|
+
if (this.advance(), this.isAtEnd())
|
|
263
|
+
s += "\\";
|
|
264
|
+
else {
|
|
249
265
|
const a = this.advance();
|
|
250
266
|
switch (a) {
|
|
251
267
|
case "n":
|
|
@@ -268,10 +284,10 @@ class g {
|
|
|
268
284
|
s += "'";
|
|
269
285
|
break;
|
|
270
286
|
default:
|
|
271
|
-
s += a;
|
|
287
|
+
s += "\\" + a;
|
|
272
288
|
}
|
|
273
289
|
}
|
|
274
|
-
|
|
290
|
+
else
|
|
275
291
|
s += this.advance();
|
|
276
292
|
return this.isAtEnd() ? {
|
|
277
293
|
type: "error",
|
|
@@ -279,7 +295,7 @@ class g {
|
|
|
279
295
|
start: n,
|
|
280
296
|
end: this.position,
|
|
281
297
|
line: i,
|
|
282
|
-
column:
|
|
298
|
+
column: t,
|
|
283
299
|
raw: r + s
|
|
284
300
|
} : (this.advance(), {
|
|
285
301
|
type: "string",
|
|
@@ -287,88 +303,88 @@ class g {
|
|
|
287
303
|
start: n,
|
|
288
304
|
end: this.position,
|
|
289
305
|
line: i,
|
|
290
|
-
column:
|
|
291
|
-
raw:
|
|
306
|
+
column: t,
|
|
307
|
+
raw: e + s + e
|
|
292
308
|
});
|
|
293
309
|
}
|
|
294
310
|
/**
|
|
295
311
|
* Scan a numeric literal
|
|
296
312
|
*/
|
|
297
|
-
scanNumber(
|
|
298
|
-
this.position =
|
|
299
|
-
let
|
|
300
|
-
for (this.peek() === "-" && (
|
|
301
|
-
|
|
313
|
+
scanNumber(e, n, i) {
|
|
314
|
+
this.position = e, this.column = i;
|
|
315
|
+
let t = "";
|
|
316
|
+
for (this.peek() === "-" && (t += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
|
|
317
|
+
t += this.advance();
|
|
302
318
|
if (this.peek() === "." && this.isDigit(this.peekNext()))
|
|
303
|
-
for (
|
|
304
|
-
|
|
319
|
+
for (t += this.advance(); !this.isAtEnd() && this.isDigit(this.peek()); )
|
|
320
|
+
t += this.advance();
|
|
305
321
|
if (this.peek() === "e" || this.peek() === "E")
|
|
306
|
-
for (
|
|
307
|
-
|
|
308
|
-
return this.makeToken("number",
|
|
322
|
+
for (t += this.advance(), (this.peek() === "+" || this.peek() === "-") && (t += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
|
|
323
|
+
t += this.advance();
|
|
324
|
+
return this.makeToken("number", t, e, n, i);
|
|
309
325
|
}
|
|
310
326
|
/**
|
|
311
327
|
* Scan symbol-based operators (==, !=, >, >=, <, <=, !)
|
|
312
328
|
*/
|
|
313
|
-
scanSymbolOperator(
|
|
314
|
-
this.position =
|
|
315
|
-
let
|
|
329
|
+
scanSymbolOperator(e, n, i) {
|
|
330
|
+
this.position = e, this.column = i;
|
|
331
|
+
let t = this.advance();
|
|
316
332
|
if (!this.isAtEnd()) {
|
|
317
|
-
const s =
|
|
333
|
+
const s = t + this.peek();
|
|
318
334
|
if (s === "=>")
|
|
319
|
-
return this.advance(), this.makeToken("arrow", "=>",
|
|
320
|
-
(s in h || s === "==" || s === "!=") && (
|
|
335
|
+
return this.advance(), this.makeToken("arrow", "=>", e, n, i);
|
|
336
|
+
(s in h || s === "==" || s === "!=") && (t = s, this.advance());
|
|
321
337
|
}
|
|
322
|
-
if (
|
|
338
|
+
if (t === "!") {
|
|
323
339
|
const s = this.position;
|
|
324
340
|
let r = "";
|
|
325
341
|
for (; !this.isAtEnd() && this.isIdentifierChar(this.peek()); )
|
|
326
342
|
r += this.advance();
|
|
327
343
|
if (r) {
|
|
328
344
|
if ("!" + r in u)
|
|
329
|
-
return this.makeToken("operator", "!" + r,
|
|
345
|
+
return this.makeToken("operator", "!" + r, e, n, i);
|
|
330
346
|
this.position = s, this.column = i + 1;
|
|
331
347
|
}
|
|
332
348
|
}
|
|
333
|
-
return
|
|
349
|
+
return t in h || t === "==" || t === "=" || t === "!=" || t === ">" || t === ">=" || t === "<" || t === "<=" ? this.makeToken("operator", t, e, n, i) : t === "!" ? this.makeToken("logicalOp", t, e, n, i) : this.makeToken("unknown", t, e, n, i);
|
|
334
350
|
}
|
|
335
351
|
/**
|
|
336
352
|
* Scan an identifier (field name, operator keyword, etc.)
|
|
337
353
|
*/
|
|
338
|
-
scanIdentifier(
|
|
339
|
-
this.position =
|
|
340
|
-
let
|
|
354
|
+
scanIdentifier(e, n, i) {
|
|
355
|
+
this.position = e, this.column = i;
|
|
356
|
+
let t = "";
|
|
341
357
|
const s = this.advance();
|
|
342
|
-
if (
|
|
343
|
-
return this.makeToken("unknown",
|
|
358
|
+
if (t += s, s === "@" && this.peek() === "@")
|
|
359
|
+
return this.makeToken("unknown", t, e, n, i);
|
|
344
360
|
let r = s;
|
|
345
361
|
for (; !this.isAtEnd() && this.isIdentifierChar(this.peek()); ) {
|
|
346
362
|
const c = this.advance();
|
|
347
363
|
if (c === "." && r === ".")
|
|
348
|
-
return this.position--, this.column--,
|
|
349
|
-
|
|
364
|
+
return this.position--, this.column--, t = t.slice(0, -1), this.makeToken("unknown", t, e, n, i);
|
|
365
|
+
t += c, r = c;
|
|
350
366
|
}
|
|
351
|
-
|
|
352
|
-
const a = this.classifyIdentifier(
|
|
353
|
-
return this.makeToken(a,
|
|
367
|
+
t.endsWith(".") && (this.position--, this.column--, t = t.slice(0, -1));
|
|
368
|
+
const a = this.classifyIdentifier(t);
|
|
369
|
+
return this.makeToken(a, t, e, n, i);
|
|
354
370
|
}
|
|
355
371
|
/**
|
|
356
372
|
* Classify an identifier into the appropriate token type
|
|
357
373
|
*/
|
|
358
|
-
classifyIdentifier(
|
|
359
|
-
const n =
|
|
360
|
-
return
|
|
374
|
+
classifyIdentifier(e) {
|
|
375
|
+
const n = e.toUpperCase(), i = e.toLowerCase();
|
|
376
|
+
return p.includes(n) ? "logicalOp" : d.includes(n) ? "collectionOp" : i === "true" || i === "false" ? "boolean" : i === "null" ? "null" : i === "stats" ? "keyword" : l.includes(i) ? "operator" : f.includes(i) ? "aggregation" : k.includes(i) ? "mutator" : m.includes(i) ? "typeHint" : T.includes(i) ? "visualization" : g.includes(i) ? "keyword" : "field";
|
|
361
377
|
}
|
|
362
378
|
// ============================================================================
|
|
363
379
|
// Helper Methods
|
|
364
380
|
// ============================================================================
|
|
365
|
-
makeToken(
|
|
381
|
+
makeToken(e, n, i, t, s) {
|
|
366
382
|
return {
|
|
367
|
-
type:
|
|
383
|
+
type: e,
|
|
368
384
|
value: n,
|
|
369
385
|
start: i,
|
|
370
386
|
end: this.position,
|
|
371
|
-
line:
|
|
387
|
+
line: t,
|
|
372
388
|
column: s
|
|
373
389
|
};
|
|
374
390
|
}
|
|
@@ -382,81 +398,84 @@ class g {
|
|
|
382
398
|
return this.position + 1 >= this.input.length ? "\0" : this.input[this.position + 1];
|
|
383
399
|
}
|
|
384
400
|
advance() {
|
|
385
|
-
const
|
|
386
|
-
return this.position++,
|
|
387
|
-
` ? (this.line++, this.column = 1) : this.column++,
|
|
401
|
+
const e = this.input[this.position];
|
|
402
|
+
return this.position++, e === `
|
|
403
|
+
` ? (this.line++, this.column = 1) : this.column++, e;
|
|
388
404
|
}
|
|
389
|
-
isWhitespace(
|
|
390
|
-
return
|
|
391
|
-
` ||
|
|
405
|
+
isWhitespace(e) {
|
|
406
|
+
return e === " " || e === " " || e === `
|
|
407
|
+
` || e === "\r";
|
|
392
408
|
}
|
|
393
|
-
isDigit(
|
|
394
|
-
return
|
|
409
|
+
isDigit(e) {
|
|
410
|
+
return e >= "0" && e <= "9";
|
|
395
411
|
}
|
|
396
|
-
isIdentifierStart(
|
|
397
|
-
return
|
|
412
|
+
isIdentifierStart(e) {
|
|
413
|
+
return e >= "a" && e <= "z" || e >= "A" && e <= "Z" || e === "_" || e === "@";
|
|
398
414
|
}
|
|
399
415
|
/**
|
|
400
416
|
* Check if char can continue an identifier (NOT including @ which is only valid at start)
|
|
401
417
|
*/
|
|
402
|
-
isIdentifierChar(
|
|
403
|
-
return
|
|
404
|
-
|
|
418
|
+
isIdentifierChar(e) {
|
|
419
|
+
return e >= "a" && e <= "z" || e >= "A" && e <= "Z" || e === "_" || this.isDigit(e) || e === "." || // For nested field access
|
|
420
|
+
e === "-";
|
|
405
421
|
}
|
|
406
|
-
isOperatorChar(
|
|
407
|
-
return
|
|
422
|
+
isOperatorChar(e) {
|
|
423
|
+
return e === "=" || e === "!" || e === ">" || e === "<";
|
|
408
424
|
}
|
|
409
425
|
}
|
|
410
|
-
function
|
|
411
|
-
return new
|
|
426
|
+
function O(o) {
|
|
427
|
+
return new w(o).tokenize();
|
|
412
428
|
}
|
|
413
|
-
function
|
|
414
|
-
return
|
|
429
|
+
function v(o) {
|
|
430
|
+
return O(o).filter((e) => e.type !== "whitespace");
|
|
415
431
|
}
|
|
416
|
-
function
|
|
432
|
+
function E(o, e) {
|
|
417
433
|
for (const n of o)
|
|
418
|
-
if (
|
|
434
|
+
if (e >= n.start && e < n.end)
|
|
419
435
|
return n;
|
|
420
436
|
return null;
|
|
421
437
|
}
|
|
422
|
-
function
|
|
423
|
-
return o.filter((i) => i.start < n && i.end >
|
|
438
|
+
function S(o, e, n) {
|
|
439
|
+
return o.filter((i) => i.start < n && i.end > e);
|
|
424
440
|
}
|
|
425
|
-
function
|
|
441
|
+
function I(o, e) {
|
|
426
442
|
let n = null;
|
|
427
443
|
for (const i of o)
|
|
428
|
-
if (i.end <=
|
|
444
|
+
if (i.end <= e)
|
|
429
445
|
n = i;
|
|
430
446
|
else
|
|
431
447
|
break;
|
|
432
448
|
return n;
|
|
433
449
|
}
|
|
434
|
-
function
|
|
450
|
+
function N(o, e, n = !0) {
|
|
435
451
|
const i = n ? o.filter((s) => s.type !== "whitespace") : o;
|
|
436
|
-
let
|
|
452
|
+
let t = null;
|
|
437
453
|
for (const s of i)
|
|
438
|
-
if (s.end <=
|
|
439
|
-
|
|
454
|
+
if (s.end <= e)
|
|
455
|
+
t = s;
|
|
440
456
|
else
|
|
441
457
|
break;
|
|
442
|
-
return
|
|
458
|
+
return t;
|
|
443
459
|
}
|
|
444
460
|
export {
|
|
445
|
-
|
|
446
|
-
|
|
461
|
+
f as AGGREGATION_FUNCTIONS,
|
|
462
|
+
_ as BOOLEAN_PREDICATE_MUTATORS,
|
|
463
|
+
A as BOOLEAN_PREDICATE_MUTATOR_SET,
|
|
464
|
+
d as COLLECTION_OPERATORS,
|
|
447
465
|
l as COMPARISON_OPERATORS,
|
|
448
|
-
|
|
449
|
-
|
|
466
|
+
g as KEYWORDS,
|
|
467
|
+
p as LOGICAL_OPERATORS,
|
|
450
468
|
k as MUTATORS,
|
|
451
469
|
u as NEGATION_SYMBOL_OPERATORS,
|
|
470
|
+
b as SYMBOL_LOGICAL_OPERATORS,
|
|
452
471
|
h as SYMBOL_OPERATORS,
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
472
|
+
m as TYPE_HINTS,
|
|
473
|
+
w as TqlTokenizer,
|
|
474
|
+
T as VISUALIZATION_TYPES,
|
|
475
|
+
N as findPreviousToken,
|
|
476
|
+
E as findTokenAtPosition,
|
|
477
|
+
I as findTokenBefore,
|
|
478
|
+
S as findTokensInRange,
|
|
479
|
+
O as tokenizeTql,
|
|
480
|
+
v as tokenizeTqlNoWhitespace
|
|
462
481
|
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -38,9 +38,25 @@ export interface TqlComparisonExpression {
|
|
|
38
38
|
start: number;
|
|
39
39
|
end: number;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* `field ANY value` and its relatives — a comparison applied across the ELEMENTS of an
|
|
43
|
+
* array-valued field rather than to the field as a whole.
|
|
44
|
+
*
|
|
45
|
+
* This type shipped for a long time with no parse path that could produce it: the tokenizer
|
|
46
|
+
* emitted `collectionOp` for `any` / `all` / `none`, the parser had no arm for that token
|
|
47
|
+
* type, and every collection query in the editor came back as
|
|
48
|
+
* "Expected operator after field". The type and `COLLECTION_OPERATORS` were exported the
|
|
49
|
+
* whole time, so the surface looked supported. `tests/collectionParity.spec.ts` now pins the
|
|
50
|
+
* accepted forms against both engine grammars.
|
|
51
|
+
*
|
|
52
|
+
* `negated` carries the `not any` / `!any` / `not_any` spellings, which both engines accept
|
|
53
|
+
* and which are otherwise indistinguishable from the positive form once `operator` has been
|
|
54
|
+
* normalised to its canonical upper-case name.
|
|
55
|
+
*/
|
|
41
56
|
export interface TqlCollectionExpression {
|
|
42
57
|
type: "collection";
|
|
43
58
|
operator: "ANY" | "ALL" | "NONE";
|
|
59
|
+
negated: boolean;
|
|
44
60
|
field: TqlFieldReference;
|
|
45
61
|
condition: TqlExpression;
|
|
46
62
|
start: number;
|
|
@@ -88,21 +104,52 @@ export interface TqlLiteral {
|
|
|
88
104
|
start: number;
|
|
89
105
|
end: number;
|
|
90
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* One argument inside a parameterised mutator call: `split(delimiter=",")`.
|
|
109
|
+
*
|
|
110
|
+
* Both engines accept named (`delimiter=","`), positional (`","`) and bare-identifier
|
|
111
|
+
* (`old=a`) arguments; neither accepts a list literal. See `mutator_arg` in
|
|
112
|
+
* tql/src/parser/grammar.pest and `_setup_mutators` in
|
|
113
|
+
* src/tql/parser_components/grammar.py.
|
|
114
|
+
*/
|
|
115
|
+
export interface TqlMutatorArgument {
|
|
116
|
+
/** Present for `name=value` form; absent for a positional argument. */
|
|
117
|
+
name?: string;
|
|
118
|
+
valueType: "string" | "number" | "boolean" | "null" | "identifier";
|
|
119
|
+
value: string | number | boolean | null;
|
|
120
|
+
start: number;
|
|
121
|
+
end: number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* One link in a mutator chain, with the arguments it was called with.
|
|
125
|
+
*
|
|
126
|
+
* `TqlFieldReference.mutators` remains the flat list of names (unchanged for existing
|
|
127
|
+
* consumers); `mutatorCalls` carries the same chain with argument detail attached.
|
|
128
|
+
*/
|
|
129
|
+
export interface TqlMutatorCall {
|
|
130
|
+
name: string;
|
|
131
|
+
args: TqlMutatorArgument[];
|
|
132
|
+
/** True when the call carried an explicit `(...)` list, even an empty one. */
|
|
133
|
+
parenthesized: boolean;
|
|
134
|
+
start: number;
|
|
135
|
+
end: number;
|
|
136
|
+
}
|
|
91
137
|
export interface TqlFieldReference {
|
|
92
138
|
type: "field";
|
|
93
139
|
name: string;
|
|
94
140
|
path: string[];
|
|
95
141
|
mutators?: string[];
|
|
142
|
+
mutatorCalls?: TqlMutatorCall[];
|
|
96
143
|
typeHint?: TqlTypeHint;
|
|
97
144
|
start: number;
|
|
98
145
|
end: number;
|
|
99
146
|
}
|
|
100
|
-
export type TqlComparisonOperator = "eq" | "ne" | "=" | "!=" | "
|
|
147
|
+
export type TqlComparisonOperator = "eq" | "ne" | "=" | "!=" | "eq_ci" | "gt" | "gte" | "lt" | "lte" | ">" | ">=" | "<" | "<=" | "contains" | "not_contains" | "!contains" | "startswith" | "not_startswith" | "!startswith" | "endswith" | "not_endswith" | "!endswith" | "contains_cs" | "not_contains_cs" | "!contains_cs" | "startswith_cs" | "not_startswith_cs" | "!startswith_cs" | "endswith_cs" | "not_endswith_cs" | "!endswith_cs" | "regexp" | "regex" | "not_regexp" | "not_regex" | "!regexp" | "!regex" | "matches" | "not_matches" | "!matches" | "between" | "not_between" | "!between" | "in" | "not_in" | "!in" | "in_cs" | "not_in_cs" | "!in_cs" | "exists" | "not_exists" | "!exists" | "is" | "is_not" | "!is" | "cidr" | "not_cidr" | "!cidr" | "any" | "all" | "none" | "not_any" | "not_all" | "not_none" | "!any" | "!all" | "!none";
|
|
101
148
|
export type TqlLogicalOperator = "AND" | "OR" | "NOT";
|
|
102
149
|
export type TqlCollectionOperator = "ANY" | "ALL" | "NONE";
|
|
103
150
|
export type TqlMutator = "lowercase" | "uppercase" | "trim" | "split" | "length" | "replace" | "b64encode" | "b64decode" | "urldecode" | "hexencode" | "hexdecode" | "md5" | "sha256" | "refang" | "defang" | "is_private" | "is_global" | "is_multicast" | "is_loopback" | "is_link_local" | "nslookup" | "geoip_lookup" | "geoip" | "geo" | "any" | "all" | "avg" | "average" | "sum" | "min" | "max";
|
|
104
151
|
export type TqlAggregationFunction = "count" | "sum" | "avg" | "average" | "mean" | "median" | "med" | "min" | "max" | "percentile" | "percentiles" | "p" | "pct" | "percentile_rank" | "percentile_ranks" | "pct_rank" | "pct_ranks" | "std" | "standard_deviation" | "unique_count" | "cardinality" | "values" | "unique" | "distinct";
|
|
105
|
-
export type TqlTypeHint = "string" | "str" | "number" | "int" | "integer" | "float" | "double" | "decimal" | "date" | "bool" | "boolean" | "array" | "list" | "object" | "geo";
|
|
152
|
+
export type TqlTypeHint = "string" | "str" | "number" | "int" | "integer" | "float" | "double" | "decimal" | "date" | "bool" | "boolean" | "array" | "list" | "object" | "geo" | "ip";
|
|
106
153
|
export type TqlVisualizationType = "bar" | "barchart" | "horizontal_bar" | "line" | "area" | "stacked_area" | "pie" | "donut" | "scatter" | "heatmap" | "treemap" | "sunburst" | "table" | "number" | "gauge" | "map" | "grouped_bar" | "stacked_bar" | "nested_pie" | "nested_donut" | "chord" | "auto";
|
|
107
154
|
/**
|
|
108
155
|
* Visualization parameters (e.g., title="Events", stacked=true).
|
|
@@ -153,8 +200,43 @@ export interface TqlParseWarning {
|
|
|
153
200
|
code: TqlWarningCode;
|
|
154
201
|
suggestion?: string;
|
|
155
202
|
}
|
|
156
|
-
export type TqlErrorCode = "UNEXPECTED_TOKEN" | "UNEXPECTED_END" | "UNBALANCED_PARENS" | "UNBALANCED_BRACKETS" | "UNTERMINATED_STRING" | "INVALID_OPERATOR" | "INVALID_MUTATOR" | "INVALID_VALUE" | "MISSING_OPERAND" | "MISSING_OPERATOR" | "MISSING_VALUE" | "MISSING_FIELD" | "MISSING_MUTATOR" | "INVALID_SYNTAX" | "MAX_DEPTH_EXCEEDED" | "TYPE_MISMATCH"
|
|
157
|
-
|
|
203
|
+
export type TqlErrorCode = "UNEXPECTED_TOKEN" | "UNEXPECTED_END" | "UNBALANCED_PARENS" | "UNBALANCED_BRACKETS" | "UNTERMINATED_STRING" | "INVALID_OPERATOR" | "INVALID_MUTATOR" | "INVALID_VALUE" | "MISSING_OPERAND" | "MISSING_OPERATOR" | "MISSING_VALUE" | "MISSING_FIELD" | "MISSING_MUTATOR" | "INVALID_SYNTAX" | "MAX_DEPTH_EXCEEDED" | "TYPE_MISMATCH"
|
|
204
|
+
/**
|
|
205
|
+
* `f::int | trim::str` — a type hint on BOTH sides of the mutator chain.
|
|
206
|
+
*
|
|
207
|
+
* Both engines accept the hint in either position and refuse it in both, structurally: each
|
|
208
|
+
* grammar is an ordered choice whose first alternative consumes `f::int | trim` and strands
|
|
209
|
+
* `::str`. There is no defensible answer for which hint would win.
|
|
210
|
+
*/
|
|
211
|
+
| "DUPLICATE_TYPE_HINT"
|
|
212
|
+
/**
|
|
213
|
+
* `::` with a token after it that can never be a type name (`f::| trim`, `f:: eq 'a'`,
|
|
214
|
+
* `f | trim:: eq 'a'`, `f::lowercase`). All four are parse errors in both engines.
|
|
215
|
+
*
|
|
216
|
+
* `f::` at END of input is NOT this — that is a hint being typed, and stays a warning.
|
|
217
|
+
*/
|
|
218
|
+
| "MISSING_TYPE_HINT"
|
|
219
|
+
/**
|
|
220
|
+
* A malformed `top N` / `bottom N` modifier on a stats aggregation.
|
|
221
|
+
*
|
|
222
|
+
* Reserved for the shapes BOTH engines refuse: the modifier given twice on one aggregation
|
|
223
|
+
* (`sum(x, top 10) top 5`), a modifier with no count (`sum(x) top by y`), and the in-parens
|
|
224
|
+
* form on `count(*)` / `count()` (`count(*, top 2)`). A spelling only one engine refuses is
|
|
225
|
+
* an ENGINE_DIVERGENCE warning instead — never this.
|
|
226
|
+
*/
|
|
227
|
+
| "INVALID_STATS_MODIFIER";
|
|
228
|
+
export type TqlWarningCode = "UNKNOWN_FIELD" | "TYPE_MISMATCH" | "DEPRECATED_OPERATOR" | "REDUNDANT_PARENS"
|
|
229
|
+
/**
|
|
230
|
+
* The query parses, but only ONE of the two engines accepts it.
|
|
231
|
+
*
|
|
232
|
+
* Reserved for measured, currently-live divergences between `tql/src/parser/grammar.pest`
|
|
233
|
+
* and `src/tql/parser_components/grammar.py` — not for anything this package merely
|
|
234
|
+
* dislikes. The editor stays permissive (a red squiggle over syntax an engine accepts is
|
|
235
|
+
* the defect this parser keeps being fixed for) while still naming the engine that will
|
|
236
|
+
* refuse the query, because silently accepting it is the worse half of the same failure:
|
|
237
|
+
* the user finds out at execution instead of at the keystroke.
|
|
238
|
+
*/
|
|
239
|
+
| "ENGINE_DIVERGENCE";
|
|
158
240
|
export interface TqlValidationResult {
|
|
159
241
|
valid: boolean;
|
|
160
242
|
errors: TqlParseError[];
|