@tellaro/tql 1.3.8 → 1.4.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.
Files changed (33) hide show
  1. package/dist/index.js +44 -41
  2. package/dist/node_modules/@kurkle/color/dist/color.esm.js +442 -0
  3. package/dist/node_modules/chart.js/dist/chart.js +6149 -0
  4. package/dist/node_modules/chart.js/dist/chunks/helpers.dataset.js +1685 -0
  5. package/dist/node_modules/chartjs-adapter-luxon/dist/chartjs-adapter-luxon.esm.js +56 -0
  6. package/dist/node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.esm.js +1655 -0
  7. package/dist/node_modules/chartjs-plugin-datalabels/dist/chartjs-plugin-datalabels.esm.js +607 -0
  8. package/dist/node_modules/luxon/build/es6/luxon.js +5524 -0
  9. package/dist/src/builder.d.ts +62 -0
  10. package/dist/src/builder.js +56 -0
  11. package/dist/src/chart/colors.d.ts +23 -0
  12. package/dist/src/chart/colors.js +101 -0
  13. package/dist/src/chart/formatters.d.ts +17 -0
  14. package/dist/src/chart/formatters.js +49 -0
  15. package/dist/src/chart/index.d.ts +9 -0
  16. package/dist/src/chart/index.js +31 -0
  17. package/dist/src/chart/mappers.d.ts +849 -0
  18. package/dist/src/chart/mappers.js +613 -0
  19. package/dist/src/completionProvider.js +294 -165
  20. package/dist/src/index.d.ts +2 -1
  21. package/dist/src/parser.d.ts +10 -0
  22. package/dist/src/parser.js +41 -9
  23. package/dist/src/tokenizer.js +124 -103
  24. package/dist/src/types.d.ts +27 -3
  25. package/dist/src/validator.js +10 -9
  26. package/dist/tql.css +1 -1
  27. package/dist/vue/TqlChart.vue.d.ts +2 -0
  28. package/dist/vue/TqlChart.vue.js +7 -0
  29. package/dist/vue/TqlChart.vue2.js +212 -0
  30. package/dist/vue/index.d.ts +1 -0
  31. package/dist/vue/index.js +12 -10
  32. package/dist/vue/useTqlInput.js +80 -80
  33. package/package.json +39 -3
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
- export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlParseResult, TqlParseError, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
9
+ export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlVizParams, TqlVizHint, TqlParseResult, TqlParseError, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
10
10
  export { TqlTokenizer, tokenizeTql, tokenizeTqlNoWhitespace, findTokenAtPosition, findTokensInRange, findTokenBefore, findPreviousToken, COMPARISON_OPERATORS, SYMBOL_OPERATORS, NEGATION_SYMBOL_OPERATORS, LOGICAL_OPERATORS, COLLECTION_OPERATORS, MUTATORS, AGGREGATION_FUNCTIONS, TYPE_HINTS, VISUALIZATION_TYPES, KEYWORDS } from './tokenizer';
11
11
  export { TqlParser, parseTql, isValidTql, getTqlErrors, formatParseError } from './parser';
12
12
  export { TqlValidator, validateTql, isValidTqlSyntax, getTqlIssues, formatValidationResult } from './validator';
@@ -15,4 +15,5 @@ export { fuzzyMatch, levenshteinDistance, findClosestMatch, fuzzyFilter, highlig
15
15
  export { SchemaCache, getSchemaCache, createSchemaCache, getCachedFieldNames, getCachedFieldType, getCachedField, type CachedSchema } from './schemaCache';
16
16
  export { ComplexityAnalyzer, analyzeComplexity, isHighComplexity, getComplexityWarnings, getComplexityMetrics } from './complexityAnalyzer';
17
17
  export { SemanticPreview, generatePreview, getFieldUsage, getLogicTree, getUniqueFields, getOperatorSummary, formatLogicTreeNode, formatLogicTreeAscii, flattenLogicTree, getLogicTreeDepth } from './semanticPreview';
18
+ export { buildStatsQuery, parseVizHintString, type StatsQueryConfig, type AggregationConfig, type GroupByConfig, type VizHintConfig } from './builder';
18
19
  export type { ComplexityScore, ComplexityWarning, ComplexityWarningType, ComplexityMetrics, ComplexityResult, ComplexityThresholds, MatchType, FieldUsage, LogicTreeNodeType, LogicTreeNode, PreviewResult, QueryHistoryEntry, UseQueryHistoryOptions } from './types';
@@ -71,6 +71,16 @@ export declare class TqlParser {
71
71
  * This allows the parser to continue and find additional errors.
72
72
  */
73
73
  private createPlaceholderExpression;
74
+ /**
75
+ * Check if the token stream represents a stats query.
76
+ * Handles: "| stats ...", "stats ...", or starts with a filter before "| stats".
77
+ */
78
+ private isStatsQuery;
79
+ /**
80
+ * Check if the current position is a pipe followed by "stats" keyword.
81
+ * Used when the filter portion parsed successfully but there are remaining tokens.
82
+ */
83
+ private isStatsFollowingPipe;
74
84
  }
75
85
  /**
76
86
  * Parse a TQL query string
@@ -1,5 +1,5 @@
1
1
  import { tokenizeTql as u, COMPARISON_OPERATORS as c } from "./tokenizer.js";
2
- const d = 50, p = /* @__PURE__ */ new Set(["logicalOp", "paren"]);
2
+ const p = 50, d = /* @__PURE__ */ new Set(["logicalOp", "paren"]);
3
3
  class v {
4
4
  tokens;
5
5
  allTokens;
@@ -23,11 +23,20 @@ class v {
23
23
  warnings: [],
24
24
  success: !0
25
25
  };
26
+ if (this.isStatsQuery())
27
+ return {
28
+ ast: null,
29
+ // Stats AST is produced by the Python/Rust parser
30
+ tokens: this.allTokens,
31
+ errors: [],
32
+ warnings: [],
33
+ success: !0
34
+ };
26
35
  try {
27
36
  const e = this.parseExpression();
28
37
  if (!this.isAtEnd()) {
29
38
  const t = this.peek();
30
- this.addError(
39
+ t.type === "pipe" && this.isStatsFollowingPipe() || this.addError(
31
40
  `Unexpected token '${t.value}'`,
32
41
  t,
33
42
  "UNEXPECTED_TOKEN",
@@ -58,7 +67,7 @@ class v {
58
67
  * Parse a full expression (lowest precedence)
59
68
  */
60
69
  parseExpression() {
61
- if (this.depth++, this.depth > d)
70
+ if (this.depth++, this.depth > p)
62
71
  throw new Error("Maximum query depth exceeded");
63
72
  try {
64
73
  return this.parseOr();
@@ -507,7 +516,7 @@ class v {
507
516
  */
508
517
  synchronize() {
509
518
  for (this.advance(); !this.isAtEnd(); ) {
510
- if (p.has(this.peek().type) || this.peek().type === "paren" && this.peek().value === ")")
519
+ if (d.has(this.peek().type) || this.peek().type === "paren" && this.peek().value === ")")
511
520
  return;
512
521
  this.advance();
513
522
  }
@@ -538,24 +547,47 @@ class v {
538
547
  end: e.end
539
548
  };
540
549
  }
550
+ /**
551
+ * Check if the token stream represents a stats query.
552
+ * Handles: "| stats ...", "stats ...", or starts with a filter before "| stats".
553
+ */
554
+ isStatsQuery() {
555
+ if (this.tokens.length >= 2 && this.tokens[0].type === "pipe")
556
+ return this.tokens[1].type === "keyword" && this.tokens[1].value.toLowerCase() === "stats";
557
+ if (this.tokens.length >= 1 && this.tokens[0].type === "keyword" && this.tokens[0].value.toLowerCase() === "stats")
558
+ return !0;
559
+ for (let e = 0; e < this.tokens.length - 1; e++)
560
+ if (this.tokens[e].type === "pipe" && this.tokens[e + 1].type === "keyword" && this.tokens[e + 1].value.toLowerCase() === "stats")
561
+ return !0;
562
+ return !1;
563
+ }
564
+ /**
565
+ * Check if the current position is a pipe followed by "stats" keyword.
566
+ * Used when the filter portion parsed successfully but there are remaining tokens.
567
+ */
568
+ isStatsFollowingPipe() {
569
+ if (this.current >= this.tokens.length || this.tokens[this.current].type !== "pipe") return !1;
570
+ const t = this.current + 1;
571
+ return t >= this.tokens.length ? !1 : this.tokens[t].type === "keyword" && this.tokens[t].value.toLowerCase() === "stats";
572
+ }
541
573
  }
542
574
  function l(i) {
543
- return new v(i).parse();
575
+ return i ? new v(i).parse() : { ast: null, errors: [], warnings: [], tokens: [] };
544
576
  }
545
- function k(i) {
577
+ function f(i) {
546
578
  return l(i).success;
547
579
  }
548
580
  function y(i) {
549
581
  return l(i).errors;
550
582
  }
551
- function E(i) {
583
+ function g(i) {
552
584
  let e = `Error at line ${i.line}, column ${i.column}: ${i.message}`;
553
585
  return i.suggestion && (e += ` (${i.suggestion})`), e;
554
586
  }
555
587
  export {
556
588
  v as TqlParser,
557
- E as formatParseError,
589
+ g as formatParseError,
558
590
  y as getTqlErrors,
559
- k as isValidTql,
591
+ f as isValidTql,
560
592
  l as parseTql
561
593
  };
@@ -2,18 +2,27 @@ const l = [
2
2
  // Equality
3
3
  "eq",
4
4
  "ne",
5
+ "eq_ci",
5
6
  // Comparison
6
7
  "gt",
7
8
  "gte",
8
9
  "lt",
9
10
  "lte",
10
- // String operators
11
+ // String operators (case-insensitive by default)
11
12
  "contains",
12
13
  "not_contains",
13
14
  "startswith",
14
15
  "not_startswith",
15
16
  "endswith",
16
17
  "not_endswith",
18
+ // Case-sensitive string operators (explicit)
19
+ "contains_cs",
20
+ "not_contains_cs",
21
+ "startswith_cs",
22
+ "not_startswith_cs",
23
+ "endswith_cs",
24
+ "not_endswith_cs",
25
+ // Regex operators
17
26
  "regexp",
18
27
  "regex",
19
28
  "not_regexp",
@@ -24,6 +33,8 @@ const l = [
24
33
  "not_between",
25
34
  "in",
26
35
  "not_in",
36
+ "in_cs",
37
+ "not_in_cs",
27
38
  // Existence operators
28
39
  "exists",
29
40
  "not_exists",
@@ -39,7 +50,7 @@ const l = [
39
50
  "not_any",
40
51
  "not_all",
41
52
  "not_none"
42
- ], c = {
53
+ ], h = {
43
54
  "==": "eq",
44
55
  "=": "eq",
45
56
  "!=": "ne",
@@ -48,6 +59,10 @@ const l = [
48
59
  "<": "lt",
49
60
  "<=": "lte"
50
61
  }, u = {
62
+ "!in_cs": "not_in_cs",
63
+ "!contains_cs": "not_contains_cs",
64
+ "!startswith_cs": "not_startswith_cs",
65
+ "!endswith_cs": "not_endswith_cs",
51
66
  "!in": "not_in",
52
67
  "!contains": "not_contains",
53
68
  "!startswith": "not_startswith",
@@ -61,7 +76,7 @@ const l = [
61
76
  "!any": "not_any",
62
77
  "!all": "not_all",
63
78
  "!none": "not_none"
64
- }, p = ["AND", "OR", "NOT"], d = ["ANY", "ALL", "NONE"], k = [
79
+ }, d = ["AND", "OR", "NOT"], p = ["ANY", "ALL", "NONE"], k = [
65
80
  // String mutators
66
81
  "lowercase",
67
82
  "uppercase",
@@ -82,6 +97,9 @@ const l = [
82
97
  "defang",
83
98
  "is_private",
84
99
  "is_global",
100
+ "is_multicast",
101
+ "is_loopback",
102
+ "is_link_local",
85
103
  // DNS mutator
86
104
  "nslookup",
87
105
  // GeoIP mutators
@@ -125,7 +143,7 @@ const l = [
125
143
  "values",
126
144
  "unique",
127
145
  "distinct"
128
- ], m = [
146
+ ], _ = [
129
147
  "string",
130
148
  "str",
131
149
  "number",
@@ -141,11 +159,13 @@ const l = [
141
159
  "list",
142
160
  "object",
143
161
  "geo"
144
- ], _ = [
162
+ ], m = [
145
163
  "bar",
146
164
  "barchart",
165
+ "horizontal_bar",
147
166
  "line",
148
167
  "area",
168
+ "stacked_area",
149
169
  "pie",
150
170
  "donut",
151
171
  "scatter",
@@ -160,24 +180,25 @@ const l = [
160
180
  "stacked_bar",
161
181
  "nested_pie",
162
182
  "nested_donut",
163
- "chord"
164
- ], g = ["by", "as", "null", "true", "false", "stats", "top", "bottom"];
165
- class T {
183
+ "chord",
184
+ "auto"
185
+ ], w = ["by", "as", "null", "true", "false", "stats", "top", "bottom"];
186
+ class g {
166
187
  input;
167
188
  position;
168
189
  line;
169
190
  column;
170
191
  tokens;
171
- constructor(e) {
172
- this.input = e, this.position = 0, this.line = 1, this.column = 1, this.tokens = [];
192
+ constructor(t) {
193
+ this.input = t ?? "", this.position = 0, this.line = 1, this.column = 1, this.tokens = [];
173
194
  }
174
195
  /**
175
196
  * Tokenize the entire input string
176
197
  */
177
198
  tokenize() {
178
199
  for (this.tokens = [], this.position = 0, this.line = 1, this.column = 1; !this.isAtEnd(); ) {
179
- const e = this.scanToken();
180
- e && this.tokens.push(e);
200
+ const t = this.scanToken();
201
+ t && this.tokens.push(t);
181
202
  }
182
203
  return this.tokens;
183
204
  }
@@ -187,40 +208,40 @@ class T {
187
208
  scanToken() {
188
209
  if (this.isWhitespace(this.peek()))
189
210
  return this.scanWhitespace();
190
- const e = this.position, n = this.line, i = this.column, t = this.advance();
191
- switch (t) {
211
+ const t = this.position, n = this.line, i = this.column, e = this.advance();
212
+ switch (e) {
192
213
  case "(":
193
214
  case ")":
194
- return this.makeToken("paren", t, e, n, i);
215
+ return this.makeToken("paren", e, t, n, i);
195
216
  case "[":
196
217
  case "]":
197
- return this.makeToken("bracket", t, e, n, i);
218
+ return this.makeToken("bracket", e, t, n, i);
198
219
  case ",":
199
- return this.makeToken("comma", t, e, n, i);
220
+ return this.makeToken("comma", e, t, n, i);
200
221
  case "|":
201
- return this.makeToken("pipe", t, e, n, i);
222
+ return this.makeToken("pipe", e, t, n, i);
202
223
  }
203
- 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);
224
+ 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);
204
225
  }
205
226
  /**
206
227
  * Scan whitespace characters
207
228
  */
208
229
  scanWhitespace() {
209
- const e = this.position, n = this.line, i = this.column;
210
- let t = "";
230
+ const t = this.position, n = this.line, i = this.column;
231
+ let e = "";
211
232
  for (; !this.isAtEnd() && this.isWhitespace(this.peek()); ) {
212
233
  const s = this.advance();
213
- t += s;
234
+ e += s;
214
235
  }
215
- return this.makeToken("whitespace", t, e, n, i);
236
+ return this.makeToken("whitespace", e, t, n, i);
216
237
  }
217
238
  /**
218
239
  * Scan a string literal (single or double quoted)
219
240
  */
220
- scanString(e, n, i, t) {
241
+ scanString(t, n, i, e) {
221
242
  let s = "";
222
- const r = e;
223
- for (; !this.isAtEnd() && this.peek() !== e; )
243
+ const r = t;
244
+ for (; !this.isAtEnd() && this.peek() !== t; )
224
245
  if (this.peek() === "\\") {
225
246
  if (this.advance(), !this.isAtEnd()) {
226
247
  const a = this.advance();
@@ -256,7 +277,7 @@ class T {
256
277
  start: n,
257
278
  end: this.position,
258
279
  line: i,
259
- column: t,
280
+ column: e,
260
281
  raw: r + s
261
282
  } : (this.advance(), {
262
283
  type: "string",
@@ -264,88 +285,88 @@ class T {
264
285
  start: n,
265
286
  end: this.position,
266
287
  line: i,
267
- column: t,
268
- raw: e + s + e
288
+ column: e,
289
+ raw: t + s + t
269
290
  });
270
291
  }
271
292
  /**
272
293
  * Scan a numeric literal
273
294
  */
274
- scanNumber(e, n, i) {
275
- this.position = e, this.column = i;
276
- let t = "";
277
- for (this.peek() === "-" && (t += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
278
- t += this.advance();
295
+ scanNumber(t, n, i) {
296
+ this.position = t, this.column = i;
297
+ let e = "";
298
+ for (this.peek() === "-" && (e += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
299
+ e += this.advance();
279
300
  if (this.peek() === "." && this.isDigit(this.peekNext()))
280
- for (t += this.advance(); !this.isAtEnd() && this.isDigit(this.peek()); )
281
- t += this.advance();
301
+ for (e += this.advance(); !this.isAtEnd() && this.isDigit(this.peek()); )
302
+ e += this.advance();
282
303
  if (this.peek() === "e" || this.peek() === "E")
283
- for (t += this.advance(), (this.peek() === "+" || this.peek() === "-") && (t += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
284
- t += this.advance();
285
- return this.makeToken("number", t, e, n, i);
304
+ for (e += this.advance(), (this.peek() === "+" || this.peek() === "-") && (e += this.advance()); !this.isAtEnd() && this.isDigit(this.peek()); )
305
+ e += this.advance();
306
+ return this.makeToken("number", e, t, n, i);
286
307
  }
287
308
  /**
288
309
  * Scan symbol-based operators (==, !=, >, >=, <, <=, !)
289
310
  */
290
- scanSymbolOperator(e, n, i) {
291
- this.position = e, this.column = i;
292
- let t = this.advance();
311
+ scanSymbolOperator(t, n, i) {
312
+ this.position = t, this.column = i;
313
+ let e = this.advance();
293
314
  if (!this.isAtEnd()) {
294
- const s = t + this.peek();
315
+ const s = e + this.peek();
295
316
  if (s === "=>")
296
- return this.advance(), this.makeToken("arrow", "=>", e, n, i);
297
- (s in c || s === "==" || s === "!=") && (t = s, this.advance());
317
+ return this.advance(), this.makeToken("arrow", "=>", t, n, i);
318
+ (s in h || s === "==" || s === "!=") && (e = s, this.advance());
298
319
  }
299
- if (t === "!") {
320
+ if (e === "!") {
300
321
  const s = this.position;
301
322
  let r = "";
302
323
  for (; !this.isAtEnd() && this.isIdentifierChar(this.peek()); )
303
324
  r += this.advance();
304
325
  if (r) {
305
326
  if ("!" + r in u)
306
- return this.makeToken("operator", "!" + r, e, n, i);
327
+ return this.makeToken("operator", "!" + r, t, n, i);
307
328
  this.position = s, this.column = i + 1;
308
329
  }
309
330
  }
310
- return t in c || t === "==" || t === "=" || t === "!=" || t === ">" || t === ">=" || t === "<" || t === "<=" ? this.makeToken("operator", t, e, n, i) : this.makeToken("unknown", t, e, n, i);
331
+ 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);
311
332
  }
312
333
  /**
313
334
  * Scan an identifier (field name, operator keyword, etc.)
314
335
  */
315
- scanIdentifier(e, n, i) {
316
- this.position = e, this.column = i;
317
- let t = "";
336
+ scanIdentifier(t, n, i) {
337
+ this.position = t, this.column = i;
338
+ let e = "";
318
339
  const s = this.advance();
319
- if (t += s, s === "@" && this.peek() === "@")
320
- return this.makeToken("unknown", t, e, n, i);
340
+ if (e += s, s === "@" && this.peek() === "@")
341
+ return this.makeToken("unknown", e, t, n, i);
321
342
  let r = s;
322
343
  for (; !this.isAtEnd() && this.isIdentifierChar(this.peek()); ) {
323
- const h = this.advance();
324
- if (h === "." && r === ".")
325
- return this.position--, this.column--, t = t.slice(0, -1), this.makeToken("unknown", t, e, n, i);
326
- t += h, r = h;
344
+ const c = this.advance();
345
+ if (c === "." && r === ".")
346
+ return this.position--, this.column--, e = e.slice(0, -1), this.makeToken("unknown", e, t, n, i);
347
+ e += c, r = c;
327
348
  }
328
- t.endsWith(".") && (this.position--, this.column--, t = t.slice(0, -1));
329
- const a = this.classifyIdentifier(t);
330
- return this.makeToken(a, t, e, n, i);
349
+ e.endsWith(".") && (this.position--, this.column--, e = e.slice(0, -1));
350
+ const a = this.classifyIdentifier(e);
351
+ return this.makeToken(a, e, t, n, i);
331
352
  }
332
353
  /**
333
354
  * Classify an identifier into the appropriate token type
334
355
  */
335
- classifyIdentifier(e) {
336
- const n = e.toUpperCase(), i = e.toLowerCase();
337
- 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" : _.includes(i) ? "visualization" : g.includes(i) ? "keyword" : "field";
356
+ classifyIdentifier(t) {
357
+ const n = t.toUpperCase(), i = t.toLowerCase();
358
+ return d.includes(n) ? "logicalOp" : p.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" : _.includes(i) ? "typeHint" : m.includes(i) ? "visualization" : w.includes(i) ? "keyword" : "field";
338
359
  }
339
360
  // ============================================================================
340
361
  // Helper Methods
341
362
  // ============================================================================
342
- makeToken(e, n, i, t, s) {
363
+ makeToken(t, n, i, e, s) {
343
364
  return {
344
- type: e,
365
+ type: t,
345
366
  value: n,
346
367
  start: i,
347
368
  end: this.position,
348
- line: t,
369
+ line: e,
349
370
  column: s
350
371
  };
351
372
  }
@@ -359,81 +380,81 @@ class T {
359
380
  return this.position + 1 >= this.input.length ? "\0" : this.input[this.position + 1];
360
381
  }
361
382
  advance() {
362
- const e = this.input[this.position];
363
- return this.position++, e === `
364
- ` ? (this.line++, this.column = 1) : this.column++, e;
383
+ const t = this.input[this.position];
384
+ return this.position++, t === `
385
+ ` ? (this.line++, this.column = 1) : this.column++, t;
365
386
  }
366
- isWhitespace(e) {
367
- return e === " " || e === " " || e === `
368
- ` || e === "\r";
387
+ isWhitespace(t) {
388
+ return t === " " || t === " " || t === `
389
+ ` || t === "\r";
369
390
  }
370
- isDigit(e) {
371
- return e >= "0" && e <= "9";
391
+ isDigit(t) {
392
+ return t >= "0" && t <= "9";
372
393
  }
373
- isIdentifierStart(e) {
374
- return e >= "a" && e <= "z" || e >= "A" && e <= "Z" || e === "_" || e === "@";
394
+ isIdentifierStart(t) {
395
+ return t >= "a" && t <= "z" || t >= "A" && t <= "Z" || t === "_" || t === "@";
375
396
  }
376
397
  /**
377
398
  * Check if char can continue an identifier (NOT including @ which is only valid at start)
378
399
  */
379
- isIdentifierChar(e) {
380
- return e >= "a" && e <= "z" || e >= "A" && e <= "Z" || e === "_" || this.isDigit(e) || e === "." || // For nested field access
381
- e === "-";
400
+ isIdentifierChar(t) {
401
+ return t >= "a" && t <= "z" || t >= "A" && t <= "Z" || t === "_" || this.isDigit(t) || t === "." || // For nested field access
402
+ t === "-";
382
403
  }
383
- isOperatorChar(e) {
384
- return e === "=" || e === "!" || e === ">" || e === "<";
404
+ isOperatorChar(t) {
405
+ return t === "=" || t === "!" || t === ">" || t === "<";
385
406
  }
386
407
  }
387
- function w(o) {
388
- return new T(o).tokenize();
408
+ function T(o) {
409
+ return new g(o).tokenize();
389
410
  }
390
411
  function b(o) {
391
- return w(o).filter((e) => e.type !== "whitespace");
412
+ return T(o).filter((t) => t.type !== "whitespace");
392
413
  }
393
- function v(o, e) {
414
+ function v(o, t) {
394
415
  for (const n of o)
395
- if (e >= n.start && e < n.end)
416
+ if (t >= n.start && t < n.end)
396
417
  return n;
397
418
  return null;
398
419
  }
399
- function O(o, e, n) {
400
- return o.filter((i) => i.start < n && i.end > e);
420
+ function O(o, t, n) {
421
+ return o.filter((i) => i.start < n && i.end > t);
401
422
  }
402
- function A(o, e) {
423
+ function A(o, t) {
403
424
  let n = null;
404
425
  for (const i of o)
405
- if (i.end <= e)
426
+ if (i.end <= t)
406
427
  n = i;
407
428
  else
408
429
  break;
409
430
  return n;
410
431
  }
411
- function E(o, e, n = !0) {
432
+ function E(o, t, n = !0) {
412
433
  const i = n ? o.filter((s) => s.type !== "whitespace") : o;
413
- let t = null;
434
+ let e = null;
414
435
  for (const s of i)
415
- if (s.end <= e)
416
- t = s;
436
+ if (s.end <= t)
437
+ e = s;
417
438
  else
418
439
  break;
419
- return t;
440
+ return e;
420
441
  }
421
442
  export {
422
443
  f as AGGREGATION_FUNCTIONS,
423
- d as COLLECTION_OPERATORS,
444
+ p as COLLECTION_OPERATORS,
424
445
  l as COMPARISON_OPERATORS,
425
- g as KEYWORDS,
426
- p as LOGICAL_OPERATORS,
446
+ w as KEYWORDS,
447
+ d as LOGICAL_OPERATORS,
427
448
  k as MUTATORS,
428
449
  u as NEGATION_SYMBOL_OPERATORS,
429
- c as SYMBOL_OPERATORS,
430
- m as TYPE_HINTS,
431
- T as TqlTokenizer,
432
- _ as VISUALIZATION_TYPES,
450
+ h as SYMBOL_OPERATORS,
451
+ _ as TYPE_HINTS,
452
+ g as TqlTokenizer,
453
+ m as VISUALIZATION_TYPES,
433
454
  E as findPreviousToken,
434
455
  v as findTokenAtPosition,
435
456
  A as findTokenBefore,
436
457
  O as findTokensInRange,
437
- w as tokenizeTql,
458
+ T as tokenizeTql,
438
459
  b as tokenizeTqlNoWhitespace
439
460
  };
@@ -70,6 +70,8 @@ export interface TqlStatsExpression {
70
70
  topN?: number;
71
71
  bottomN?: number;
72
72
  visualization?: TqlVisualizationType;
73
+ /** Full visualization hint with type and optional parameters */
74
+ vizHint?: TqlVizHint;
73
75
  start: number;
74
76
  end: number;
75
77
  }
@@ -95,13 +97,35 @@ export interface TqlFieldReference {
95
97
  start: number;
96
98
  end: number;
97
99
  }
98
- export type TqlComparisonOperator = "eq" | "ne" | "=" | "!=" | "==" | "gt" | "gte" | "lt" | "lte" | ">" | ">=" | "<" | "<=" | "contains" | "not_contains" | "!contains" | "startswith" | "not_startswith" | "!startswith" | "endswith" | "not_endswith" | "!endswith" | "regexp" | "regex" | "not_regexp" | "!regexp" | "matches" | "not_matches" | "!matches" | "between" | "not_between" | "!between" | "in" | "not_in" | "!in" | "exists" | "not_exists" | "!exists" | "is" | "is_not" | "!is" | "cidr" | "not_cidr" | "!cidr" | "any" | "all" | "none" | "not_any" | "not_all" | "not_none" | "!any" | "!all" | "!none";
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" | "!regexp" | "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";
99
101
  export type TqlLogicalOperator = "AND" | "OR" | "NOT";
100
102
  export type TqlCollectionOperator = "ANY" | "ALL" | "NONE";
101
- export type TqlMutator = "lowercase" | "uppercase" | "trim" | "split" | "length" | "replace" | "b64encode" | "b64decode" | "urldecode" | "hexencode" | "hexdecode" | "md5" | "sha256" | "refang" | "defang" | "is_private" | "is_global" | "nslookup" | "geoip_lookup" | "geoip" | "geo" | "any" | "all" | "avg" | "average" | "sum" | "min" | "max";
103
+ 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";
102
104
  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";
103
105
  export type TqlTypeHint = "string" | "str" | "number" | "int" | "integer" | "float" | "double" | "decimal" | "date" | "bool" | "boolean" | "array" | "list" | "object" | "geo";
104
- export type TqlVisualizationType = "bar" | "barchart" | "line" | "area" | "pie" | "donut" | "scatter" | "heatmap" | "treemap" | "sunburst" | "table" | "number" | "gauge" | "map" | "grouped_bar" | "stacked_bar" | "nested_pie" | "nested_donut" | "chord";
106
+ 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
+ /**
108
+ * Visualization parameters (e.g., title="Events", stacked=true).
109
+ */
110
+ export interface TqlVizParams {
111
+ title?: string;
112
+ x_label?: string;
113
+ y_label?: string;
114
+ legend?: string;
115
+ stacked?: boolean;
116
+ donut?: boolean;
117
+ fill?: boolean;
118
+ smooth?: boolean;
119
+ limit?: number;
120
+ [key: string]: string | number | boolean | undefined;
121
+ }
122
+ /**
123
+ * Full visualization hint with type and optional parameters.
124
+ */
125
+ export interface TqlVizHint {
126
+ type: TqlVisualizationType;
127
+ params?: TqlVizParams;
128
+ }
105
129
  export interface TqlParseResult {
106
130
  ast: TqlExpression | null;
107
131
  tokens: TqlToken[];