@allurereport/aql 3.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/README.md +482 -0
- package/dist/errors/index.d.ts +105 -0
- package/dist/errors/index.js +165 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/filter/index.d.ts +43 -0
- package/dist/filter/index.js +335 -0
- package/dist/filter/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +192 -0
- package/dist/model.js +45 -0
- package/dist/model.js.map +1 -0
- package/dist/parser/index.d.ts +120 -0
- package/dist/parser/index.js +497 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/tokenizer/index.d.ts +89 -0
- package/dist/tokenizer/index.js +416 -0
- package/dist/tokenizer/index.js.map +1 -0
- package/dist/utils/index.d.ts +56 -0
- package/dist/utils/index.js +139 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# Allure Query Language for TypeScript
|
|
2
|
+
|
|
3
|
+
[<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
|
|
4
|
+
|
|
5
|
+
- Learn more about Allure Report at https://allurereport.org
|
|
6
|
+
- π [Documentation](https://allurereport.org/docs/) β discover official documentation for Allure Report
|
|
7
|
+
- β [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) β get help from the team and community
|
|
8
|
+
- π’ [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) β be in touch with the latest updates
|
|
9
|
+
- π¬ [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) β engage in casual conversations, share insights and ideas with the community
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What is AQL?
|
|
14
|
+
|
|
15
|
+
Allure Query Language (AQL) is a domain-specific language designed for querying and filtering objects. It provides a simple, SQL-like syntax for expressing complex filtering conditions.
|
|
16
|
+
|
|
17
|
+
**Key characteristics:**
|
|
18
|
+
|
|
19
|
+
- **Simple syntax** - Easy to read and write, similar to SQL WHERE clauses
|
|
20
|
+
- **Type-safe** - Full TypeScript support with typed AST nodes
|
|
21
|
+
- **Extensible** - Support for custom functions and context values
|
|
22
|
+
- **Compatible** - Fully compatible with Allure TestOps Java implementation
|
|
23
|
+
|
|
24
|
+
**Example AQL expressions:**
|
|
25
|
+
|
|
26
|
+
- `'status = "passed"'` - Simple equality check
|
|
27
|
+
- `'status = "passed" AND duration < 100'` - Multiple conditions
|
|
28
|
+
- `'status IN ["passed", "failed"]'` - Array membership
|
|
29
|
+
- `'cf["Priority"] = "High"'` - Nested property access
|
|
30
|
+
|
|
31
|
+
## Overview
|
|
32
|
+
|
|
33
|
+
This package provides a TypeScript parser that converts AQL expressions into an Abstract Syntax Tree (AST), enabling programmatic filtering and validation of test data. The parser is fully compatible with the Allure TestOps implementation and supports all standard AQL features including operations, logical operators, parentheses, and context functions.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
Use your favorite package manager to install the package:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
npm add @allurereport/aql
|
|
41
|
+
yarn add @allurereport/aql
|
|
42
|
+
pnpm add @allurereport/aql
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- β
**Full AQL expression parsing** - Parse any valid AQL expression into an AST
|
|
48
|
+
- β
**All comparison operations** - Support for `>`, `>=`, `<`, `<=`, `=`, `!=`, `~=`, `IN`
|
|
49
|
+
- Example: `'status = "passed" AND age > 25'`
|
|
50
|
+
- β
**Logical operators** - Complete support for `AND`, `OR`, `NOT`
|
|
51
|
+
- Example: `'(status = "passed" OR status = "failed") AND name ~= "test"'`
|
|
52
|
+
- β
**Parentheses for grouping** - Control operator precedence with parentheses
|
|
53
|
+
- Example: `'(a = 1 OR b = 2) AND c = 3'`
|
|
54
|
+
- β
**Array/object access** - Access nested properties via `identifier[key]`
|
|
55
|
+
- Example: `'cf["Custom Field"] = "value"'`
|
|
56
|
+
- β
**Context functions** - Support for dynamic values like `now()`, `currentUser()`
|
|
57
|
+
- Example: `"createdDate >= now()"`
|
|
58
|
+
- β
**Type-safe validation** - Typed errors with detailed information for localization
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
### Basic example
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { parseAql } from "@allurereport/aql";
|
|
66
|
+
|
|
67
|
+
// Parse a simple AQL expression
|
|
68
|
+
const result = parseAql('status = "passed"');
|
|
69
|
+
|
|
70
|
+
// result.expression contains the parsed AST
|
|
71
|
+
console.log(result.expression);
|
|
72
|
+
// {
|
|
73
|
+
// type: "condition",
|
|
74
|
+
// left: { identifier: "status" },
|
|
75
|
+
// operator: "EQ",
|
|
76
|
+
// right: { value: "passed", type: "STRING" }
|
|
77
|
+
// }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### With context
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { parseAql } from "@allurereport/aql";
|
|
84
|
+
|
|
85
|
+
// Provide context for function calls like now() or currentUser()
|
|
86
|
+
const context = {
|
|
87
|
+
"now()": Date.now(), // Current timestamp
|
|
88
|
+
"currentUser()": "admin", // Current user identifier
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Functions in AQL will be resolved using the context
|
|
92
|
+
const result = parseAql("createdDate >= now()", context);
|
|
93
|
+
// The parser replaces now() with the value from context
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### With configuration
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { parseAql } from "@allurereport/aql";
|
|
100
|
+
|
|
101
|
+
// Restrict available features for security or validation
|
|
102
|
+
const config = {
|
|
103
|
+
operations: ["EQ", "NEQ"], // Only allow equality checks
|
|
104
|
+
identifiers: ["status", "name"], // Only allow specific fields
|
|
105
|
+
logicalOperators: ["AND"], // Only allow AND operator
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// This will succeed
|
|
109
|
+
const result = parseAql('status = "passed" AND name = "test"', undefined, config);
|
|
110
|
+
|
|
111
|
+
// This will throw an error (OR is not allowed)
|
|
112
|
+
// parseAql('status = "passed" OR name = "test"', undefined, config);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Validation
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { isAqlError, parseAql } from "@allurereport/aql";
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const result = parseAql('status = "passed"');
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (isAqlError(error)) {
|
|
124
|
+
console.error("Error code:", error.code);
|
|
125
|
+
console.error("Error message:", error.message);
|
|
126
|
+
console.error("Error details:", error.details);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Supported Operations
|
|
132
|
+
|
|
133
|
+
- `>` - greater than (e.g., `age > 25`)
|
|
134
|
+
- `>=` - greater than or equal (e.g., `score >= 80`)
|
|
135
|
+
- `<` - less than (e.g., `duration < 100`)
|
|
136
|
+
- `<=` - less than or equal (e.g., `price <= 1000`)
|
|
137
|
+
- `=` or `is` - equal (e.g., `status = "passed"` or `status is "passed"`)
|
|
138
|
+
- `!=` - not equal (e.g., `status != "broken"`)
|
|
139
|
+
- `~=` - contains (substring match, e.g., `name ~= "test"`)
|
|
140
|
+
- `IN` - in array (e.g., `status IN ["passed", "failed"]`)
|
|
141
|
+
|
|
142
|
+
## AQL Expression Examples
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Simple condition - check if status equals "passed"
|
|
146
|
+
'status = "passed"';
|
|
147
|
+
|
|
148
|
+
// Logical operators - combine multiple conditions
|
|
149
|
+
'status = "passed" AND name ~= "test"';
|
|
150
|
+
|
|
151
|
+
// Parentheses - control operator precedence
|
|
152
|
+
// This means: (status is passed OR failed) AND name contains "test"
|
|
153
|
+
'(status = "passed" OR status = "failed") AND name ~= "test"';
|
|
154
|
+
|
|
155
|
+
// Comparison operations - numeric comparisons
|
|
156
|
+
"createdDate >= 1234567890";
|
|
157
|
+
|
|
158
|
+
// Array condition - check if value is in a list
|
|
159
|
+
'status IN ["passed", "failed", "broken"]';
|
|
160
|
+
|
|
161
|
+
// Element access - access nested properties or array elements
|
|
162
|
+
'cf["Custom Field"] = "value"';
|
|
163
|
+
|
|
164
|
+
// NOT operator - negate a condition
|
|
165
|
+
'NOT status = "passed"';
|
|
166
|
+
|
|
167
|
+
// Functions - use dynamic values from context
|
|
168
|
+
"createdDate >= now()";
|
|
169
|
+
|
|
170
|
+
// Boolean value - standalone boolean expression
|
|
171
|
+
"true";
|
|
172
|
+
|
|
173
|
+
// NULL values - check for null or empty values
|
|
174
|
+
"status = null";
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## AST Structure
|
|
178
|
+
|
|
179
|
+
The parser returns an AST (Abstract Syntax Tree) with the following structure:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
type AqlExpression =
|
|
183
|
+
| AqlConditionExpression // condition: left operator right
|
|
184
|
+
| AqlArrayConditionExpression // array condition: left IN [values]
|
|
185
|
+
| AqlBinaryExpression // binary operation: left AND/OR right
|
|
186
|
+
| AqlNotExpression // negation: NOT expression
|
|
187
|
+
| AqlParenExpression // parentheses: (expression)
|
|
188
|
+
| AqlBooleanExpression; // boolean value: true/false
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Each expression node contains type information and the necessary data to evaluate or transform the query. The AST can be used for:
|
|
192
|
+
|
|
193
|
+
- **Filtering** - Evaluate expressions against objects
|
|
194
|
+
- **Validation** - Check if expressions are valid
|
|
195
|
+
- **Transformation** - Convert to other query languages
|
|
196
|
+
- **Analysis** - Extract identifiers, operations, and values
|
|
197
|
+
|
|
198
|
+
## API
|
|
199
|
+
|
|
200
|
+
### `parseAql(aql: string, context?: Map | Record, config?: AqlParserConfig): AqlParseResult`
|
|
201
|
+
|
|
202
|
+
Parses an AQL string and returns an AST (Abstract Syntax Tree).
|
|
203
|
+
|
|
204
|
+
**Parameters:**
|
|
205
|
+
|
|
206
|
+
- `aql` - AQL string to parse (e.g., `'status = "passed"'`)
|
|
207
|
+
- `context` - optional context with functions (Map or object), e.g., `{ "now()": Date.now() }`
|
|
208
|
+
- `config` - optional parser configuration to restrict available features
|
|
209
|
+
|
|
210
|
+
**Returns:**
|
|
211
|
+
|
|
212
|
+
- `AqlParseResult` object with `expression` field:
|
|
213
|
+
```typescript
|
|
214
|
+
{
|
|
215
|
+
expression: AqlExpression | null; // null for empty strings
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Example return value:**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
const result = parseAql('status = "passed" AND age > 25');
|
|
223
|
+
// result.expression = {
|
|
224
|
+
// type: "binary",
|
|
225
|
+
// operator: "AND",
|
|
226
|
+
// left: {
|
|
227
|
+
// type: "condition",
|
|
228
|
+
// left: { identifier: "status" },
|
|
229
|
+
// operator: "EQ",
|
|
230
|
+
// right: { value: "passed", type: "STRING" }
|
|
231
|
+
// },
|
|
232
|
+
// right: {
|
|
233
|
+
// type: "condition",
|
|
234
|
+
// left: { identifier: "age" },
|
|
235
|
+
// operator: "GT",
|
|
236
|
+
// right: { value: "25", type: "NUMBER" }
|
|
237
|
+
// }
|
|
238
|
+
// }
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Throws:**
|
|
242
|
+
|
|
243
|
+
- `AqlParserError` if the AQL string is invalid or uses forbidden features
|
|
244
|
+
|
|
245
|
+
### `includesAll(aql: string | null | undefined): boolean`
|
|
246
|
+
|
|
247
|
+
Checks if AQL includes all records (empty string or "true").
|
|
248
|
+
|
|
249
|
+
## Parser Configuration
|
|
250
|
+
|
|
251
|
+
You can restrict available features in the parser using `AqlParserConfig`:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { parseAql } from "@allurereport/aql";
|
|
255
|
+
|
|
256
|
+
const config = {
|
|
257
|
+
// Allow only specific operations
|
|
258
|
+
operations: ["EQ", "NEQ"],
|
|
259
|
+
|
|
260
|
+
// Allow only specific logical operators
|
|
261
|
+
logicalOperators: ["AND", "OR"],
|
|
262
|
+
|
|
263
|
+
// Allow only specific identifiers
|
|
264
|
+
identifiers: ["status", "name", "age"],
|
|
265
|
+
|
|
266
|
+
// Or use a validation function
|
|
267
|
+
identifiers: (id: string) => id.startsWith("custom_"),
|
|
268
|
+
|
|
269
|
+
// Allow only specific value types
|
|
270
|
+
valueTypes: ["STRING", "NUMBER"],
|
|
271
|
+
|
|
272
|
+
// Disable parentheses
|
|
273
|
+
parentheses: false,
|
|
274
|
+
|
|
275
|
+
// Disable bracket access (identifier[key])
|
|
276
|
+
indexAccess: false,
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const result = parseAql('status = "passed"', undefined, config);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Configuration Options
|
|
283
|
+
|
|
284
|
+
- `operations?: AqlOperations[]` - Allowed operations (GT, GE, LT, LE, EQ, NEQ, CONTAINS, IN)
|
|
285
|
+
- `logicalOperators?: AqlLogicalOperators[]` - Allowed logical operators (AND, OR, NOT)
|
|
286
|
+
- `identifiers?: string[] | ((identifier: string) => boolean)` - Allowed identifiers (array or validation function)
|
|
287
|
+
- `valueTypes?: AqlValueKind[]` - Allowed value types (NULL, BOOLEAN, NUMBER, STRING, FUNCTION)
|
|
288
|
+
- `parentheses?: boolean` - Whether parentheses are allowed (default: `true`)
|
|
289
|
+
- `indexAccess?: boolean` - Whether bracket access is allowed (default: `true`)
|
|
290
|
+
|
|
291
|
+
If a configuration option is not specified, all features are available.
|
|
292
|
+
|
|
293
|
+
## Filtering Objects
|
|
294
|
+
|
|
295
|
+
You can filter arrays of objects using AQL expressions. This is useful for filtering test results, user data, or any structured objects:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { filterByAql } from "@allurereport/aql";
|
|
299
|
+
|
|
300
|
+
// Example: Filter test results
|
|
301
|
+
const testResults = [
|
|
302
|
+
{ id: 1, name: "Login test", status: "passed", duration: 150, tags: ["smoke"] },
|
|
303
|
+
{ id: 2, name: "Logout test", status: "failed", duration: 200, tags: ["regression"] },
|
|
304
|
+
{ id: 3, name: "API test", status: "passed", duration: 100, tags: ["smoke", "api"] },
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
// Filter by simple condition - get all passed tests
|
|
308
|
+
const passedTests = filterByAql(testResults, 'status = "passed"');
|
|
309
|
+
// Returns: [{ id: 1, ... }, { id: 3, ... }]
|
|
310
|
+
|
|
311
|
+
// Filter with AND - passed tests with duration less than 150ms
|
|
312
|
+
const fastPassedTests = filterByAql(testResults, 'status = "passed" AND duration < 150');
|
|
313
|
+
// Returns: [{ id: 3, ... }]
|
|
314
|
+
|
|
315
|
+
// Filter with OR - get passed or failed tests (exclude broken)
|
|
316
|
+
const activeTests = filterByAql(testResults, 'status = "passed" OR status = "failed"');
|
|
317
|
+
// Returns: all items
|
|
318
|
+
|
|
319
|
+
// Filter with IN - get tests with specific statuses
|
|
320
|
+
const relevantTests = filterByAql(testResults, 'status IN ["passed", "failed"]');
|
|
321
|
+
// Returns: all items
|
|
322
|
+
|
|
323
|
+
// Filter with nested properties - access custom fields
|
|
324
|
+
const itemsWithCustomFields = [
|
|
325
|
+
{ id: 1, cf: { Priority: "High", Component: "Auth" } },
|
|
326
|
+
{ id: 2, cf: { Priority: "Low", Component: "UI" } },
|
|
327
|
+
];
|
|
328
|
+
const highPriorityAuth = filterByAql(itemsWithCustomFields, 'cf["Priority"] = "High" AND cf["Component"] = "Auth"');
|
|
329
|
+
// Returns: [{ id: 1, ... }]
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Filter API
|
|
333
|
+
|
|
334
|
+
#### `filterByAql<T>(items: T[], aql: string, context?: Map | Record, config?: AqlParserConfig): T[]`
|
|
335
|
+
|
|
336
|
+
Filters an array of objects based on an AQL expression string.
|
|
337
|
+
|
|
338
|
+
**Parameters:**
|
|
339
|
+
|
|
340
|
+
- `items` - array of objects to filter
|
|
341
|
+
- `aql` - AQL expression string
|
|
342
|
+
- `context` - optional context with functions
|
|
343
|
+
- `config` - optional parser configuration to restrict available features
|
|
344
|
+
|
|
345
|
+
**Returns:**
|
|
346
|
+
|
|
347
|
+
- Filtered array of objects
|
|
348
|
+
|
|
349
|
+
#### `filterByAql<T>(items: T[], expression: AqlExpression): T[]`
|
|
350
|
+
|
|
351
|
+
Filters an array of objects using a pre-parsed AQL expression. Useful when you need to filter multiple arrays with the same expression.
|
|
352
|
+
|
|
353
|
+
**Parameters:**
|
|
354
|
+
|
|
355
|
+
- `items` - array of objects to filter
|
|
356
|
+
- `expression` - parsed AQL expression (from `parseAql()`)
|
|
357
|
+
|
|
358
|
+
**Returns:**
|
|
359
|
+
|
|
360
|
+
- Filtered array of objects
|
|
361
|
+
|
|
362
|
+
**Example:**
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// Parse once
|
|
366
|
+
const parseResult = parseAql('status = "passed"');
|
|
367
|
+
if (parseResult.expression) {
|
|
368
|
+
// Use multiple times
|
|
369
|
+
const filtered1 = filterByAql(items1, parseResult.expression);
|
|
370
|
+
const filtered2 = filterByAql(items2, parseResult.expression);
|
|
371
|
+
const filtered3 = filterByAql(items3, parseResult.expression);
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Error Handling
|
|
376
|
+
|
|
377
|
+
AQL parser uses typed error classes for better error handling and localization support. All errors include position information and detailed context.
|
|
378
|
+
|
|
379
|
+
### Error Types
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
import { AqlError, AqlErrorCode, isAqlError } from "@allurereport/aql";
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
parseAql("invalid aql");
|
|
386
|
+
} catch (error) {
|
|
387
|
+
if (isAqlError(error)) {
|
|
388
|
+
console.log("Error code:", error.code);
|
|
389
|
+
// Example: "EXPECTED_TOKEN"
|
|
390
|
+
|
|
391
|
+
console.log("Error message:", error.message);
|
|
392
|
+
// Example: "Expected '=' at position 7"
|
|
393
|
+
|
|
394
|
+
console.log("Error details:", error.fullDetails);
|
|
395
|
+
// Example: { expected: "=", actual: "!", position: 7, context: "status !" }
|
|
396
|
+
|
|
397
|
+
// Use error.code for translation keys in your UI
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Common Error Examples
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
// Syntax error - unexpected character
|
|
406
|
+
try {
|
|
407
|
+
parseAql('status @ "passed"');
|
|
408
|
+
} catch (error) {
|
|
409
|
+
// error.code = "UNEXPECTED_CHARACTER"
|
|
410
|
+
// error.message = "Unexpected character '@' at position 7"
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Unterminated string
|
|
414
|
+
try {
|
|
415
|
+
parseAql('status = "passed');
|
|
416
|
+
} catch (error) {
|
|
417
|
+
// error.code = "UNTERMINATED_STRING"
|
|
418
|
+
// error.message = "Unterminated string at position 7"
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Expected token
|
|
422
|
+
try {
|
|
423
|
+
parseAql("status =");
|
|
424
|
+
} catch (error) {
|
|
425
|
+
// error.code = "EXPECTED_TOKEN"
|
|
426
|
+
// error.message = "Expected value at position 9"
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Forbidden operation (with config)
|
|
430
|
+
try {
|
|
431
|
+
const config = { operations: ["EQ"] };
|
|
432
|
+
parseAql('status > "passed"', undefined, config);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
// error.code = "FORBIDDEN_OPERATION"
|
|
435
|
+
// error.message = "Operation 'GT' is not allowed at position 7"
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Error Codes
|
|
440
|
+
|
|
441
|
+
- `UNEXPECTED_CHARACTER` - Unexpected character in input
|
|
442
|
+
- `UNTERMINATED_STRING` - String literal not properly closed
|
|
443
|
+
- `INVALID_UNICODE_ESCAPE` - Invalid Unicode escape sequence
|
|
444
|
+
- `EXPECTED_TOKEN` - Expected specific token
|
|
445
|
+
- `EXPECTED_OPERATION` - Expected operation
|
|
446
|
+
- `EXPECTED_VALUE` - Expected value
|
|
447
|
+
- `EXPECTED_ACCESSOR` - Expected accessor
|
|
448
|
+
- `INVALID_INPUT` - Invalid input
|
|
449
|
+
- `INVALID_SYNTAX` - Invalid syntax
|
|
450
|
+
|
|
451
|
+
### Error Classes
|
|
452
|
+
|
|
453
|
+
- `AqlError` - Base error class
|
|
454
|
+
- `AqlTokenizerError` - Tokenizer-specific errors
|
|
455
|
+
- `AqlParserError` - Parser-specific errors
|
|
456
|
+
|
|
457
|
+
### Localization Example
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
import { AqlError, AqlErrorCode } from "@allurereport/aql";
|
|
461
|
+
|
|
462
|
+
function translateError(error: AqlError, locale: string): string {
|
|
463
|
+
const translations = {
|
|
464
|
+
en: {
|
|
465
|
+
[AqlErrorCode.EXPECTED_TOKEN]: "Expected {expected} at position {position}",
|
|
466
|
+
// ... more translations
|
|
467
|
+
},
|
|
468
|
+
es: {
|
|
469
|
+
[AqlErrorCode.EXPECTED_TOKEN]: "Se esperaba {expected} en la posiciΓ³n {position}",
|
|
470
|
+
// ... more translations
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const template = translations[locale]?.[error.code];
|
|
475
|
+
const details = error.fullDetails;
|
|
476
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => details[key]?.toString() || "");
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Compatibility
|
|
481
|
+
|
|
482
|
+
The parser is compatible with the Java implementation in `allure-query-language` and uses the same ANTLR grammar.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AQL error types and classes
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extend ErrorConstructor to include captureStackTrace (V8/Node.js specific)
|
|
6
|
+
*/
|
|
7
|
+
declare global {
|
|
8
|
+
interface ErrorConstructor {
|
|
9
|
+
captureStackTrace?(error: Error, constructorOpt?: Function): void;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare enum AqlErrorCode {
|
|
13
|
+
/** Tokenizer errors */
|
|
14
|
+
UNEXPECTED_CHARACTER = "UNEXPECTED_CHARACTER",
|
|
15
|
+
UNTERMINATED_STRING = "UNTERMINATED_STRING",
|
|
16
|
+
INVALID_UNICODE_ESCAPE = "INVALID_UNICODE_ESCAPE",
|
|
17
|
+
/** Parser errors */
|
|
18
|
+
EXPECTED_TOKEN = "EXPECTED_TOKEN",
|
|
19
|
+
EXPECTED_OPERATION = "EXPECTED_OPERATION",
|
|
20
|
+
EXPECTED_VALUE = "EXPECTED_VALUE",
|
|
21
|
+
EXPECTED_ACCESSOR = "EXPECTED_ACCESSOR",
|
|
22
|
+
INVALID_SYNTAX = "INVALID_SYNTAX",
|
|
23
|
+
INVALID_INPUT = "INVALID_INPUT",
|
|
24
|
+
INVALID_IDENTIFIER = "INVALID_IDENTIFIER",
|
|
25
|
+
/** Configuration errors */
|
|
26
|
+
FORBIDDEN_LOGICAL_OPERATOR = "FORBIDDEN_LOGICAL_OPERATOR",
|
|
27
|
+
FORBIDDEN_OPERATION = "FORBIDDEN_OPERATION",
|
|
28
|
+
FORBIDDEN_ARRAY_OPERATION = "FORBIDDEN_ARRAY_OPERATION",
|
|
29
|
+
FORBIDDEN_IDENTIFIER = "FORBIDDEN_IDENTIFIER",
|
|
30
|
+
FORBIDDEN_VALUE_TYPE = "FORBIDDEN_VALUE_TYPE",
|
|
31
|
+
FORBIDDEN_PARENTHESES = "FORBIDDEN_PARENTHESES",
|
|
32
|
+
FORBIDDEN_BRACKET_ACCESS = "FORBIDDEN_BRACKET_ACCESS"
|
|
33
|
+
}
|
|
34
|
+
export interface AqlErrorDetails {
|
|
35
|
+
position?: number;
|
|
36
|
+
expected?: string;
|
|
37
|
+
got?: string;
|
|
38
|
+
context?: string;
|
|
39
|
+
character?: string;
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Base error class for AQL errors
|
|
44
|
+
*/
|
|
45
|
+
export declare class AqlError extends Error {
|
|
46
|
+
readonly code: AqlErrorCode;
|
|
47
|
+
readonly details: AqlErrorDetails;
|
|
48
|
+
constructor(code: AqlErrorCode, message: string, details?: AqlErrorDetails);
|
|
49
|
+
/**
|
|
50
|
+
* Gets error details for translation/localization
|
|
51
|
+
* Includes error code and all context information
|
|
52
|
+
*/
|
|
53
|
+
get fullDetails(): AqlErrorDetails & {
|
|
54
|
+
code: AqlErrorCode;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Gets error code for translation key generation
|
|
58
|
+
*/
|
|
59
|
+
get translationKey(): string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Tokenizer error
|
|
63
|
+
*/
|
|
64
|
+
export declare class AqlTokenizerError extends AqlError {
|
|
65
|
+
constructor(code: AqlErrorCode, message: string, details?: AqlErrorDetails);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parser error
|
|
69
|
+
*/
|
|
70
|
+
export declare class AqlParserError extends AqlError {
|
|
71
|
+
constructor(code: AqlErrorCode, message: string, details?: AqlErrorDetails);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Helper functions to create specific errors
|
|
75
|
+
*/
|
|
76
|
+
export declare const AqlErrors: {
|
|
77
|
+
unexpectedCharacter: (character: string, position: number) => AqlTokenizerError;
|
|
78
|
+
unterminatedString: (position: number) => AqlTokenizerError;
|
|
79
|
+
invalidUnicodeEscape: (position: number) => AqlTokenizerError;
|
|
80
|
+
expectedToken: (expected: string, got: string, position: number, context?: string) => AqlParserError;
|
|
81
|
+
expectedOperation: (position: number) => AqlParserError;
|
|
82
|
+
expectedValue: (position: number) => AqlParserError;
|
|
83
|
+
expectedAccessor: (position: number, expected?: string) => AqlParserError;
|
|
84
|
+
invalidInput: (reason: string) => AqlParserError;
|
|
85
|
+
invalidIdentifier: (identifier: string, position: number) => AqlParserError;
|
|
86
|
+
forbiddenLogicalOperator: (operator: string, position: number) => AqlParserError;
|
|
87
|
+
forbiddenOperation: (operation: string, position: number) => AqlParserError;
|
|
88
|
+
forbiddenArrayOperation: (operation: string, position: number) => AqlParserError;
|
|
89
|
+
forbiddenIdentifier: (identifier: string, position: number) => AqlParserError;
|
|
90
|
+
forbiddenValueType: (valueType: string, position: number) => AqlParserError;
|
|
91
|
+
forbiddenParentheses: (position: number) => AqlParserError;
|
|
92
|
+
forbiddenBracketAccess: (position: number) => AqlParserError;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Type guard to check if error is AqlError
|
|
96
|
+
*/
|
|
97
|
+
export declare function isAqlError(error: unknown): error is AqlError;
|
|
98
|
+
/**
|
|
99
|
+
* Type guard to check if error is AqlTokenizerError
|
|
100
|
+
*/
|
|
101
|
+
export declare function isAqlTokenizerError(error: unknown): error is AqlTokenizerError;
|
|
102
|
+
/**
|
|
103
|
+
* Type guard to check if error is AqlParserError
|
|
104
|
+
*/
|
|
105
|
+
export declare function isAqlParserError(error: unknown): error is AqlParserError;
|