@tellaro/tql 0.1.10 → 0.1.12

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.
@@ -1,7 +1,7 @@
1
1
  var I = Object.defineProperty;
2
2
  var S = (e, t, a) => t in e ? I(e, t, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[t] = a;
3
3
  var p = (e, t, a) => S(e, typeof t != "symbol" ? t + "" : t, a);
4
- import { tokenizeTql as b, COMPARISON_OPERATORS as A, LOGICAL_OPERATORS as L, AGGREGATION_FUNCTIONS as R, VISUALIZATION_TYPES as $, TYPE_HINTS as P, MUTATORS as D } from "./tokenizer.js";
4
+ import { tokenizeTql as b, COMPARISON_OPERATORS as A, LOGICAL_OPERATORS as L, AGGREGATION_FUNCTIONS as R, VISUALIZATION_TYPES as $, TYPE_HINTS as P, MUTATORS as D, ENRICHMENT_MUTATORS as ENRICHMENT_MUTATORS, MUTATOR_PARAMETERS as MUTATOR_PARAMETERS } from "./tokenizer.js";
5
5
  import { fuzzyMatch as _ } from "./fuzzyMatcher.js";
6
6
  import { getSchemaCache as M } from "./schemaCache.js";
7
7
  const E = [
@@ -256,8 +256,8 @@ class q {
256
256
  }
257
257
  set(t, a) {
258
258
  if (this.cache.size >= this.maxSize) {
259
- const o = this.cache.keys().next().value;
260
- o && this.cache.delete(o);
259
+ const i = this.cache.keys().next().value;
260
+ i && this.cache.delete(i);
261
261
  }
262
262
  this.cache.set(t, { result: a, timestamp: Date.now() });
263
263
  }
@@ -267,22 +267,28 @@ class q {
267
267
  }
268
268
  const v = new q();
269
269
  function B(e, t, a) {
270
- const o = `${e.substring(0, t)}|${t}`, i = v.get(o);
271
- if (i)
272
- return i.fieldName && !i.fieldType && a && (i.fieldType = f(i.fieldName, a)), i;
270
+ const i = `${e.substring(0, t)}|${t}`, o = v.get(i);
271
+ if (o)
272
+ return o.fieldName && !o.fieldType && a && (o.fieldType = f(o.fieldName, a)), o;
273
273
  const n = G(e, t, a);
274
- return v.set(o, n), n;
274
+ return v.set(i, n), n;
275
275
  }
276
276
  function G(e, t, a) {
277
277
  var u;
278
- const i = b(e.substring(0, t)).filter((l) => l.type !== "whitespace");
279
- if (i.length === 0)
278
+ const o = b(e.substring(0, t)).filter((l) => l.type !== "whitespace");
279
+ if (o.length === 0)
280
280
  return { type: "start" };
281
- const n = i[i.length - 1], r = i.length > 1 ? i[i.length - 2] : null, d = n.end === t && !((u = e[t - 1]) != null && u.match(/\s/)), s = d ? n.value : void 0;
281
+ const n = o[o.length - 1], r = o.length > 1 ? o[o.length - 2] : null, d = n.end === t && !((u = e[t - 1]) != null && u.match(/\s/)), s = d ? n.value : void 0;
282
282
  if (n.type === "logicalOp")
283
283
  return { type: "start" };
284
- if (n.type === "paren" && n.value === "(")
284
+ if (n.type === "paren" && n.value === "(") {
285
+ // Check if previous token is a mutator - we're inside mutator params
286
+ if (r && r.type === "mutator") {
287
+ const mutatorName = r.value.toLowerCase();
288
+ return { type: "mutator_params", mutatorName: mutatorName, usedParams: [], partialText: s };
289
+ }
285
290
  return { type: "after_paren" };
291
+ }
286
292
  if (n.type === "arrow")
287
293
  return { type: "after_arrow", partialText: s };
288
294
  if (n.type === "doubleColon")
@@ -347,21 +353,29 @@ function G(e, t, a) {
347
353
  function f(e, t) {
348
354
  return t ? M().getFieldType(t, e) : void 0;
349
355
  }
350
- function te(e, t = {}) {
351
- const { query: a, cursorPosition: o } = e, i = B(a, o, t.fields), n = [];
352
- switch (i.type) {
356
+ function ae(e, t = {}) {
357
+ const { query: a, cursorPosition: i } = e, o = B(a, i, t.fields), n = [];
358
+ switch (o.type) {
353
359
  case "start":
354
360
  case "after_paren":
355
- n.push(...y(t.fields, i.partialText)), n.push(N("NOT")), t.includeSnippets !== !1 && n.push(...Y(t, i.partialText));
361
+ n.push(...y(t.fields, o.partialText)), n.push(N("NOT")), t.includeSnippets !== !1 && n.push(...K(t, o.partialText));
356
362
  break;
357
363
  case "after_field":
358
- n.push(...x(i.partialText, i.fieldType));
364
+ n.push(...x(o.partialText, o.fieldType)), n.push(H());
359
365
  break;
360
366
  case "after_mutator":
361
- n.push(...x(i.partialText, i.mutatorOutputType));
367
+ // Check if this is an enrichment mutator (geo, nslookup, etc.)
368
+ // Enrichment mutators don't need operators - they transform the field into enriched data
369
+ if (o.mutatorName && ENRICHMENT_MUTATORS.includes(o.mutatorName)) {
370
+ // Suggest logical operators (AND, OR) or pipe for chaining
371
+ n.push(...C());
372
+ n.push(H());
373
+ } else {
374
+ n.push(...x(o.partialText, o.mutatorOutputType));
375
+ }
362
376
  break;
363
377
  case "after_operator":
364
- n.push(...H(i.fieldName, t));
378
+ n.push(...Y(o.fieldName, t));
365
379
  break;
366
380
  case "after_value":
367
381
  n.push(...C());
@@ -369,28 +383,31 @@ function te(e, t = {}) {
369
383
  case "at_value_end":
370
384
  break;
371
385
  case "after_pipe":
372
- n.push(...K(i.partialText));
386
+ n.push(...W(o.partialText));
373
387
  break;
374
388
  case "after_double_colon":
375
- n.push(...W(i.partialText));
389
+ n.push(...Z(o.partialText));
376
390
  break;
377
391
  case "after_arrow":
378
- n.push(...Z(i.partialText));
392
+ n.push(...J(o.partialText));
379
393
  break;
380
394
  case "after_stats":
381
- n.push(...O(i.partialText));
395
+ n.push(...O(o.partialText));
382
396
  break;
383
397
  case "after_by":
384
- n.push(...y(t.fields, i.partialText));
398
+ n.push(...y(t.fields, o.partialText));
399
+ break;
400
+ case "mutator_params":
401
+ n.push(...getMutatorParameterCompletions(o.mutatorName, o.usedParams, o.partialText));
385
402
  break;
386
403
  default:
387
- n.push(...y(t.fields, i.partialText)), n.push(...x(i.partialText)), n.push(...C());
404
+ n.push(...y(t.fields, o.partialText)), n.push(...x(o.partialText)), n.push(...C());
388
405
  }
389
- t.includeAggregations && i.type === "start" && n.push(...O(i.partialText));
406
+ t.includeAggregations && o.type === "start" && n.push(...O(o.partialText));
390
407
  let r = n;
391
408
  const d = t.fuzzyMatching !== !1, s = t.minFuzzyScore ?? 0;
392
- if (i.partialText) {
393
- const u = i.partialText.toLowerCase();
409
+ if (o.partialText) {
410
+ const u = o.partialText.toLowerCase();
394
411
  if (d) {
395
412
  const l = [];
396
413
  for (const c of n) {
@@ -416,11 +433,11 @@ function y(e, t) {
416
433
  if (!e || e.length === 0)
417
434
  return V(t);
418
435
  const a = [];
419
- for (const o of e) {
420
- const i = k(o);
421
- if (a.push(i), o.nested)
422
- for (const n of o.nested) {
423
- const r = k(n, o.name);
436
+ for (const i of e) {
437
+ const o = k(i);
438
+ if (a.push(o), i.nested)
439
+ for (const n of i.nested) {
440
+ const r = k(n, i.name);
424
441
  a.push(r);
425
442
  }
426
443
  }
@@ -466,18 +483,18 @@ function k(e, t) {
466
483
  }
467
484
  function x(e, t) {
468
485
  let a = [...A];
469
- return t && (a = a.filter((o) => {
470
- const i = F[o];
471
- return !i || i.includes(t);
472
- })), e && (a = a.filter((o) => o.toLowerCase().includes(e.toLowerCase()))), a.map((o, i) => {
473
- const n = U[o] || { detail: o, documentation: "" }, r = j(o, t);
486
+ return t && (a = a.filter((i) => {
487
+ const o = F[i];
488
+ return !o || o.includes(t);
489
+ })), e && (a = a.filter((i) => i.toLowerCase().includes(e.toLowerCase()))), a.map((i, o) => {
490
+ const n = U[i] || { detail: i, documentation: "" }, r = j(i, t);
474
491
  return {
475
- label: o,
492
+ label: i,
476
493
  insertText: r,
477
494
  kind: "operator",
478
495
  detail: n.detail,
479
496
  documentation: n.documentation,
480
- sortOrder: 20 + i
497
+ sortOrder: 20 + o
481
498
  };
482
499
  });
483
500
  }
@@ -494,14 +511,14 @@ function j(e, t) {
494
511
  "not_regexp",
495
512
  "matches",
496
513
  "not_matches"
497
- ], o = ["exists", "not_exists"], i = ["is", "is_not"];
514
+ ], i = ["exists", "not_exists"], o = ["is", "is_not"];
498
515
  if (e === "in" || e === "not_in")
499
516
  return T(t) ? `${e} [$1]` : `${e} ["$1"]`;
500
517
  if (e === "between" || e === "not_between")
501
518
  return T(t) ? `${e} $1 AND $2` : `${e} "$1" AND "$2"`;
502
- if (i.includes(e))
503
- return `${e} null`;
504
519
  if (o.includes(e))
520
+ return `${e} null`;
521
+ if (i.includes(e))
505
522
  return e;
506
523
  if (e === "cidr" || e === "not_cidr")
507
524
  return `${e} "$1"`;
@@ -545,10 +562,21 @@ function N(e, t = 0) {
545
562
  sortOrder: 30 + t
546
563
  };
547
564
  }
548
- function H(e, t) {
549
- var o;
565
+ function H() {
566
+ return {
567
+ label: "|",
568
+ insertText: "| ",
569
+ kind: "operator",
570
+ detail: "Pipe to mutator",
571
+ documentation: "Chain field to a mutator function (e.g., hostname | lower)",
572
+ sortOrder: 19
573
+ // Just before operators (20+)
574
+ };
575
+ }
576
+ function Y(e, t) {
577
+ var i;
550
578
  const a = [];
551
- return e && ((o = t == null ? void 0 : t.fieldValues) != null && o[e]) && t.fieldValues[e].forEach((n, r) => {
579
+ return e && ((i = t == null ? void 0 : t.fieldValues) != null && i[e]) && t.fieldValues[e].forEach((n, r) => {
552
580
  a.push({
553
581
  label: n,
554
582
  insertText: `"${n}"`,
@@ -587,26 +615,26 @@ function H(e, t) {
587
615
  }
588
616
  ), a;
589
617
  }
590
- function Y(e, t) {
591
- return E.filter((o) => !t || o.label.toLowerCase().includes(t.toLowerCase())).map((o, i) => ({
592
- label: o.label,
593
- insertText: o.insertText,
618
+ function K(e, t) {
619
+ return E.filter((i) => !t || i.label.toLowerCase().includes(t.toLowerCase())).map((i, o) => ({
620
+ label: i.label,
621
+ insertText: i.insertText,
594
622
  kind: "snippet",
595
- detail: o.description,
596
- documentation: `Insert: ${o.insertText}`,
597
- sortOrder: 100 + i
623
+ detail: i.description,
624
+ documentation: `Insert: ${i.insertText}`,
625
+ sortOrder: 100 + o
598
626
  }));
599
627
  }
600
- function K(e) {
628
+ function W(e) {
601
629
  return D.filter((t) => !e || t.toLowerCase().includes(e.toLowerCase())).map(
602
630
  (t, a) => {
603
- const o = z[t] || { detail: "Field mutator", documentation: "" };
631
+ const i = z[t] || { detail: "Field mutator", documentation: "" };
604
632
  return {
605
633
  label: t,
606
634
  insertText: t,
607
635
  kind: "mutator",
608
- detail: o.detail,
609
- documentation: o.documentation,
636
+ detail: i.detail,
637
+ documentation: i.documentation,
610
638
  sortOrder: 60 + a
611
639
  };
612
640
  }
@@ -623,7 +651,7 @@ function O(e) {
623
651
  sortOrder: 70 + a
624
652
  }));
625
653
  }
626
- function W(e) {
654
+ function Z(e) {
627
655
  return P.filter(
628
656
  (t) => !e || t.toLowerCase().includes(e.toLowerCase())
629
657
  ).map((t, a) => ({
@@ -634,7 +662,7 @@ function W(e) {
634
662
  sortOrder: 80 + a
635
663
  }));
636
664
  }
637
- function Z(e) {
665
+ function J(e) {
638
666
  return $.filter(
639
667
  (t) => !e || t.toLowerCase().includes(e.toLowerCase())
640
668
  ).map((t, a) => ({
@@ -645,27 +673,73 @@ function Z(e) {
645
673
  sortOrder: 90 + a
646
674
  }));
647
675
  }
648
- function ae(e, t) {
649
- const o = b(e).find(
650
- (i) => i.start <= t && i.end >= t && i.type !== "whitespace"
676
+ function ne(e, t) {
677
+ const i = b(e).find(
678
+ (o) => o.start <= t && o.end >= t && o.type !== "whitespace"
651
679
  );
652
- return o ? {
653
- word: o.value,
654
- start: o.start,
655
- end: o.end
680
+ return i ? {
681
+ word: i.value,
682
+ start: i.start,
683
+ end: i.end
656
684
  } : null;
657
685
  }
658
- function ne() {
686
+ function oe() {
659
687
  return [" ", "(", ".", '"', "'", "|", ":", "="];
660
688
  }
661
689
  function ie(e, t, a) {
662
690
  if (a === " " || a === "(" || a === "." || a === "|" || a === ":" || a === "=") return !0;
663
- const o = b(e.substring(0, t)), i = o[o.length - 1];
664
- return !!(i && i.type === "field" && i.value.length >= 2);
691
+ const i = b(e.substring(0, t)), o = i[i.length - 1];
692
+ return !!(o && o.type === "field" && o.value.length >= 2);
693
+ }
694
+ /**
695
+ * Get mutator parameter completions
696
+ * @param mutatorName - The mutator name (e.g., "geo", "nslookup")
697
+ * @param usedParams - Parameters already used in the current call
698
+ * @param partialText - Partial text for filtering
699
+ */
700
+ function getMutatorParameterCompletions(mutatorName, usedParams = [], partialText) {
701
+ const params = MUTATOR_PARAMETERS[mutatorName];
702
+ if (!params || params.length === 0) {
703
+ return [];
704
+ }
705
+
706
+ // Filter out already used parameters
707
+ const usedSet = new Set(usedParams.map(p => p.toLowerCase()));
708
+ const availableParams = params.filter(p => !usedSet.has(p.name.toLowerCase()));
709
+
710
+ // Filter by partial text if provided
711
+ let filteredParams = availableParams;
712
+ if (partialText) {
713
+ const searchText = partialText.toLowerCase();
714
+ filteredParams = availableParams.filter(p =>
715
+ p.name.toLowerCase().includes(searchText)
716
+ );
717
+ }
718
+
719
+ return filteredParams.map((param, idx) => {
720
+ // Generate insert text based on parameter type
721
+ let insertText = `${param.name}=`;
722
+ if (param.type === "boolean") {
723
+ insertText = `${param.name}=true`;
724
+ } else if (param.type === "string") {
725
+ insertText = `${param.name}="$1"`;
726
+ } else if (param.type === "number") {
727
+ insertText = `${param.name}=$1`;
728
+ }
729
+
730
+ return {
731
+ label: param.name,
732
+ insertText: insertText,
733
+ kind: "property",
734
+ detail: `${param.type} - ${param.description}`,
735
+ documentation: param.description,
736
+ sortOrder: 100 + idx
737
+ };
738
+ });
665
739
  }
666
740
  export {
667
- ne as getCompletionTriggerCharacters,
668
- te as getCompletions,
669
- ae as getWordAtPosition,
741
+ oe as getCompletionTriggerCharacters,
742
+ ae as getCompletions,
743
+ ne as getWordAtPosition,
670
744
  ie as shouldTriggerCompletion
671
745
  };
@@ -1,7 +1,7 @@
1
1
  var c = Object.defineProperty;
2
2
  var d = (r, e, t) => e in r ? c(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
3
  var o = (r, e, t) => d(r, typeof e != "symbol" ? e + "" : e, t);
4
- import { tokenizeTql as p, COMPARISON_OPERATORS as v } from "./tokenizer.js";
4
+ import { tokenizeTql as p, COMPARISON_OPERATORS as v, ENRICHMENT_MUTATORS as ENRICHMENT_MUTATORS } from "./tokenizer.js";
5
5
  const f = 50, k = /* @__PURE__ */ new Set(["logicalOp", "paren"]);
6
6
  class y {
7
7
  constructor(e) {
@@ -220,6 +220,22 @@ class y {
220
220
  mutators: n,
221
221
  end: this.previous().end
222
222
  }), !this.check("operator")) {
223
+ // Check if the last mutator is an enrichment mutator (geo, nslookup, etc.)
224
+ // Enrichment mutators don't require an operator - they transform the field into enriched data
225
+ const lastMutator = n.length > 0 ? n[n.length - 1] : null;
226
+ const isEnrichmentMutator = lastMutator && ENRICHMENT_MUTATORS.includes(lastMutator);
227
+
228
+ if (isEnrichmentMutator) {
229
+ // Return a valid enrichment expression without error
230
+ return {
231
+ type: "enrichment",
232
+ field: t,
233
+ mutator: lastMutator,
234
+ start: t.start,
235
+ end: t.end
236
+ };
237
+ }
238
+
223
239
  const s = this.isAtEnd() ? this.previous() : this.peek(), h = n.length > 0 ? `'${e.value}' with mutator` : `'${e.value}'`;
224
240
  return this.addError(
225
241
  `Expected operator after field ${h}`,
@@ -20,6 +20,20 @@ export declare const COLLECTION_OPERATORS: TqlCollectionOperator[];
20
20
  * Synchronized with Python/Rust implementations.
21
21
  */
22
22
  export declare const MUTATORS: TqlMutator[];
23
+ /**
24
+ * Enrichment mutators that don't require an operator after them.
25
+ * These mutators transform the field into an enriched object/value that stands alone.
26
+ */
27
+ export declare const ENRICHMENT_MUTATORS: string[];
28
+ /**
29
+ * Parameters available for mutators that support function call syntax.
30
+ */
31
+ export interface MutatorParameter {
32
+ name: string;
33
+ type: 'boolean' | 'string' | 'number';
34
+ description: string;
35
+ }
36
+ export declare const MUTATOR_PARAMETERS: Record<string, MutatorParameter[]>;
23
37
  /**
24
38
  * All aggregation functions supported by TQL.
25
39
  * Synchronized with Python/Rust implementations.
@@ -1,6 +1,52 @@
1
1
  var l = Object.defineProperty;
2
2
  var u = (o, e, n) => e in o ? l(o, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : o[e] = n;
3
3
  var a = (o, e, n) => u(o, typeof e != "symbol" ? e + "" : e, n);
4
+ // Enrichment mutators that don't require an operator after them
5
+ // These mutators transform the field into an enriched object/value that stands alone
6
+ const ENRICHMENT_MUTATORS = [
7
+ "geo",
8
+ "geoip",
9
+ "geoip_lookup",
10
+ "nslookup"
11
+ ];
12
+
13
+ // Parameters available for mutators that support function call syntax
14
+ // e.g., geo(force=true, save=true)
15
+ const MUTATOR_PARAMETERS = {
16
+ geo: [
17
+ { name: "force", type: "boolean", description: "Force lookup even if geo data already exists" },
18
+ { name: "save", type: "boolean", description: "Save results to the record" },
19
+ { name: "field", type: "string", description: "Field name to save results to" },
20
+ { name: "cache", type: "boolean", description: "Enable caching of lookup results" },
21
+ { name: "cache_ttl", type: "number", description: "Cache TTL in seconds" }
22
+ ],
23
+ geoip: [
24
+ { name: "force", type: "boolean", description: "Force lookup even if geo data already exists" },
25
+ { name: "save", type: "boolean", description: "Save results to the record" },
26
+ { name: "field", type: "string", description: "Field name to save results to" },
27
+ { name: "cache", type: "boolean", description: "Enable caching of lookup results" },
28
+ { name: "cache_ttl", type: "number", description: "Cache TTL in seconds" }
29
+ ],
30
+ geoip_lookup: [
31
+ { name: "force", type: "boolean", description: "Force lookup even if geo data already exists" },
32
+ { name: "save", type: "boolean", description: "Save results to the record" },
33
+ { name: "field", type: "string", description: "Field name to save results to" },
34
+ { name: "cache", type: "boolean", description: "Enable caching of lookup results" },
35
+ { name: "cache_ttl", type: "number", description: "Cache TTL in seconds" }
36
+ ],
37
+ nslookup: [
38
+ { name: "record_type", type: "string", description: "DNS record type (A, AAAA, MX, etc.)" },
39
+ { name: "cache", type: "boolean", description: "Enable caching of lookup results" },
40
+ { name: "cache_ttl", type: "number", description: "Cache TTL in seconds" }
41
+ ],
42
+ split: [
43
+ { name: "delimiter", type: "string", description: "Delimiter to split on (default: comma)" }
44
+ ],
45
+ replace: [
46
+ { name: "find", type: "string", description: "Text to find" },
47
+ { name: "replace", type: "string", description: "Text to replace with" }
48
+ ]
49
+ };
4
50
  const p = [
5
51
  // Equality
6
52
  "eq",
@@ -413,9 +459,11 @@ export {
413
459
  _ as AGGREGATION_FUNCTIONS,
414
460
  f as COLLECTION_OPERATORS,
415
461
  p as COMPARISON_OPERATORS,
462
+ ENRICHMENT_MUTATORS,
416
463
  w as KEYWORDS,
417
464
  k as LOGICAL_OPERATORS,
418
465
  m as MUTATORS,
466
+ MUTATOR_PARAMETERS,
419
467
  d as NEGATION_SYMBOL_OPERATORS,
420
468
  c as SYMBOL_OPERATORS,
421
469
  g as TYPE_HINTS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellaro/tql",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Tellaro Query Language (TQL) parser, validator, and autocomplete for JavaScript/TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,17 +23,11 @@
23
23
  "README.md"
24
24
  ],
25
25
  "scripts": {
26
- "build": "vite build",
27
26
  "test": "vitest run",
28
27
  "test:watch": "vitest",
29
28
  "test:shared": "vitest run --grep 'shared-fixtures'",
30
29
  "test:e2e": "playwright test",
31
- "test:e2e:ui": "playwright test --ui",
32
- "playground:serve": "vite --config vite.playground.config.ts --port 5174",
33
- "playground:dev": "vite --config vite.playground.config.ts",
34
- "lint": "eslint src vue tests --ext .ts,.vue",
35
- "typecheck": "vue-tsc --noEmit",
36
- "prepublishOnly": "npm run build"
30
+ "test:e2e:ui": "playwright test --ui"
37
31
  },
38
32
  "repository": {
39
33
  "type": "git",