@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.
@@ -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
- }, d = ["AND", "OR", "NOT"], p = ["ANY", "ALL", "NONE"], k = [
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
- ], f = [
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
- ], m = [
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
- ], w = ["by", "as", "null", "true", "false", "stats", "top", "bottom"];
188
- class g {
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(t) {
195
- this.input = t ?? "", this.position = 0, this.line = 1, this.column = 1, this.tokens = [];
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 t = this.scanToken();
203
- t && this.tokens.push(t);
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 t = this.position, n = this.line, i = this.column, e = this.advance();
214
- switch (e) {
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", e, t, n, i);
231
+ return this.makeToken("paren", t, e, n, i);
218
232
  case "[":
219
233
  case "]":
220
- return this.makeToken("bracket", e, t, n, i);
234
+ return this.makeToken("bracket", t, e, n, i);
221
235
  case ",":
222
- return this.makeToken("comma", e, t, n, i);
236
+ return this.makeToken("comma", t, e, n, i);
223
237
  case "|":
224
- return this.makeToken("pipe", e, t, n, i);
238
+ return this.makeToken("pipe", t, e, n, i);
225
239
  }
226
- return e === "=" && this.peek() === ">" ? (this.advance(), this.makeToken("arrow", "=>", t, n, i)) : e === ":" && this.peek() === ":" ? (this.advance(), this.makeToken("doubleColon", "::", t, n, i)) : e === '"' || e === "'" ? this.scanString(e, t, n, i) : this.isDigit(e) || e === "-" && this.isDigit(this.peek()) ? this.scanNumber(t, n, i) : this.isOperatorChar(e) ? this.scanSymbolOperator(t, n, i) : this.isIdentifierStart(e) ? this.scanIdentifier(t, n, i) : this.makeToken("unknown", e, t, n, i);
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 t = this.position, n = this.line, i = this.column;
233
- let e = "";
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
- e += s;
250
+ t += s;
237
251
  }
238
- return this.makeToken("whitespace", e, t, n, i);
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(t, n, i, e) {
257
+ scanString(e, n, i, t) {
244
258
  let s = "";
245
- const r = t;
246
- for (; !this.isAtEnd() && this.peek() !== t; )
247
- if (this.peek() === "\\") {
248
- if (this.advance(), !this.isAtEnd()) {
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
- } else
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: e,
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: e,
291
- raw: t + s + t
306
+ column: t,
307
+ raw: e + s + e
292
308
  });
293
309
  }
294
310
  /**
295
311
  * Scan a numeric literal
296
312
  */
297
- scanNumber(t, n, i) {
298
- this.position = t, this.column = i;
299
- let e = "";
300
- for (this.peek() === "-" && (e += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
301
- e += this.advance();
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 (e += this.advance(); !this.isAtEnd() && this.isDigit(this.peek()); )
304
- e += this.advance();
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 (e += this.advance(), (this.peek() === "+" || this.peek() === "-") && (e += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
307
- e += this.advance();
308
- return this.makeToken("number", e, t, n, i);
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(t, n, i) {
314
- this.position = t, this.column = i;
315
- let e = this.advance();
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 = e + this.peek();
333
+ const s = t + this.peek();
318
334
  if (s === "=>")
319
- return this.advance(), this.makeToken("arrow", "=>", t, n, i);
320
- (s in h || s === "==" || s === "!=") && (e = s, this.advance());
335
+ return this.advance(), this.makeToken("arrow", "=>", e, n, i);
336
+ (s in h || s === "==" || s === "!=") && (t = s, this.advance());
321
337
  }
322
- if (e === "!") {
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, t, n, i);
345
+ return this.makeToken("operator", "!" + r, e, n, i);
330
346
  this.position = s, this.column = i + 1;
331
347
  }
332
348
  }
333
- return e in h || e === "==" || e === "=" || e === "!=" || e === ">" || e === ">=" || e === "<" || e === "<=" ? this.makeToken("operator", e, t, n, i) : this.makeToken("unknown", e, t, n, i);
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(t, n, i) {
339
- this.position = t, this.column = i;
340
- let e = "";
354
+ scanIdentifier(e, n, i) {
355
+ this.position = e, this.column = i;
356
+ let t = "";
341
357
  const s = this.advance();
342
- if (e += s, s === "@" && this.peek() === "@")
343
- return this.makeToken("unknown", e, t, n, i);
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--, e = e.slice(0, -1), this.makeToken("unknown", e, t, n, i);
349
- e += c, r = c;
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
- e.endsWith(".") && (this.position--, this.column--, e = e.slice(0, -1));
352
- const a = this.classifyIdentifier(e);
353
- return this.makeToken(a, e, t, n, i);
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(t) {
359
- const n = t.toUpperCase(), i = t.toLowerCase();
360
- return d.includes(n) ? "logicalOp" : p.includes(n) ? "collectionOp" : i === "true" || i === "false" ? "boolean" : i === "null" ? "null" : i === "stats" ? "keyword" : l.includes(i) ? "operator" : _.includes(i) ? "aggregation" : k.includes(i) ? "mutator" : f.includes(i) ? "typeHint" : m.includes(i) ? "visualization" : w.includes(i) ? "keyword" : "field";
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(t, n, i, e, s) {
381
+ makeToken(e, n, i, t, s) {
366
382
  return {
367
- type: t,
383
+ type: e,
368
384
  value: n,
369
385
  start: i,
370
386
  end: this.position,
371
- line: e,
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 t = this.input[this.position];
386
- return this.position++, t === `
387
- ` ? (this.line++, this.column = 1) : this.column++, t;
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(t) {
390
- return t === " " || t === " " || t === `
391
- ` || t === "\r";
405
+ isWhitespace(e) {
406
+ return e === " " || e === " " || e === `
407
+ ` || e === "\r";
392
408
  }
393
- isDigit(t) {
394
- return t >= "0" && t <= "9";
409
+ isDigit(e) {
410
+ return e >= "0" && e <= "9";
395
411
  }
396
- isIdentifierStart(t) {
397
- return t >= "a" && t <= "z" || t >= "A" && t <= "Z" || t === "_" || t === "@";
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(t) {
403
- return t >= "a" && t <= "z" || t >= "A" && t <= "Z" || t === "_" || this.isDigit(t) || t === "." || // For nested field access
404
- t === "-";
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(t) {
407
- return t === "=" || t === "!" || t === ">" || t === "<";
422
+ isOperatorChar(e) {
423
+ return e === "=" || e === "!" || e === ">" || e === "<";
408
424
  }
409
425
  }
410
- function T(o) {
411
- return new g(o).tokenize();
426
+ function O(o) {
427
+ return new w(o).tokenize();
412
428
  }
413
- function b(o) {
414
- return T(o).filter((t) => t.type !== "whitespace");
429
+ function v(o) {
430
+ return O(o).filter((e) => e.type !== "whitespace");
415
431
  }
416
- function v(o, t) {
432
+ function E(o, e) {
417
433
  for (const n of o)
418
- if (t >= n.start && t < n.end)
434
+ if (e >= n.start && e < n.end)
419
435
  return n;
420
436
  return null;
421
437
  }
422
- function O(o, t, n) {
423
- return o.filter((i) => i.start < n && i.end > t);
438
+ function S(o, e, n) {
439
+ return o.filter((i) => i.start < n && i.end > e);
424
440
  }
425
- function A(o, t) {
441
+ function I(o, e) {
426
442
  let n = null;
427
443
  for (const i of o)
428
- if (i.end <= t)
444
+ if (i.end <= e)
429
445
  n = i;
430
446
  else
431
447
  break;
432
448
  return n;
433
449
  }
434
- function E(o, t, n = !0) {
450
+ function N(o, e, n = !0) {
435
451
  const i = n ? o.filter((s) => s.type !== "whitespace") : o;
436
- let e = null;
452
+ let t = null;
437
453
  for (const s of i)
438
- if (s.end <= t)
439
- e = s;
454
+ if (s.end <= e)
455
+ t = s;
440
456
  else
441
457
  break;
442
- return e;
458
+ return t;
443
459
  }
444
460
  export {
445
- _ as AGGREGATION_FUNCTIONS,
446
- p as COLLECTION_OPERATORS,
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
- w as KEYWORDS,
449
- d as LOGICAL_OPERATORS,
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
- f as TYPE_HINTS,
454
- g as TqlTokenizer,
455
- m as VISUALIZATION_TYPES,
456
- E as findPreviousToken,
457
- v as findTokenAtPosition,
458
- A as findTokenBefore,
459
- O as findTokensInRange,
460
- T as tokenizeTql,
461
- b as tokenizeTqlNoWhitespace
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
  };
@@ -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" | "=" | "!=" | "==" | "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";
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
- export type TqlWarningCode = "UNKNOWN_FIELD" | "TYPE_MISMATCH" | "DEPRECATED_OPERATOR" | "REDUNDANT_PARENS";
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[];