@tellaro/tql 0.1.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/_virtual/_plugin-vue_export-helper.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +37 -0
- package/dist/src/completionProvider.d.ts +22 -0
- package/dist/src/completionProvider.js +619 -0
- package/dist/src/index.d.ts +13 -0
- package/dist/src/parser.d.ts +81 -0
- package/dist/src/parser.js +511 -0
- package/dist/src/tokenizer.d.ts +113 -0
- package/dist/src/tokenizer.js +430 -0
- package/dist/src/types.d.ts +221 -0
- package/dist/src/validator.d.ts +46 -0
- package/dist/src/validator.js +315 -0
- package/dist/style.css +1 -0
- package/dist/vue/TqlAutocomplete.vue.d.ts +2 -0
- package/dist/vue/TqlAutocomplete.vue.js +7 -0
- package/dist/vue/TqlAutocomplete.vue2.js +136 -0
- package/dist/vue/TqlInput.vue.d.ts +2 -0
- package/dist/vue/TqlInput.vue.js +7 -0
- package/dist/vue/TqlInput.vue2.js +326 -0
- package/dist/vue/index.d.ts +10 -0
- package/dist/vue/index.js +8 -0
- package/dist/vue/useTqlInput.js +166 -0
- package/package.json +79 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TQL (Tellaro Query Language) Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive type system for TQL parsing, validation, and autocomplete.
|
|
5
|
+
* Synchronized with tellaro-query-language Python/Rust implementations.
|
|
6
|
+
*/
|
|
7
|
+
export type TqlTokenType = "field" | "operator" | "logicalOp" | "collectionOp" | "string" | "number" | "boolean" | "null" | "paren" | "bracket" | "comma" | "pipe" | "arrow" | "doubleColon" | "mutator" | "aggregation" | "keyword" | "typeHint" | "visualization" | "whitespace" | "unknown" | "error";
|
|
8
|
+
export interface TqlToken {
|
|
9
|
+
type: TqlTokenType;
|
|
10
|
+
value: string;
|
|
11
|
+
start: number;
|
|
12
|
+
end: number;
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
raw?: string;
|
|
16
|
+
}
|
|
17
|
+
export type TqlExpression = TqlBinaryExpression | TqlUnaryExpression | TqlComparisonExpression | TqlCollectionExpression | TqlMutatorExpression | TqlAggregationExpression | TqlStatsExpression | TqlGroupExpression | TqlLiteral | TqlFieldReference;
|
|
18
|
+
export interface TqlBinaryExpression {
|
|
19
|
+
type: "binary";
|
|
20
|
+
operator: "AND" | "OR";
|
|
21
|
+
left: TqlExpression;
|
|
22
|
+
right: TqlExpression;
|
|
23
|
+
start: number;
|
|
24
|
+
end: number;
|
|
25
|
+
}
|
|
26
|
+
export interface TqlUnaryExpression {
|
|
27
|
+
type: "unary";
|
|
28
|
+
operator: "NOT";
|
|
29
|
+
operand: TqlExpression;
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
}
|
|
33
|
+
export interface TqlComparisonExpression {
|
|
34
|
+
type: "comparison";
|
|
35
|
+
field: TqlFieldReference | TqlMutatorExpression;
|
|
36
|
+
operator: TqlComparisonOperator;
|
|
37
|
+
value: TqlLiteral | TqlLiteral[];
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
}
|
|
41
|
+
export interface TqlCollectionExpression {
|
|
42
|
+
type: "collection";
|
|
43
|
+
operator: "ANY" | "ALL" | "NONE";
|
|
44
|
+
field: TqlFieldReference;
|
|
45
|
+
condition: TqlExpression;
|
|
46
|
+
start: number;
|
|
47
|
+
end: number;
|
|
48
|
+
}
|
|
49
|
+
export interface TqlMutatorExpression {
|
|
50
|
+
type: "mutator";
|
|
51
|
+
mutator: TqlMutator;
|
|
52
|
+
field: TqlFieldReference | TqlMutatorExpression;
|
|
53
|
+
args?: TqlLiteral[];
|
|
54
|
+
start: number;
|
|
55
|
+
end: number;
|
|
56
|
+
}
|
|
57
|
+
export interface TqlAggregationExpression {
|
|
58
|
+
type: "aggregation";
|
|
59
|
+
function: TqlAggregationFunction;
|
|
60
|
+
field?: TqlFieldReference;
|
|
61
|
+
args?: (string | number)[];
|
|
62
|
+
alias?: string;
|
|
63
|
+
start: number;
|
|
64
|
+
end: number;
|
|
65
|
+
}
|
|
66
|
+
export interface TqlStatsExpression {
|
|
67
|
+
type: "stats";
|
|
68
|
+
aggregations: TqlAggregationExpression[];
|
|
69
|
+
groupBy?: TqlFieldReference[];
|
|
70
|
+
topN?: number;
|
|
71
|
+
bottomN?: number;
|
|
72
|
+
visualization?: TqlVisualizationType;
|
|
73
|
+
start: number;
|
|
74
|
+
end: number;
|
|
75
|
+
}
|
|
76
|
+
export interface TqlGroupExpression {
|
|
77
|
+
type: "group";
|
|
78
|
+
expression: TqlExpression;
|
|
79
|
+
start: number;
|
|
80
|
+
end: number;
|
|
81
|
+
}
|
|
82
|
+
export interface TqlLiteral {
|
|
83
|
+
type: "literal";
|
|
84
|
+
valueType: "string" | "number" | "boolean" | "null";
|
|
85
|
+
value: string | number | boolean | null;
|
|
86
|
+
start: number;
|
|
87
|
+
end: number;
|
|
88
|
+
}
|
|
89
|
+
export interface TqlFieldReference {
|
|
90
|
+
type: "field";
|
|
91
|
+
name: string;
|
|
92
|
+
path: string[];
|
|
93
|
+
mutators?: string[];
|
|
94
|
+
typeHint?: TqlTypeHint;
|
|
95
|
+
start: number;
|
|
96
|
+
end: number;
|
|
97
|
+
}
|
|
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";
|
|
99
|
+
export type TqlLogicalOperator = "AND" | "OR" | "NOT";
|
|
100
|
+
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";
|
|
102
|
+
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
|
+
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";
|
|
105
|
+
export interface TqlParseResult {
|
|
106
|
+
ast: TqlExpression | null;
|
|
107
|
+
tokens: TqlToken[];
|
|
108
|
+
errors: TqlParseError[];
|
|
109
|
+
warnings: TqlParseWarning[];
|
|
110
|
+
success: boolean;
|
|
111
|
+
}
|
|
112
|
+
export interface TqlParseError {
|
|
113
|
+
message: string;
|
|
114
|
+
start: number;
|
|
115
|
+
end: number;
|
|
116
|
+
line: number;
|
|
117
|
+
column: number;
|
|
118
|
+
severity: "error";
|
|
119
|
+
code: TqlErrorCode;
|
|
120
|
+
suggestion?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface TqlParseWarning {
|
|
123
|
+
message: string;
|
|
124
|
+
start: number;
|
|
125
|
+
end: number;
|
|
126
|
+
line: number;
|
|
127
|
+
column: number;
|
|
128
|
+
severity: "warning";
|
|
129
|
+
code: TqlWarningCode;
|
|
130
|
+
suggestion?: string;
|
|
131
|
+
}
|
|
132
|
+
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";
|
|
133
|
+
export type TqlWarningCode = "UNKNOWN_FIELD" | "TYPE_MISMATCH" | "DEPRECATED_OPERATOR" | "REDUNDANT_PARENS";
|
|
134
|
+
export interface TqlValidationResult {
|
|
135
|
+
valid: boolean;
|
|
136
|
+
errors: TqlParseError[];
|
|
137
|
+
warnings: TqlParseWarning[];
|
|
138
|
+
}
|
|
139
|
+
export interface TqlValidationOptions {
|
|
140
|
+
availableFields?: string[];
|
|
141
|
+
fieldTypes?: Record<string, TqlFieldType>;
|
|
142
|
+
strictMode?: boolean;
|
|
143
|
+
allowAggregations?: boolean;
|
|
144
|
+
allowMutators?: boolean;
|
|
145
|
+
maxDepth?: number;
|
|
146
|
+
}
|
|
147
|
+
export type TqlFieldType = "text" | "keyword" | "long" | "integer" | "short" | "byte" | "double" | "float" | "half_float" | "scaled_float" | "unsigned_long" | "date" | "boolean" | "ip" | "nested" | "object" | "geo_point";
|
|
148
|
+
export interface TqlCompletionItem {
|
|
149
|
+
label: string;
|
|
150
|
+
insertText: string;
|
|
151
|
+
kind: TqlCompletionKind;
|
|
152
|
+
detail?: string;
|
|
153
|
+
documentation?: string;
|
|
154
|
+
sortOrder: number;
|
|
155
|
+
filterText?: string;
|
|
156
|
+
commitCharacters?: string[];
|
|
157
|
+
}
|
|
158
|
+
export type TqlCompletionKind = "field" | "operator" | "value" | "keyword" | "snippet" | "mutator" | "aggregation" | "logicalOp" | "typeHint" | "visualization";
|
|
159
|
+
export interface TqlCompletionContext {
|
|
160
|
+
query: string;
|
|
161
|
+
cursorPosition: number;
|
|
162
|
+
triggerKind: "invoked" | "character" | "automatic";
|
|
163
|
+
triggerCharacter?: string;
|
|
164
|
+
}
|
|
165
|
+
export interface TqlCompletionOptions {
|
|
166
|
+
fields?: TqlFieldSchema[];
|
|
167
|
+
includeSnippets?: boolean;
|
|
168
|
+
includeMutators?: boolean;
|
|
169
|
+
includeAggregations?: boolean;
|
|
170
|
+
includeTypeHints?: boolean;
|
|
171
|
+
includeVisualizations?: boolean;
|
|
172
|
+
maxItems?: number;
|
|
173
|
+
fieldValues?: Record<string, string[]>;
|
|
174
|
+
}
|
|
175
|
+
export interface TqlFieldSchema {
|
|
176
|
+
name: string;
|
|
177
|
+
type: TqlFieldType;
|
|
178
|
+
description?: string;
|
|
179
|
+
examples?: string[];
|
|
180
|
+
path?: string[];
|
|
181
|
+
nested?: TqlFieldSchema[];
|
|
182
|
+
}
|
|
183
|
+
export interface TqlSnippet {
|
|
184
|
+
label: string;
|
|
185
|
+
insertText: string;
|
|
186
|
+
description?: string;
|
|
187
|
+
category?: string;
|
|
188
|
+
}
|
|
189
|
+
export interface TqlInputProps {
|
|
190
|
+
modelValue: string;
|
|
191
|
+
placeholder?: string;
|
|
192
|
+
disabled?: boolean;
|
|
193
|
+
readonly?: boolean;
|
|
194
|
+
rows?: number;
|
|
195
|
+
multiline?: boolean;
|
|
196
|
+
showValidation?: boolean;
|
|
197
|
+
validateOnInput?: boolean;
|
|
198
|
+
debounceMs?: number;
|
|
199
|
+
fieldSchema?: TqlFieldSchema[];
|
|
200
|
+
modelName?: string;
|
|
201
|
+
snippets?: TqlSnippet[];
|
|
202
|
+
showSnippetButton?: boolean;
|
|
203
|
+
autocomplete?: boolean;
|
|
204
|
+
syntaxHighlighting?: boolean;
|
|
205
|
+
}
|
|
206
|
+
export interface TqlInputEmits {
|
|
207
|
+
(e: "update:modelValue", value: string): void;
|
|
208
|
+
(e: "validation", result: TqlValidationResult): void;
|
|
209
|
+
(e: "parse", result: TqlParseResult): void;
|
|
210
|
+
(e: "submit", value: string): void;
|
|
211
|
+
}
|
|
212
|
+
export interface TqlInputExpose {
|
|
213
|
+
focus(): void;
|
|
214
|
+
blur(): void;
|
|
215
|
+
validate(): TqlValidationResult;
|
|
216
|
+
insertText(text: string): void;
|
|
217
|
+
insertSnippet(snippet: TqlSnippet): void;
|
|
218
|
+
getTokenAtPosition(pos: number): TqlToken | null;
|
|
219
|
+
getCursorPosition(): number;
|
|
220
|
+
setCursorPosition(pos: number): void;
|
|
221
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { TqlParseError, TqlParseWarning, TqlValidationOptions, TqlValidationResult } from './types';
|
|
2
|
+
|
|
3
|
+
export declare class TqlValidator {
|
|
4
|
+
private options;
|
|
5
|
+
private errors;
|
|
6
|
+
private warnings;
|
|
7
|
+
constructor(options?: TqlValidationOptions);
|
|
8
|
+
/**
|
|
9
|
+
* Validate a TQL query
|
|
10
|
+
*/
|
|
11
|
+
validate(query: string): TqlValidationResult;
|
|
12
|
+
/**
|
|
13
|
+
* Validate an expression recursively
|
|
14
|
+
*/
|
|
15
|
+
private validateExpression;
|
|
16
|
+
/**
|
|
17
|
+
* Validate a comparison expression
|
|
18
|
+
*/
|
|
19
|
+
private validateComparison;
|
|
20
|
+
/**
|
|
21
|
+
* Suggest a similar field name using Levenshtein distance
|
|
22
|
+
*/
|
|
23
|
+
private suggestField;
|
|
24
|
+
/**
|
|
25
|
+
* Calculate Levenshtein distance between two strings
|
|
26
|
+
*/
|
|
27
|
+
private levenshteinDistance;
|
|
28
|
+
private addError;
|
|
29
|
+
private addWarning;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validate a TQL query with options
|
|
33
|
+
*/
|
|
34
|
+
export declare function validateTql(query: string, options?: TqlValidationOptions): TqlValidationResult;
|
|
35
|
+
/**
|
|
36
|
+
* Quick check if TQL is valid (syntax only)
|
|
37
|
+
*/
|
|
38
|
+
export declare function isValidTqlSyntax(query: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get all validation issues (errors + warnings)
|
|
41
|
+
*/
|
|
42
|
+
export declare function getTqlIssues(query: string, options?: TqlValidationOptions): (TqlParseError | TqlParseWarning)[];
|
|
43
|
+
/**
|
|
44
|
+
* Format validation result for display
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatValidationResult(result: TqlValidationResult): string;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var u = (s, e, t) => e in s ? b(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
|
|
3
|
+
var r = (s, e, t) => u(s, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import { parseTql as c } from "./parser.js";
|
|
5
|
+
const f = {
|
|
6
|
+
// Equality (all types)
|
|
7
|
+
eq: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
8
|
+
ne: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
9
|
+
"=": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
10
|
+
"==": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
11
|
+
"!=": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
12
|
+
// Comparison (numeric and dates)
|
|
13
|
+
gt: ["long", "integer", "double", "float", "date"],
|
|
14
|
+
gte: ["long", "integer", "double", "float", "date"],
|
|
15
|
+
lt: ["long", "integer", "double", "float", "date"],
|
|
16
|
+
lte: ["long", "integer", "double", "float", "date"],
|
|
17
|
+
">": ["long", "integer", "double", "float", "date"],
|
|
18
|
+
">=": ["long", "integer", "double", "float", "date"],
|
|
19
|
+
"<": ["long", "integer", "double", "float", "date"],
|
|
20
|
+
"<=": ["long", "integer", "double", "float", "date"],
|
|
21
|
+
// String operations
|
|
22
|
+
contains: ["text", "keyword"],
|
|
23
|
+
not_contains: ["text", "keyword"],
|
|
24
|
+
"!contains": ["text", "keyword"],
|
|
25
|
+
startswith: ["text", "keyword"],
|
|
26
|
+
not_startswith: ["text", "keyword"],
|
|
27
|
+
"!startswith": ["text", "keyword"],
|
|
28
|
+
endswith: ["text", "keyword"],
|
|
29
|
+
not_endswith: ["text", "keyword"],
|
|
30
|
+
"!endswith": ["text", "keyword"],
|
|
31
|
+
regexp: ["text", "keyword"],
|
|
32
|
+
regex: ["text", "keyword"],
|
|
33
|
+
not_regexp: ["text", "keyword"],
|
|
34
|
+
"!regexp": ["text", "keyword"],
|
|
35
|
+
matches: ["text", "keyword"],
|
|
36
|
+
not_matches: ["text", "keyword"],
|
|
37
|
+
"!matches": ["text", "keyword"],
|
|
38
|
+
// Range
|
|
39
|
+
between: ["long", "integer", "double", "float", "date"],
|
|
40
|
+
not_between: ["long", "integer", "double", "float", "date"],
|
|
41
|
+
"!between": ["long", "integer", "double", "float", "date"],
|
|
42
|
+
in: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip"],
|
|
43
|
+
not_in: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip"],
|
|
44
|
+
"!in": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip"],
|
|
45
|
+
// Existence (all types)
|
|
46
|
+
exists: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
47
|
+
not_exists: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
48
|
+
"!exists": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
49
|
+
// Null checks (all types)
|
|
50
|
+
is: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
51
|
+
is_not: ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
52
|
+
"!is": ["text", "keyword", "long", "integer", "double", "float", "date", "boolean", "ip", "nested", "object", "geo_point"],
|
|
53
|
+
// IP-specific operators
|
|
54
|
+
cidr: ["ip"],
|
|
55
|
+
not_cidr: ["ip"],
|
|
56
|
+
"!cidr": ["ip"],
|
|
57
|
+
// Collection operators
|
|
58
|
+
any: ["nested", "object", "keyword", "text"],
|
|
59
|
+
all: ["nested", "object", "keyword", "text"],
|
|
60
|
+
none: ["nested", "object", "keyword", "text"],
|
|
61
|
+
not_any: ["nested", "object", "keyword", "text"],
|
|
62
|
+
not_all: ["nested", "object", "keyword", "text"],
|
|
63
|
+
not_none: ["nested", "object", "keyword", "text"],
|
|
64
|
+
"!any": ["nested", "object", "keyword", "text"],
|
|
65
|
+
"!all": ["nested", "object", "keyword", "text"],
|
|
66
|
+
"!none": ["nested", "object", "keyword", "text"]
|
|
67
|
+
}, d = {
|
|
68
|
+
cidr: ["ip"],
|
|
69
|
+
not_cidr: ["ip"],
|
|
70
|
+
"!cidr": ["ip"]
|
|
71
|
+
}, h = {
|
|
72
|
+
eq: ["string", "number", "boolean"],
|
|
73
|
+
ne: ["string", "number", "boolean"],
|
|
74
|
+
"=": ["string", "number", "boolean"],
|
|
75
|
+
"==": ["string", "number", "boolean"],
|
|
76
|
+
"!=": ["string", "number", "boolean"],
|
|
77
|
+
gt: ["number", "string"],
|
|
78
|
+
gte: ["number", "string"],
|
|
79
|
+
lt: ["number", "string"],
|
|
80
|
+
lte: ["number", "string"],
|
|
81
|
+
">": ["number", "string"],
|
|
82
|
+
">=": ["number", "string"],
|
|
83
|
+
"<": ["number", "string"],
|
|
84
|
+
"<=": ["number", "string"],
|
|
85
|
+
contains: ["string"],
|
|
86
|
+
not_contains: ["string"],
|
|
87
|
+
"!contains": ["string"],
|
|
88
|
+
startswith: ["string"],
|
|
89
|
+
not_startswith: ["string"],
|
|
90
|
+
"!startswith": ["string"],
|
|
91
|
+
endswith: ["string"],
|
|
92
|
+
not_endswith: ["string"],
|
|
93
|
+
"!endswith": ["string"],
|
|
94
|
+
regexp: ["string"],
|
|
95
|
+
regex: ["string"],
|
|
96
|
+
not_regexp: ["string"],
|
|
97
|
+
"!regexp": ["string"],
|
|
98
|
+
matches: ["string"],
|
|
99
|
+
not_matches: ["string"],
|
|
100
|
+
"!matches": ["string"],
|
|
101
|
+
between: ["number", "string"],
|
|
102
|
+
not_between: ["number", "string"],
|
|
103
|
+
"!between": ["number", "string"],
|
|
104
|
+
in: ["string", "number", "boolean"],
|
|
105
|
+
not_in: ["string", "number", "boolean"],
|
|
106
|
+
"!in": ["string", "number", "boolean"],
|
|
107
|
+
exists: ["boolean"],
|
|
108
|
+
not_exists: ["boolean"],
|
|
109
|
+
"!exists": ["boolean"],
|
|
110
|
+
is: ["null"],
|
|
111
|
+
is_not: ["null"],
|
|
112
|
+
"!is": ["null"],
|
|
113
|
+
cidr: ["string"],
|
|
114
|
+
not_cidr: ["string"],
|
|
115
|
+
"!cidr": ["string"],
|
|
116
|
+
any: ["string", "number", "boolean"],
|
|
117
|
+
all: ["string", "number", "boolean"],
|
|
118
|
+
none: ["string", "number", "boolean"],
|
|
119
|
+
not_any: ["string", "number", "boolean"],
|
|
120
|
+
not_all: ["string", "number", "boolean"],
|
|
121
|
+
not_none: ["string", "number", "boolean"],
|
|
122
|
+
"!any": ["string", "number", "boolean"],
|
|
123
|
+
"!all": ["string", "number", "boolean"],
|
|
124
|
+
"!none": ["string", "number", "boolean"]
|
|
125
|
+
};
|
|
126
|
+
class y {
|
|
127
|
+
constructor(e = {}) {
|
|
128
|
+
r(this, "options");
|
|
129
|
+
r(this, "errors");
|
|
130
|
+
r(this, "warnings");
|
|
131
|
+
this.options = e, this.errors = [], this.warnings = [];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Validate a TQL query
|
|
135
|
+
*/
|
|
136
|
+
validate(e) {
|
|
137
|
+
this.errors = [], this.warnings = [];
|
|
138
|
+
const t = c(e);
|
|
139
|
+
return this.errors.push(...t.errors), this.warnings.push(...t.warnings), t.ast && this.validateExpression(t.ast), {
|
|
140
|
+
valid: this.errors.length === 0,
|
|
141
|
+
errors: this.errors,
|
|
142
|
+
warnings: this.warnings
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Validate an expression recursively
|
|
147
|
+
*/
|
|
148
|
+
validateExpression(e) {
|
|
149
|
+
switch (e.type) {
|
|
150
|
+
case "binary":
|
|
151
|
+
this.validateExpression(e.left), this.validateExpression(e.right);
|
|
152
|
+
break;
|
|
153
|
+
case "unary":
|
|
154
|
+
this.validateExpression(e.operand);
|
|
155
|
+
break;
|
|
156
|
+
case "group":
|
|
157
|
+
this.validateExpression(e.expression);
|
|
158
|
+
break;
|
|
159
|
+
case "comparison":
|
|
160
|
+
this.validateComparison(e);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Validate a comparison expression
|
|
166
|
+
*/
|
|
167
|
+
validateComparison(e) {
|
|
168
|
+
const t = e.field.type === "field" ? e.field.name : "computed";
|
|
169
|
+
if (this.options.availableFields && this.options.strictMode && !this.options.availableFields.includes(t) && e.field.type === "field" && this.addWarning(
|
|
170
|
+
`Unknown field '${t}'`,
|
|
171
|
+
e.field.start,
|
|
172
|
+
e.field.end,
|
|
173
|
+
(e.field.type === "field", 1),
|
|
174
|
+
1,
|
|
175
|
+
"UNKNOWN_FIELD",
|
|
176
|
+
`Did you mean: ${this.suggestField(t)}`
|
|
177
|
+
), this.options.fieldTypes && e.field.type === "field") {
|
|
178
|
+
const o = this.options.fieldTypes[t];
|
|
179
|
+
if (o) {
|
|
180
|
+
const n = d[e.operator];
|
|
181
|
+
n && !n.includes(o) && this.addError(
|
|
182
|
+
`Operator '${e.operator}' requires field type ${n.join(" or ")}, but '${t}' is type '${o}'`,
|
|
183
|
+
e.start,
|
|
184
|
+
e.end,
|
|
185
|
+
1,
|
|
186
|
+
1,
|
|
187
|
+
"TYPE_MISMATCH",
|
|
188
|
+
`Use '${e.operator}' only with ${n.join(" or ")} fields`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (this.options.fieldTypes && e.field.type === "field") {
|
|
193
|
+
const o = this.options.fieldTypes[t];
|
|
194
|
+
if (o) {
|
|
195
|
+
const n = f[e.operator];
|
|
196
|
+
!d[e.operator] && n && !n.includes(o) && this.addWarning(
|
|
197
|
+
`Operator '${e.operator}' may not work well with field type '${o}'`,
|
|
198
|
+
e.start,
|
|
199
|
+
e.end,
|
|
200
|
+
1,
|
|
201
|
+
1,
|
|
202
|
+
"TYPE_MISMATCH",
|
|
203
|
+
`Consider using a different operator for ${o} fields`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!Array.isArray(e.value) && e.value.type === "literal") {
|
|
208
|
+
const o = h[e.operator];
|
|
209
|
+
o && !o.includes(e.value.valueType) && this.addWarning(
|
|
210
|
+
`Operator '${e.operator}' expects ${o.join(" or ")} value`,
|
|
211
|
+
e.value.start,
|
|
212
|
+
e.value.end,
|
|
213
|
+
1,
|
|
214
|
+
1,
|
|
215
|
+
"TYPE_MISMATCH"
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
if ((e.operator === "regexp" || e.operator === "regex" || e.operator === "not_regexp" || e.operator === "matches" || e.operator === "not_matches") && !Array.isArray(e.value) && e.value.valueType === "string" && typeof e.value.value == "string")
|
|
219
|
+
try {
|
|
220
|
+
new RegExp(e.value.value);
|
|
221
|
+
} catch {
|
|
222
|
+
this.addError(
|
|
223
|
+
`Invalid regular expression: ${e.value.value}`,
|
|
224
|
+
e.value.start,
|
|
225
|
+
e.value.end,
|
|
226
|
+
1,
|
|
227
|
+
1,
|
|
228
|
+
"INVALID_VALUE",
|
|
229
|
+
"Check the regex syntax"
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Suggest a similar field name using Levenshtein distance
|
|
235
|
+
*/
|
|
236
|
+
suggestField(e) {
|
|
237
|
+
if (!this.options.availableFields || this.options.availableFields.length === 0)
|
|
238
|
+
return "check available fields";
|
|
239
|
+
let t = this.options.availableFields[0], o = this.levenshteinDistance(e, t);
|
|
240
|
+
for (const n of this.options.availableFields) {
|
|
241
|
+
const i = this.levenshteinDistance(e, n);
|
|
242
|
+
i < o && (o = i, t = n);
|
|
243
|
+
}
|
|
244
|
+
return t;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Calculate Levenshtein distance between two strings
|
|
248
|
+
*/
|
|
249
|
+
levenshteinDistance(e, t) {
|
|
250
|
+
const o = [];
|
|
251
|
+
for (let n = 0; n <= t.length; n++)
|
|
252
|
+
o[n] = [n];
|
|
253
|
+
for (let n = 0; n <= e.length; n++)
|
|
254
|
+
o[0][n] = n;
|
|
255
|
+
for (let n = 1; n <= t.length; n++)
|
|
256
|
+
for (let i = 1; i <= e.length; i++)
|
|
257
|
+
t.charAt(n - 1) === e.charAt(i - 1) ? o[n][i] = o[n - 1][i - 1] : o[n][i] = Math.min(
|
|
258
|
+
o[n - 1][i - 1] + 1,
|
|
259
|
+
o[n][i - 1] + 1,
|
|
260
|
+
o[n - 1][i] + 1
|
|
261
|
+
);
|
|
262
|
+
return o[t.length][e.length];
|
|
263
|
+
}
|
|
264
|
+
addError(e, t, o, n, i, a, l) {
|
|
265
|
+
this.errors.push({
|
|
266
|
+
message: e,
|
|
267
|
+
start: t,
|
|
268
|
+
end: o,
|
|
269
|
+
line: n,
|
|
270
|
+
column: i,
|
|
271
|
+
severity: "error",
|
|
272
|
+
code: a,
|
|
273
|
+
suggestion: l
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
addWarning(e, t, o, n, i, a, l) {
|
|
277
|
+
this.warnings.push({
|
|
278
|
+
message: e,
|
|
279
|
+
start: t,
|
|
280
|
+
end: o,
|
|
281
|
+
line: n,
|
|
282
|
+
column: i,
|
|
283
|
+
severity: "warning",
|
|
284
|
+
code: a,
|
|
285
|
+
suggestion: l
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function g(s, e) {
|
|
290
|
+
return new y(e).validate(s);
|
|
291
|
+
}
|
|
292
|
+
function _(s) {
|
|
293
|
+
return g(s).valid;
|
|
294
|
+
}
|
|
295
|
+
function m(s, e) {
|
|
296
|
+
const t = g(s, e);
|
|
297
|
+
return [...t.errors, ...t.warnings];
|
|
298
|
+
}
|
|
299
|
+
function v(s) {
|
|
300
|
+
const e = [];
|
|
301
|
+
s.valid ? e.push("Query is valid") : e.push("Query has errors:");
|
|
302
|
+
for (const t of s.errors)
|
|
303
|
+
e.push(` Error: ${t.message}`), t.suggestion && e.push(` Suggestion: ${t.suggestion}`);
|
|
304
|
+
for (const t of s.warnings)
|
|
305
|
+
e.push(` Warning: ${t.message}`), t.suggestion && e.push(` Suggestion: ${t.suggestion}`);
|
|
306
|
+
return e.join(`
|
|
307
|
+
`);
|
|
308
|
+
}
|
|
309
|
+
export {
|
|
310
|
+
y as TqlValidator,
|
|
311
|
+
v as formatValidationResult,
|
|
312
|
+
m as getTqlIssues,
|
|
313
|
+
_ as isValidTqlSyntax,
|
|
314
|
+
g as validateTql
|
|
315
|
+
};
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.tql-autocomplete-dropdown[data-v-6381bbdd]{position:fixed;top:var(--dropdown-top);left:var(--dropdown-left);z-index:9999;min-width:280px;max-width:450px;max-height:var(--dropdown-max-height);background:var(--surface-overlay, #fff);border:1px solid var(--surface-border, #ddd);border-radius:var(--border-radius, 6px);box-shadow:0 4px 16px #00000026;overflow:hidden;display:flex;flex-direction:column}.tql-completion-list[data-v-6381bbdd]{overflow-y:auto;max-height:calc(var(--dropdown-max-height) - 60px)}.tql-completion-item[data-v-6381bbdd]{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;transition:background-color .15s}.tql-completion-item[data-v-6381bbdd]:hover,.tql-completion-item.selected[data-v-6381bbdd]{background:var(--highlight-bg, #f0f0f0)}.tql-completion-icon[data-v-6381bbdd]{display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:4px;font-size:.75rem}.tql-completion-icon.tql-completion-kind-field[data-v-6381bbdd]{background:var(--blue-100, #e3f2fd);color:var(--blue-600, #1e88e5)}.tql-completion-icon.tql-completion-kind-operator[data-v-6381bbdd]{background:var(--pink-100, #fce4ec);color:var(--pink-600, #d81b60)}.tql-completion-icon.tql-completion-kind-value[data-v-6381bbdd]{background:var(--green-100, #e8f5e9);color:var(--green-600, #43a047)}.tql-completion-icon.tql-completion-kind-keyword[data-v-6381bbdd]{background:var(--purple-100, #f3e5f5);color:var(--purple-600, #8e24aa)}.tql-completion-icon.tql-completion-kind-snippet[data-v-6381bbdd]{background:var(--orange-100, #fff3e0);color:var(--orange-600, #fb8c00)}.tql-completion-icon.tql-completion-kind-mutator[data-v-6381bbdd]{background:var(--cyan-100, #e0f7fa);color:var(--cyan-600, #00acc1)}.tql-completion-icon.tql-completion-kind-aggregation[data-v-6381bbdd]{background:var(--indigo-100, #e8eaf6);color:var(--indigo-600, #3949ab)}.tql-completion-icon.tql-completion-kind-logicalOp[data-v-6381bbdd]{background:var(--yellow-100, #fffde7);color:var(--yellow-700, #fbc02d)}.tql-completion-icon.tql-completion-kind-typeHint[data-v-6381bbdd]{background:var(--teal-100, #e0f2f1);color:var(--teal-600, #00897b)}.tql-completion-icon.tql-completion-kind-visualization[data-v-6381bbdd]{background:var(--red-100, #ffebee);color:var(--red-600, #e53935)}.tql-completion-content[data-v-6381bbdd]{flex:1;display:flex;flex-direction:column;min-width:0}.tql-completion-label[data-v-6381bbdd]{font-family:Courier New,monospace;font-size:.875rem;font-weight:500;color:var(--text-color, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tql-completion-detail[data-v-6381bbdd]{font-size:.75rem;color:var(--text-color-secondary, #666);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tql-completion-kind-badge[data-v-6381bbdd]{font-size:.625rem;padding:.125rem .375rem;background:var(--surface-100, #f5f5f5);border-radius:3px;color:var(--text-color-secondary, #666);text-transform:uppercase;letter-spacing:.025em}.tql-completion-docs[data-v-6381bbdd]{padding:.5rem .75rem;border-top:1px solid var(--surface-border, #ddd);background:var(--surface-50, #fafafa);font-size:.75rem;color:var(--text-color-secondary, #666);max-height:60px;overflow-y:auto}.tql-input-wrapper[data-v-c0e226bb]{position:relative;display:flex;align-items:flex-start;border:1px solid var(--surface-border, #ddd);border-radius:var(--border-radius, 6px);background:var(--surface-ground, #fff);transition:border-color .2s,box-shadow .2s}.tql-input-wrapper.tql-input-focused[data-v-c0e226bb]{border-color:var(--primary-color, #3b82f6);box-shadow:0 0 0 2px var(--primary-100, rgba(59, 130, 246, .2))}.tql-input-wrapper.tql-input-invalid[data-v-c0e226bb]{border-color:var(--red-500, #ef4444)}.tql-input-wrapper.tql-input-invalid.tql-input-focused[data-v-c0e226bb]{box-shadow:0 0 0 2px var(--red-100, rgba(239, 68, 68, .2))}.tql-input-wrapper.tql-input-disabled[data-v-c0e226bb]{opacity:.6;cursor:not-allowed}.tql-highlight-layer[data-v-c0e226bb]{position:absolute;top:0;left:0;right:0;bottom:0;padding:.5rem .75rem;pointer-events:none;white-space:pre-wrap;word-wrap:break-word;font-family:Courier New,monospace;font-size:.875rem;line-height:1.5;overflow:hidden}.tql-input-multiline .tql-highlight-layer[data-v-c0e226bb]{overflow-y:auto}.tql-input[data-v-c0e226bb]{flex:1;width:100%;padding:.5rem 2.5rem .5rem .75rem;border:none;background:transparent;font-family:Courier New,monospace;font-size:.875rem;line-height:1.5;color:var(--text-color, #333);outline:none;resize:none}.tql-input.tql-input-highlighted[data-v-c0e226bb]{color:transparent;caret-color:var(--text-color, #333)}.tql-input[data-v-c0e226bb]::placeholder{color:var(--text-color-secondary, #666);opacity:.7}.tql-input[data-v-c0e226bb]:disabled{cursor:not-allowed}.tql-token-field[data-v-c0e226bb]{color:var(--tql-field-color, var(--blue-600, #2563eb))}.tql-token-operator[data-v-c0e226bb]{color:var(--tql-operator-color, var(--pink-600, #db2777));font-weight:500}.tql-token-logicalOp[data-v-c0e226bb]{color:var(--tql-logical-color, var(--purple-600, #9333ea));font-weight:600}.tql-token-collectionOp[data-v-c0e226bb]{color:var(--tql-collection-color, var(--indigo-600, #4f46e5));font-weight:600}.tql-token-string[data-v-c0e226bb]{color:var(--tql-string-color, var(--green-600, #16a34a))}.tql-token-number[data-v-c0e226bb]{color:var(--tql-number-color, var(--orange-600, #ea580c))}.tql-token-boolean[data-v-c0e226bb]{color:var(--tql-boolean-color, var(--cyan-600, #0891b2))}.tql-token-null[data-v-c0e226bb]{color:var(--tql-null-color, var(--gray-500, #6b7280));font-style:italic}.tql-token-mutator[data-v-c0e226bb]{color:var(--tql-mutator-color, var(--teal-600, #0d9488));font-style:italic}.tql-token-aggregation[data-v-c0e226bb]{color:var(--tql-aggregation-color, var(--indigo-600, #4f46e5))}.tql-token-keyword[data-v-c0e226bb]{color:var(--tql-keyword-color, var(--purple-500, #a855f7))}.tql-token-typeHint[data-v-c0e226bb]{color:var(--tql-typehint-color, var(--teal-500, #14b8a6))}.tql-token-visualization[data-v-c0e226bb]{color:var(--tql-viz-color, var(--red-500, #ef4444))}.tql-token-arrow[data-v-c0e226bb]{color:var(--tql-arrow-color, var(--gray-600, #4b5563));font-weight:600}.tql-token-doubleColon[data-v-c0e226bb]{color:var(--tql-colon-color, var(--gray-500, #6b7280))}.tql-token-paren[data-v-c0e226bb],.tql-token-bracket[data-v-c0e226bb]{color:var(--tql-bracket-color, var(--gray-600, #4b5563))}.tql-token-error[data-v-c0e226bb]{color:var(--tql-error-color, var(--red-600, #dc2626));text-decoration:wavy underline;text-decoration-color:var(--red-400, #f87171)}.tql-token-error-range[data-v-c0e226bb]{background-color:var(--red-50, #fef2f2)}.tql-token-unknown[data-v-c0e226bb]{color:var(--text-color-secondary, #666)}.tql-validation-icon[data-v-c0e226bb]{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);display:flex;align-items:center;justify-content:center}.tql-input-multiline .tql-validation-icon[data-v-c0e226bb]{top:.75rem;transform:none}.tql-icon-valid[data-v-c0e226bb]{color:var(--green-500, #22c55e)}.tql-icon-invalid[data-v-c0e226bb]{color:var(--red-500, #ef4444)}.tql-icon-clickable[data-v-c0e226bb]{cursor:pointer;transition:transform .2s}.tql-icon-clickable[data-v-c0e226bb]:hover{transform:scale(1.2)}.tql-icon-clickable[data-v-c0e226bb]:focus{outline:2px solid var(--primary-color, #3b82f6);outline-offset:2px;border-radius:50%}.tql-snippet-button[data-v-c0e226bb]{position:absolute;right:2rem;top:50%;transform:translateY(-50%);padding:.25rem;border:none;background:transparent;color:var(--text-color-secondary, #666);cursor:pointer;border-radius:var(--border-radius, 6px);transition:color .2s,background-color .2s}.tql-snippet-button[data-v-c0e226bb]:hover{color:var(--primary-color, #3b82f6);background:var(--surface-100, #f5f5f5)}.tql-input-multiline .tql-snippet-button[data-v-c0e226bb]{top:.75rem;transform:none}.tql-validation-messages[data-v-c0e226bb]{position:absolute;top:100%;left:0;right:0;margin-top:.25rem;background:var(--surface-overlay, #fff);border:1px solid var(--red-200, #fecaca);border-radius:var(--border-radius, 6px);padding:.5rem;z-index:10;box-shadow:0 2px 8px #0000001a}.tql-error-message[data-v-c0e226bb]{display:flex;align-items:flex-start;gap:.5rem;padding:.25rem 0;font-size:.75rem;color:var(--red-600, #dc2626)}.tql-error-message i[data-v-c0e226bb]{margin-top:.125rem;font-size:.75rem}.tql-error-suggestion[data-v-c0e226bb]{display:block;color:var(--text-color-secondary, #666);font-style:italic;margin-left:1.25rem}
|