flowquery 1.0.13 → 1.0.15

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 (61) hide show
  1. package/.editorconfig +21 -0
  2. package/.husky/pre-commit +1 -0
  3. package/.prettierrc +22 -0
  4. package/dist/flowquery.min.js +1 -1
  5. package/dist/parsing/expressions/expression_map.d.ts +8 -0
  6. package/dist/parsing/expressions/expression_map.d.ts.map +1 -0
  7. package/dist/parsing/expressions/expression_map.js +21 -0
  8. package/dist/parsing/expressions/expression_map.js.map +1 -0
  9. package/dist/parsing/functions/async_function.d.ts +16 -2
  10. package/dist/parsing/functions/async_function.d.ts.map +1 -1
  11. package/dist/parsing/functions/async_function.js +15 -1
  12. package/dist/parsing/functions/async_function.js.map +1 -1
  13. package/dist/parsing/operations/call.d.ts +17 -0
  14. package/dist/parsing/operations/call.d.ts.map +1 -0
  15. package/dist/parsing/operations/call.js +103 -0
  16. package/dist/parsing/operations/call.js.map +1 -0
  17. package/dist/parsing/operations/load.d.ts +7 -6
  18. package/dist/parsing/operations/load.d.ts.map +1 -1
  19. package/dist/parsing/operations/load.js +11 -7
  20. package/dist/parsing/operations/load.js.map +1 -1
  21. package/dist/parsing/operations/operation.d.ts +1 -0
  22. package/dist/parsing/operations/operation.d.ts.map +1 -1
  23. package/dist/parsing/operations/operation.js +6 -5
  24. package/dist/parsing/operations/operation.js.map +1 -1
  25. package/dist/parsing/operations/projection.d.ts +1 -1
  26. package/dist/parsing/operations/projection.d.ts.map +1 -1
  27. package/dist/parsing/operations/projection.js.map +1 -1
  28. package/dist/parsing/parser.d.ts +1 -0
  29. package/dist/parsing/parser.d.ts.map +1 -1
  30. package/dist/parsing/parser.js +148 -99
  31. package/dist/parsing/parser.js.map +1 -1
  32. package/dist/parsing/token_to_node.d.ts +2 -2
  33. package/dist/parsing/token_to_node.d.ts.map +1 -1
  34. package/dist/parsing/token_to_node.js +12 -12
  35. package/dist/parsing/token_to_node.js.map +1 -1
  36. package/dist/tokenization/token.d.ts +5 -1
  37. package/dist/tokenization/token.d.ts.map +1 -1
  38. package/dist/tokenization/token.js +17 -5
  39. package/dist/tokenization/token.js.map +1 -1
  40. package/docs/flowquery.min.js +1 -1
  41. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  42. package/misc/apps/RAG/package.json +1 -1
  43. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +4 -4
  44. package/misc/apps/RAG/src/plugins/loaders/Form.ts +3 -3
  45. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +4 -3
  46. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +7 -5
  47. package/misc/apps/RAG/src/plugins/loaders/Table.ts +3 -3
  48. package/misc/apps/RAG/src/plugins/loaders/Weather.ts +4 -3
  49. package/package.json +12 -2
  50. package/src/parsing/expressions/expression_map.ts +19 -0
  51. package/src/parsing/functions/async_function.ts +16 -2
  52. package/src/parsing/operations/call.ts +67 -0
  53. package/src/parsing/operations/load.ts +123 -118
  54. package/src/parsing/operations/operation.ts +14 -13
  55. package/src/parsing/operations/projection.ts +3 -3
  56. package/src/parsing/parser.ts +303 -239
  57. package/src/parsing/token_to_node.ts +67 -50
  58. package/src/tokenization/token.ts +29 -14
  59. package/tests/compute/runner.test.ts +277 -165
  60. package/tests/parsing/parser.test.ts +355 -303
  61. package/vscode-settings.json.recommended +16 -0
@@ -1,51 +1,52 @@
1
- import Return from "./operations/return";
2
- import Expression from "./expressions/expression";
1
+ import Token from "../tokenization/token";
2
+ import ObjectUtils from "../utils/object_utils";
3
+ import Alias from "./alias";
4
+ import { AliasOption } from "./alias_option";
3
5
  import ASTNode from "./ast_node";
4
6
  import BaseParser from "./base_parser";
5
- import FunctionFactory from "./functions/function_factory";
6
- import Function from "./functions/function";
7
- import AsyncFunction from "./functions/async_function";
7
+ import From from "./components/from";
8
+ import Headers from "./components/headers";
9
+ import Null from "./components/null";
10
+ import Post from "./components/post";
11
+ import Context from "./context";
8
12
  import AssociativeArray from "./data_structures/associative_array";
9
13
  import JSONArray from "./data_structures/json_array";
10
14
  import KeyValuePair from "./data_structures/key_value_pair";
11
- import With from "./operations/with";
12
- import Unwind from "./operations/unwind";
13
- import Where from "./operations/where";
14
- import { AliasOption } from "./alias_option";
15
- import Load from "./operations/load";
16
- import From from "./components/from";
17
- import Alias from "./alias";
18
- import Headers from "./components/headers";
19
- import Case from "./logic/case";
20
- import When from "./logic/when";
21
- import Else from "./logic/else";
22
- import Then from "./logic/then";
23
15
  import Lookup from "./data_structures/lookup";
16
+ import RangeLookup from "./data_structures/range_lookup";
17
+ import Expression from "./expressions/expression";
18
+ import FString from "./expressions/f_string";
19
+ import Identifier from "./expressions/identifier";
24
20
  import { Not } from "./expressions/operator";
25
21
  import Reference from "./expressions/reference";
26
- import Operation from "./operations/operation";
27
- import Post from './components/post';
28
- import AggregatedReturn from "./operations/aggregated_return";
29
- import Context from "./context";
22
+ import String from "./expressions/string";
30
23
  import AggregateFunction from "./functions/aggregate_function";
31
- import ObjectUtils from "../utils/object_utils";
24
+ import AsyncFunction from "./functions/async_function";
25
+ import Function from "./functions/function";
26
+ import FunctionFactory from "./functions/function_factory";
32
27
  import PredicateFunction from "./functions/predicate_function";
33
- import Token from "../tokenization/token";
34
- import FString from "./expressions/f_string";
35
- import String from "./expressions/string";
28
+ import Case from "./logic/case";
29
+ import Else from "./logic/else";
30
+ import Then from "./logic/then";
31
+ import When from "./logic/when";
32
+ import AggregatedReturn from "./operations/aggregated_return";
36
33
  import AggregatedWith from "./operations/aggregated_with";
37
- import Identifier from "./expressions/identifier";
34
+ import Call from "./operations/call";
38
35
  import Limit from "./operations/limit";
39
- import RangeLookup from "./data_structures/range_lookup";
40
- import Null from "./components/null";
36
+ import Load from "./operations/load";
37
+ import Operation from "./operations/operation";
38
+ import Return from "./operations/return";
39
+ import Unwind from "./operations/unwind";
40
+ import Where from "./operations/where";
41
+ import With from "./operations/with";
41
42
 
42
43
  /**
43
44
  * Main parser for FlowQuery statements.
44
- *
45
+ *
45
46
  * Parses FlowQuery declarative query language statements into an Abstract Syntax Tree (AST).
46
47
  * Supports operations like WITH, UNWIND, RETURN, LOAD, WHERE, and LIMIT, along with
47
48
  * expressions, functions, data structures, and logical constructs.
48
- *
49
+ *
49
50
  * @example
50
51
  * ```typescript
51
52
  * const parser = new Parser();
@@ -59,11 +60,11 @@ class Parser extends BaseParser {
59
60
 
60
61
  /**
61
62
  * Parses a FlowQuery statement into an Abstract Syntax Tree.
62
- *
63
+ *
63
64
  * @param statement - The FlowQuery statement to parse
64
65
  * @returns The root AST node containing the parsed structure
65
66
  * @throws {Error} If the statement is malformed or contains syntax errors
66
- *
67
+ *
67
68
  * @example
68
69
  * ```typescript
69
70
  * const ast = parser.parse("LOAD JSON FROM 'https://api.adviceslip.com/advice' AS data RETURN data");
@@ -74,27 +75,32 @@ class Parser extends BaseParser {
74
75
  const root: ASTNode = new ASTNode();
75
76
  let previous: Operation | null = null;
76
77
  let operation: Operation | null = null;
77
- while(!this.token.isEOF()) {
78
- if(root.childCount() > 0) {
78
+ while (!this.token.isEOF()) {
79
+ if (root.childCount() > 0) {
79
80
  this.expectAndSkipWhitespaceAndComments();
80
81
  } else {
81
82
  this.skipWhitespaceAndComments();
82
83
  }
83
84
  operation = this.parseOperation();
84
- if(operation === null) {
85
- throw new Error('Expected one of WITH, UNWIND, RETURN, or LOAD');
85
+ if (operation === null) {
86
+ throw new Error("Expected one of WITH, UNWIND, RETURN, LOAD, OR CALL");
87
+ }
88
+ if (this._returns > 1) {
89
+ throw new Error("Only one RETURN statement is allowed");
86
90
  }
87
- if(this._returns > 1) {
88
- throw new Error('Only one RETURN statement is allowed');
91
+ if (previous instanceof Call && !previous.hasYield) {
92
+ throw new Error(
93
+ "CALL operations must have a YIELD clause unless they are the last operation"
94
+ );
89
95
  }
90
- if(previous !== null) {
96
+ if (previous !== null) {
91
97
  previous.addSibling(operation);
92
98
  } else {
93
99
  root.addChild(operation);
94
100
  }
95
101
  const where = this.parseWhere();
96
- if(where !== null) {
97
- if(operation instanceof Return) {
102
+ if (where !== null) {
103
+ if (operation instanceof Return) {
98
104
  (operation as Return).where = where;
99
105
  } else {
100
106
  operation.addSibling(where);
@@ -102,14 +108,14 @@ class Parser extends BaseParser {
102
108
  }
103
109
  }
104
110
  const limit = this.parseLimit();
105
- if(limit !== null) {
111
+ if (limit !== null) {
106
112
  operation.addSibling(limit);
107
113
  operation = limit;
108
114
  }
109
115
  previous = operation;
110
116
  }
111
- if(!(operation instanceof Return)) {
112
- throw new Error('Last statement must be a RETURN or a WHERE statement');
117
+ if (!(operation instanceof Return) && !(operation instanceof Call)) {
118
+ throw new Error("Last statement must be a RETURN, WHERE, or a CALL statement");
113
119
  }
114
120
  return root;
115
121
  }
@@ -119,45 +125,54 @@ class Parser extends BaseParser {
119
125
  this.parseWith() ||
120
126
  this.parseUnwind() ||
121
127
  this.parseReturn() ||
122
- this.parseLoad()
128
+ this.parseLoad() ||
129
+ this.parseCall()
123
130
  );
124
131
  }
125
-
132
+
126
133
  private parseWith(): With | null {
127
- if(!this.token.isWith()) {
134
+ if (!this.token.isWith()) {
128
135
  return null;
129
136
  }
130
137
  this.setNextToken();
131
138
  this.expectAndSkipWhitespaceAndComments();
132
139
  const expressions = Array.from(this.parseExpressions(AliasOption.REQUIRED));
133
- if(expressions.length === 0) {
134
- throw new Error('Expected expression');
140
+ if (expressions.length === 0) {
141
+ throw new Error("Expected expression");
135
142
  }
136
- if(expressions.some((expression: Expression) => expression.has_reducers())) {
143
+ if (expressions.some((expression: Expression) => expression.has_reducers())) {
137
144
  return new AggregatedWith(expressions);
138
145
  }
139
146
  return new With(expressions);
140
147
  }
141
148
 
142
149
  private parseUnwind(): Unwind | null {
143
- if(!this.token.isUnwind()) {
150
+ if (!this.token.isUnwind()) {
144
151
  return null;
145
152
  }
146
153
  this.setNextToken();
147
154
  this.expectAndSkipWhitespaceAndComments();
148
155
  const expression: Expression | null = this.parseExpression();
149
- if(expression === null) {
150
- throw new Error('Expected expression');
151
- }
152
- if(!ObjectUtils.isInstanceOfAny(expression.firstChild(), [JSONArray, Function, Reference, Lookup, RangeLookup])) {
153
- throw new Error('Expected array, function, reference, or lookup.');
156
+ if (expression === null) {
157
+ throw new Error("Expected expression");
158
+ }
159
+ if (
160
+ !ObjectUtils.isInstanceOfAny(expression.firstChild(), [
161
+ JSONArray,
162
+ Function,
163
+ Reference,
164
+ Lookup,
165
+ RangeLookup,
166
+ ])
167
+ ) {
168
+ throw new Error("Expected array, function, reference, or lookup.");
154
169
  }
155
170
  this.expectAndSkipWhitespaceAndComments();
156
171
  const alias = this.parseAlias();
157
- if(alias !== null) {
172
+ if (alias !== null) {
158
173
  expression.setAlias(alias.getAlias());
159
174
  } else {
160
- throw new Error('Expected alias');
175
+ throw new Error("Expected alias");
161
176
  }
162
177
  const unwind = new Unwind(expression);
163
178
  this.variables.set(alias.getAlias(), unwind);
@@ -165,16 +180,16 @@ class Parser extends BaseParser {
165
180
  }
166
181
 
167
182
  private parseReturn(): Return | null {
168
- if(!this.token.isReturn()) {
183
+ if (!this.token.isReturn()) {
169
184
  return null;
170
185
  }
171
186
  this.setNextToken();
172
187
  this.expectAndSkipWhitespaceAndComments();
173
188
  const expressions = Array.from(this.parseExpressions(AliasOption.OPTIONAL));
174
- if(expressions.length === 0) {
175
- throw new Error('Expected expression');
189
+ if (expressions.length === 0) {
190
+ throw new Error("Expected expression");
176
191
  }
177
- if(expressions.some((expression: Expression) => expression.has_reducers())) {
192
+ if (expressions.some((expression: Expression) => expression.has_reducers())) {
178
193
  return new AggregatedReturn(expressions);
179
194
  }
180
195
  this._returns++;
@@ -182,120 +197,155 @@ class Parser extends BaseParser {
182
197
  }
183
198
 
184
199
  private parseWhere(): Where | null {
185
- if(!this.token.isWhere()) {
200
+ if (!this.token.isWhere()) {
186
201
  return null;
187
202
  }
188
203
  this.expectPreviousTokenToBeWhitespaceOrComment();
189
204
  this.setNextToken();
190
205
  this.expectAndSkipWhitespaceAndComments();
191
206
  const expression = this.parseExpression();
192
- if(expression === null) {
193
- throw new Error('Expected expression');
207
+ if (expression === null) {
208
+ throw new Error("Expected expression");
194
209
  }
195
- if(ObjectUtils.isInstanceOfAny(expression.firstChild(), [JSONArray, AssociativeArray])) {
196
- throw new Error('Expected an expression which can be evaluated to a boolean');
210
+ if (ObjectUtils.isInstanceOfAny(expression.firstChild(), [JSONArray, AssociativeArray])) {
211
+ throw new Error("Expected an expression which can be evaluated to a boolean");
197
212
  }
198
213
  return new Where(expression);
199
214
  }
200
215
 
201
216
  private parseLoad(): Load | null {
202
- if(!this.token.isLoad()) {
217
+ if (!this.token.isLoad()) {
203
218
  return null;
204
219
  }
205
220
  const load = new Load();
206
221
  this.setNextToken();
207
222
  this.expectAndSkipWhitespaceAndComments();
208
- if(!(this.token.isJSON() || this.token.isCSV() || this.token.isText())) {
209
- throw new Error('Expected JSON, CSV, or TEXT');
223
+ if (!(this.token.isJSON() || this.token.isCSV() || this.token.isText())) {
224
+ throw new Error("Expected JSON, CSV, or TEXT");
210
225
  }
211
226
  load.addChild(this.token.node);
212
227
  this.setNextToken();
213
228
  this.expectAndSkipWhitespaceAndComments();
214
- if(!this.token.isFrom()) {
215
- throw new Error('Expected FROM');
229
+ if (!this.token.isFrom()) {
230
+ throw new Error("Expected FROM");
216
231
  }
217
232
  this.setNextToken();
218
233
  this.expectAndSkipWhitespaceAndComments();
219
234
  const from = new From();
220
235
  load.addChild(from);
221
-
236
+
222
237
  // Check if the source is an async function
223
238
  const asyncFunc = this.parseAsyncFunction();
224
239
  if (asyncFunc !== null) {
225
240
  from.addChild(asyncFunc);
226
241
  } else {
227
242
  const expression = this.parseExpression();
228
- if(expression === null) {
229
- throw new Error('Expected expression or async function');
243
+ if (expression === null) {
244
+ throw new Error("Expected expression or async function");
230
245
  }
231
246
  from.addChild(expression);
232
247
  }
233
-
248
+
234
249
  this.expectAndSkipWhitespaceAndComments();
235
- if(this.token.isHeaders()) {
250
+ if (this.token.isHeaders()) {
236
251
  const headers = new Headers();
237
252
  this.setNextToken();
238
253
  this.expectAndSkipWhitespaceAndComments();
239
254
  const header = this.parseExpression();
240
- if(header === null) {
241
- throw new Error('Expected expression');
255
+ if (header === null) {
256
+ throw new Error("Expected expression");
242
257
  }
243
258
  headers.addChild(header);
244
259
  load.addChild(headers);
245
260
  this.expectAndSkipWhitespaceAndComments();
246
261
  }
247
- if(this.token.isPost()) {
262
+ if (this.token.isPost()) {
248
263
  const post = new Post();
249
264
  this.setNextToken();
250
265
  this.expectAndSkipWhitespaceAndComments();
251
266
  const payload = this.parseExpression();
252
- if(payload === null) {
253
- throw new Error('Expected expression');
267
+ if (payload === null) {
268
+ throw new Error("Expected expression");
254
269
  }
255
270
  post.addChild(payload);
256
271
  load.addChild(post);
257
272
  this.expectAndSkipWhitespaceAndComments();
258
273
  }
259
274
  const alias = this.parseAlias();
260
- if(alias !== null) {
275
+ if (alias !== null) {
261
276
  load.addChild(alias);
262
277
  this.variables.set(alias.getAlias(), load);
263
278
  } else {
264
- throw new Error('Expected alias');
279
+ throw new Error("Expected alias");
265
280
  }
266
281
  return load;
267
282
  }
268
283
 
284
+ private parseCall(): Call | null {
285
+ if (!this.token.isCall()) {
286
+ return null;
287
+ }
288
+ this.setNextToken();
289
+ this.expectAndSkipWhitespaceAndComments();
290
+ const asyncFunction = this.parseAsyncFunction();
291
+ if (asyncFunction === null) {
292
+ throw new Error("Expected async function");
293
+ }
294
+ const call = new Call();
295
+ call.function = asyncFunction;
296
+ this.skipWhitespaceAndComments();
297
+ if (this.token.isYield()) {
298
+ this.expectPreviousTokenToBeWhitespaceOrComment();
299
+ this.setNextToken();
300
+ this.expectAndSkipWhitespaceAndComments();
301
+ const expressions = Array.from(this.parseExpressions(AliasOption.OPTIONAL));
302
+ if (expressions.length === 0) {
303
+ throw new Error("Expected at least one expression");
304
+ }
305
+ call.yielded = expressions;
306
+ }
307
+ return call;
308
+ }
309
+
269
310
  private parseLimit(): Limit | null {
270
311
  this.skipWhitespaceAndComments();
271
- if(!this.token.isLimit()) {
312
+ if (!this.token.isLimit()) {
272
313
  return null;
273
314
  }
274
315
  this.expectPreviousTokenToBeWhitespaceOrComment();
275
316
  this.setNextToken();
276
317
  this.expectAndSkipWhitespaceAndComments();
277
- if(!this.token.isNumber()) {
278
- throw new Error('Expected number');
318
+ if (!this.token.isNumber()) {
319
+ throw new Error("Expected number");
279
320
  }
280
- const limit = new Limit(parseInt(this.token.value || '0'));
321
+ const limit = new Limit(parseInt(this.token.value || "0"));
281
322
  this.setNextToken();
282
323
  return limit;
283
324
  }
284
325
 
285
- private *parseExpressions(alias_option: AliasOption = AliasOption.NOT_ALLOWED): IterableIterator<Expression> {
286
- while(true) {
326
+ private *parseExpressions(
327
+ alias_option: AliasOption = AliasOption.NOT_ALLOWED
328
+ ): IterableIterator<Expression> {
329
+ while (true) {
287
330
  const expression: Expression | null = this.parseExpression();
288
- if(expression !== null) {
331
+ if (expression !== null) {
289
332
  const alias = this.parseAlias();
290
- if(expression.firstChild() instanceof Reference && alias === null) {
333
+ if (expression.firstChild() instanceof Reference && alias === null) {
291
334
  const reference: Reference = expression.firstChild() as Reference;
292
335
  expression.setAlias(reference.identifier);
293
336
  this.variables.set(reference.identifier, expression);
294
- } else if(alias_option === AliasOption.REQUIRED && alias === null && !(expression.firstChild() instanceof Reference)) {
295
- throw new Error('Alias required');
296
- } else if(alias_option === AliasOption.NOT_ALLOWED && alias !== null) {
297
- throw new Error('Alias not allowed');
298
- } else if([AliasOption.OPTIONAL, AliasOption.REQUIRED].includes(alias_option) && alias !== null) {
337
+ } else if (
338
+ alias_option === AliasOption.REQUIRED &&
339
+ alias === null &&
340
+ !(expression.firstChild() instanceof Reference)
341
+ ) {
342
+ throw new Error("Alias required");
343
+ } else if (alias_option === AliasOption.NOT_ALLOWED && alias !== null) {
344
+ throw new Error("Alias not allowed");
345
+ } else if (
346
+ [AliasOption.OPTIONAL, AliasOption.REQUIRED].includes(alias_option) &&
347
+ alias !== null
348
+ ) {
299
349
  expression.setAlias(alias.getAlias());
300
350
  this.variables.set(alias.getAlias(), expression);
301
351
  }
@@ -304,7 +354,7 @@ class Parser extends BaseParser {
304
354
  break;
305
355
  }
306
356
  this.skipWhitespaceAndComments();
307
- if(!this.token.isComma()) {
357
+ if (!this.token.isComma()) {
308
358
  break;
309
359
  }
310
360
  this.setNextToken();
@@ -313,79 +363,79 @@ class Parser extends BaseParser {
313
363
 
314
364
  private parseExpression(): Expression | null {
315
365
  const expression = new Expression();
316
- while(true) {
366
+ while (true) {
317
367
  this.skipWhitespaceAndComments();
318
- if(this.token.isIdentifier() && !this.peek()?.isLeftParenthesis()) {
319
- const identifier: string = this.token.value || '';
368
+ if (this.token.isIdentifier() && !this.peek()?.isLeftParenthesis()) {
369
+ const identifier: string = this.token.value || "";
320
370
  const reference = new Reference(identifier, this.variables.get(identifier));
321
371
  this.setNextToken();
322
372
  const lookup = this.parseLookup(reference);
323
373
  expression.addNode(lookup);
324
- } else if(this.token.isIdentifier() && this.peek()?.isLeftParenthesis()) {
374
+ } else if (this.token.isIdentifier() && this.peek()?.isLeftParenthesis()) {
325
375
  const func = this.parsePredicateFunction() || this.parseFunction();
326
- if(func !== null) {
376
+ if (func !== null) {
327
377
  const lookup = this.parseLookup(func);
328
378
  expression.addNode(lookup);
329
379
  }
330
- } else if(this.token.isOperand()) {
380
+ } else if (this.token.isOperand()) {
331
381
  expression.addNode(this.token.node);
332
382
  this.setNextToken();
333
- } else if(this.token.isFString()) {
383
+ } else if (this.token.isFString()) {
334
384
  const f_string = this.parseFString();
335
- if(f_string === null) {
336
- throw new Error('Expected f-string');
385
+ if (f_string === null) {
386
+ throw new Error("Expected f-string");
337
387
  }
338
388
  expression.addNode(f_string);
339
- } else if(this.token.isLeftParenthesis()) {
389
+ } else if (this.token.isLeftParenthesis()) {
340
390
  this.setNextToken();
341
391
  const sub = this.parseExpression();
342
- if(sub === null) {
343
- throw new Error('Expected expression');
392
+ if (sub === null) {
393
+ throw new Error("Expected expression");
344
394
  }
345
- if(!this.token.isRightParenthesis()) {
346
- throw new Error('Expected right parenthesis');
395
+ if (!this.token.isRightParenthesis()) {
396
+ throw new Error("Expected right parenthesis");
347
397
  }
348
398
  this.setNextToken();
349
399
  const lookup = this.parseLookup(sub);
350
400
  expression.addNode(lookup);
351
- } else if(this.token.isOpeningBrace() || this.token.isOpeningBracket()) {
401
+ } else if (this.token.isOpeningBrace() || this.token.isOpeningBracket()) {
352
402
  const json = this.parseJSON();
353
- if(json === null) {
354
- throw new Error('Expected JSON object');
403
+ if (json === null) {
404
+ throw new Error("Expected JSON object");
355
405
  }
356
406
  const lookup = this.parseLookup(json);
357
407
  expression.addNode(lookup);
358
- } else if(this.token.isCase()) {
408
+ } else if (this.token.isCase()) {
359
409
  const _case = this.parseCase();
360
- if(_case === null) {
361
- throw new Error('Expected CASE statement');
410
+ if (_case === null) {
411
+ throw new Error("Expected CASE statement");
362
412
  }
363
413
  expression.addNode(_case);
364
- } else if(this.token.isNot()) {
414
+ } else if (this.token.isNot()) {
365
415
  const not = new Not();
366
416
  this.setNextToken();
367
417
  const sub = this.parseExpression();
368
- if(sub === null) {
369
- throw new Error('Expected expression');
418
+ if (sub === null) {
419
+ throw new Error("Expected expression");
370
420
  }
371
421
  not.addChild(sub);
372
422
  expression.addNode(not);
373
423
  } else {
374
- if(expression.nodesAdded()) {
375
- throw new Error('Expected operand or left parenthesis');
424
+ if (expression.nodesAdded()) {
425
+ throw new Error("Expected operand or left parenthesis");
376
426
  } else {
377
427
  break;
378
428
  }
379
429
  }
380
430
  this.skipWhitespaceAndComments();
381
- if(this.token.isOperator()) {
431
+ if (this.token.isOperator()) {
382
432
  expression.addNode(this.token.node);
383
433
  } else {
384
434
  break;
385
435
  }
386
436
  this.setNextToken();
387
437
  }
388
- if(expression.nodesAdded()) {
438
+ if (expression.nodesAdded()) {
389
439
  expression.finish();
390
440
  return expression;
391
441
  }
@@ -395,42 +445,42 @@ class Parser extends BaseParser {
395
445
  private parseLookup(node: ASTNode): ASTNode {
396
446
  let variable: ASTNode = node;
397
447
  let lookup: Lookup | RangeLookup | null = null;
398
- while(true) {
399
- if(this.token.isDot()) {
448
+ while (true) {
449
+ if (this.token.isDot()) {
400
450
  this.setNextToken();
401
- if(!this.token.isIdentifier() && !this.token.isKeyword()) {
402
- throw new Error('Expected identifier');
451
+ if (!this.token.isIdentifier() && !this.token.isKeyword()) {
452
+ throw new Error("Expected identifier");
403
453
  }
404
454
  lookup = new Lookup();
405
- lookup.index = new Identifier(this.token.value || '');
455
+ lookup.index = new Identifier(this.token.value || "");
406
456
  lookup.variable = variable;
407
457
  this.setNextToken();
408
- } else if(this.token.isOpeningBracket()) {
458
+ } else if (this.token.isOpeningBracket()) {
409
459
  this.setNextToken();
410
460
  this.skipWhitespaceAndComments();
411
461
  const index = this.parseExpression();
412
462
  let to: Expression | null = null;
413
463
  this.skipWhitespaceAndComments();
414
- if(this.token.isColon()) {
464
+ if (this.token.isColon()) {
415
465
  this.setNextToken();
416
466
  this.skipWhitespaceAndComments();
417
467
  lookup = new RangeLookup();
418
468
  to = this.parseExpression();
419
469
  } else {
420
- if(index === null) {
421
- throw new Error('Expected expression');
470
+ if (index === null) {
471
+ throw new Error("Expected expression");
422
472
  }
423
473
  lookup = new Lookup();
424
474
  }
425
475
  this.skipWhitespaceAndComments();
426
- if(!this.token.isClosingBracket()) {
427
- throw new Error('Expected closing bracket');
476
+ if (!this.token.isClosingBracket()) {
477
+ throw new Error("Expected closing bracket");
428
478
  }
429
479
  this.setNextToken();
430
- if(lookup instanceof RangeLookup) {
480
+ if (lookup instanceof RangeLookup) {
431
481
  lookup.from = index || new Null();
432
482
  lookup.to = to || new Null();
433
- } else if(lookup instanceof Lookup && index !== null) {
483
+ } else if (lookup instanceof Lookup && index !== null) {
434
484
  lookup.index = index;
435
485
  }
436
486
  lookup.variable = variable;
@@ -443,26 +493,26 @@ class Parser extends BaseParser {
443
493
  }
444
494
 
445
495
  private parseCase(): Case | null {
446
- if(!this.token.isCase()) {
496
+ if (!this.token.isCase()) {
447
497
  return null;
448
498
  }
449
499
  this.setNextToken();
450
500
  const _case = new Case();
451
501
  let parts: number = 0;
452
502
  this.expectAndSkipWhitespaceAndComments();
453
- while(true) {
503
+ while (true) {
454
504
  const when = this.parseWhen();
455
- if(when === null && parts === 0) {
456
- throw new Error('Expected WHEN');
457
- } else if(when === null && parts > 0) {
505
+ if (when === null && parts === 0) {
506
+ throw new Error("Expected WHEN");
507
+ } else if (when === null && parts > 0) {
458
508
  break;
459
509
  } else if (when !== null) {
460
510
  _case.addChild(when);
461
511
  }
462
512
  this.expectAndSkipWhitespaceAndComments();
463
513
  const then = this.parseThen();
464
- if(then === null) {
465
- throw new Error('Expected THEN');
514
+ if (then === null) {
515
+ throw new Error("Expected THEN");
466
516
  } else {
467
517
  _case.addChild(then);
468
518
  }
@@ -470,59 +520,59 @@ class Parser extends BaseParser {
470
520
  parts++;
471
521
  }
472
522
  const _else = this.parseElse();
473
- if(_else === null) {
474
- throw new Error('Expected ELSE');
523
+ if (_else === null) {
524
+ throw new Error("Expected ELSE");
475
525
  } else {
476
526
  _case.addChild(_else);
477
527
  }
478
528
  this.expectAndSkipWhitespaceAndComments();
479
- if(!this.token.isEnd()) {
480
- throw new Error('Expected END');
529
+ if (!this.token.isEnd()) {
530
+ throw new Error("Expected END");
481
531
  }
482
532
  this.setNextToken();
483
533
  return _case;
484
534
  }
485
535
 
486
536
  private parseWhen(): When | null {
487
- if(!this.token.isWhen()) {
537
+ if (!this.token.isWhen()) {
488
538
  return null;
489
539
  }
490
540
  this.setNextToken();
491
541
  const when = new When();
492
542
  this.expectAndSkipWhitespaceAndComments();
493
543
  const expression = this.parseExpression();
494
- if(expression === null) {
495
- throw new Error('Expected expression');
544
+ if (expression === null) {
545
+ throw new Error("Expected expression");
496
546
  }
497
547
  when.addChild(expression);
498
548
  return when;
499
549
  }
500
550
 
501
551
  private parseThen(): Then | null {
502
- if(!this.token.isThen()) {
552
+ if (!this.token.isThen()) {
503
553
  return null;
504
554
  }
505
555
  this.setNextToken();
506
556
  const then = new Then();
507
557
  this.expectAndSkipWhitespaceAndComments();
508
558
  const expression = this.parseExpression();
509
- if(expression === null) {
510
- throw new Error('Expected expression');
559
+ if (expression === null) {
560
+ throw new Error("Expected expression");
511
561
  }
512
562
  then.addChild(expression);
513
563
  return then;
514
564
  }
515
565
 
516
566
  private parseElse(): Else | null {
517
- if(!this.token.isElse()) {
567
+ if (!this.token.isElse()) {
518
568
  return null;
519
569
  }
520
570
  this.setNextToken();
521
571
  const _else = new Else();
522
572
  this.expectAndSkipWhitespaceAndComments();
523
573
  const expression = this.parseExpression();
524
- if(expression === null) {
525
- throw new Error('Expected expression');
574
+ if (expression === null) {
575
+ throw new Error("Expected expression");
526
576
  }
527
577
  _else.addChild(expression);
528
578
  return _else;
@@ -530,47 +580,47 @@ class Parser extends BaseParser {
530
580
 
531
581
  private parseAlias(): Alias | null {
532
582
  this.skipWhitespaceAndComments();
533
- if(!this.token.isAs()) {
583
+ if (!this.token.isAs()) {
534
584
  return null;
535
585
  }
536
586
  this.expectPreviousTokenToBeWhitespaceOrComment();
537
587
  this.setNextToken();
538
588
  this.expectAndSkipWhitespaceAndComments();
539
- if((!this.token.isIdentifier() && !this.token.isKeyword()) || this.token.value === null) {
540
- throw new Error('Expected identifier');
589
+ if ((!this.token.isIdentifier() && !this.token.isKeyword()) || this.token.value === null) {
590
+ throw new Error("Expected identifier");
541
591
  }
542
- const alias = new Alias(this.token.value || '');
592
+ const alias = new Alias(this.token.value || "");
543
593
  this.setNextToken();
544
594
  return alias;
545
595
  }
546
596
 
547
597
  private parseFunction(): Function | null {
548
- if(!this.token.isIdentifier()) {
598
+ if (!this.token.isIdentifier()) {
549
599
  return null;
550
600
  }
551
- if(this.token.value === null) {
552
- throw new Error('Expected identifier');
601
+ if (this.token.value === null) {
602
+ throw new Error("Expected identifier");
553
603
  }
554
- if(!this.peek()?.isLeftParenthesis()) {
604
+ if (!this.peek()?.isLeftParenthesis()) {
555
605
  return null;
556
606
  }
557
607
  const func = FunctionFactory.create(this.token.value);
558
- if(func instanceof AggregateFunction && this.context.containsType(AggregateFunction)) {
559
- throw new Error('Aggregate functions cannot be nested');
608
+ if (func instanceof AggregateFunction && this.context.containsType(AggregateFunction)) {
609
+ throw new Error("Aggregate functions cannot be nested");
560
610
  }
561
611
  this.context.push(func);
562
612
  this.setNextToken();
563
613
  this.setNextToken();
564
614
  this.skipWhitespaceAndComments();
565
- if(this.token.isDistinct()) {
615
+ if (this.token.isDistinct()) {
566
616
  func.distinct = true;
567
617
  this.setNextToken();
568
618
  this.expectAndSkipWhitespaceAndComments();
569
619
  }
570
620
  func.parameters = Array.from(this.parseExpressions(AliasOption.NOT_ALLOWED));
571
621
  this.skipWhitespaceAndComments();
572
- if(!this.token.isRightParenthesis()) {
573
- throw new Error('Expected right parenthesis');
622
+ if (!this.token.isRightParenthesis()) {
623
+ throw new Error("Expected right parenthesis");
574
624
  }
575
625
  this.setNextToken();
576
626
  this.context.pop();
@@ -580,21 +630,21 @@ class Parser extends BaseParser {
580
630
  /**
581
631
  * Parses an async function call for use in LOAD operations.
582
632
  * Only matches if the identifier is registered as an async data provider.
583
- *
633
+ *
584
634
  * @returns An AsyncFunction node if a registered async function is found, otherwise null
585
635
  */
586
636
  private parseAsyncFunction(): AsyncFunction | null {
587
- if(!this.token.isIdentifier()) {
637
+ if (!this.token.isIdentifier()) {
588
638
  return null;
589
639
  }
590
- if(this.token.value === null) {
640
+ if (this.token.value === null) {
591
641
  return null;
592
642
  }
593
643
  // Only parse as async function if it's registered as an async provider
594
- if(!FunctionFactory.isAsyncProvider(this.token.value)) {
644
+ if (!FunctionFactory.isAsyncProvider(this.token.value)) {
595
645
  return null;
596
646
  }
597
- if(!this.peek()?.isLeftParenthesis()) {
647
+ if (!this.peek()?.isLeftParenthesis()) {
598
648
  return null;
599
649
  }
600
650
  const asyncFunc = FunctionFactory.createAsync(this.token.value);
@@ -603,65 +653,79 @@ class Parser extends BaseParser {
603
653
  this.skipWhitespaceAndComments();
604
654
  asyncFunc.parameters = Array.from(this.parseExpressions(AliasOption.NOT_ALLOWED));
605
655
  this.skipWhitespaceAndComments();
606
- if(!this.token.isRightParenthesis()) {
607
- throw new Error('Expected right parenthesis');
656
+ if (!this.token.isRightParenthesis()) {
657
+ throw new Error("Expected right parenthesis");
608
658
  }
609
659
  this.setNextToken();
610
660
  return asyncFunc;
611
661
  }
612
-
662
+
613
663
  private parsePredicateFunction(): PredicateFunction | null {
614
- if(!this.ahead([Token.IDENTIFIER(""), Token.LEFT_PARENTHESIS, Token.IDENTIFIER(""), Token.IN])) {
664
+ if (
665
+ !this.ahead([
666
+ Token.IDENTIFIER(""),
667
+ Token.LEFT_PARENTHESIS,
668
+ Token.IDENTIFIER(""),
669
+ Token.IN,
670
+ ])
671
+ ) {
615
672
  return null;
616
673
  }
617
- if(this.token.value === null) {
618
- throw new Error('Expected identifier');
674
+ if (this.token.value === null) {
675
+ throw new Error("Expected identifier");
619
676
  }
620
677
  const func = FunctionFactory.createPredicate(this.token.value);
621
678
  this.setNextToken();
622
- if(!this.token.isLeftParenthesis()) {
623
- throw new Error('Expected left parenthesis');
679
+ if (!this.token.isLeftParenthesis()) {
680
+ throw new Error("Expected left parenthesis");
624
681
  }
625
682
  this.setNextToken();
626
683
  this.skipWhitespaceAndComments();
627
- if(!this.token.isIdentifier()) {
628
- throw new Error('Expected identifier');
684
+ if (!this.token.isIdentifier()) {
685
+ throw new Error("Expected identifier");
629
686
  }
630
687
  const reference = new Reference(this.token.value);
631
688
  this.variables.set(reference.identifier, reference);
632
689
  func.addChild(reference);
633
690
  this.setNextToken();
634
691
  this.expectAndSkipWhitespaceAndComments();
635
- if(!this.token.isIn()) {
636
- throw new Error('Expected IN');
692
+ if (!this.token.isIn()) {
693
+ throw new Error("Expected IN");
637
694
  }
638
695
  this.setNextToken();
639
696
  this.expectAndSkipWhitespaceAndComments();
640
697
  const expression = this.parseExpression();
641
- if(expression === null) {
642
- throw new Error('Expected expression');
643
- }
644
- if(!ObjectUtils.isInstanceOfAny(expression.firstChild(), [JSONArray, Reference, Lookup, Function])) {
645
- throw new Error('Expected array or reference');
698
+ if (expression === null) {
699
+ throw new Error("Expected expression");
700
+ }
701
+ if (
702
+ !ObjectUtils.isInstanceOfAny(expression.firstChild(), [
703
+ JSONArray,
704
+ Reference,
705
+ Lookup,
706
+ Function,
707
+ ])
708
+ ) {
709
+ throw new Error("Expected array or reference");
646
710
  }
647
711
  func.addChild(expression);
648
712
  this.skipWhitespaceAndComments();
649
- if(!this.token.isPipe()) {
650
- throw new Error('Expected pipe');
713
+ if (!this.token.isPipe()) {
714
+ throw new Error("Expected pipe");
651
715
  }
652
716
  this.setNextToken();
653
717
  const _return = this.parseExpression();
654
- if(_return === null) {
655
- throw new Error('Expected expression');
718
+ if (_return === null) {
719
+ throw new Error("Expected expression");
656
720
  }
657
721
  func.addChild(_return);
658
722
  const where = this.parseWhere();
659
- if(where !== null) {
723
+ if (where !== null) {
660
724
  func.addChild(where);
661
725
  }
662
726
  this.skipWhitespaceAndComments();
663
- if(!this.token.isRightParenthesis()) {
664
- throw new Error('Expected right parenthesis');
727
+ if (!this.token.isRightParenthesis()) {
728
+ throw new Error("Expected right parenthesis");
665
729
  }
666
730
  this.setNextToken();
667
731
  this.variables.delete(reference.identifier);
@@ -669,24 +733,24 @@ class Parser extends BaseParser {
669
733
  }
670
734
 
671
735
  private parseFString(): FString | null {
672
- if(!this.token.isFString()) {
736
+ if (!this.token.isFString()) {
673
737
  return null;
674
738
  }
675
739
  const f_string = new FString();
676
- while(this.token.isFString()) {
677
- if(this.token.value !== null) {
740
+ while (this.token.isFString()) {
741
+ if (this.token.value !== null) {
678
742
  f_string.addChild(new String(this.token.value));
679
743
  }
680
744
  this.setNextToken();
681
- if(this.token.isOpeningBrace()) {
745
+ if (this.token.isOpeningBrace()) {
682
746
  this.setNextToken();
683
747
  const expression = this.parseExpression();
684
- if(expression === null) {
685
- throw new Error('Expected expression');
748
+ if (expression === null) {
749
+ throw new Error("Expected expression");
686
750
  }
687
751
  f_string.addChild(expression);
688
- if(!this.token.isClosingBrace()) {
689
- throw new Error('Expected closing brace');
752
+ if (!this.token.isClosingBrace()) {
753
+ throw new Error("Expected closing brace");
690
754
  }
691
755
  this.setNextToken();
692
756
  } else {
@@ -697,54 +761,54 @@ class Parser extends BaseParser {
697
761
  }
698
762
 
699
763
  private parseJSON(): AssociativeArray | JSONArray {
700
- if(this.token.isOpeningBrace()) {
764
+ if (this.token.isOpeningBrace()) {
701
765
  const array = this.parseAssociativeArray();
702
- if(array === null) {
703
- throw new Error('Expected associative array');
766
+ if (array === null) {
767
+ throw new Error("Expected associative array");
704
768
  }
705
769
  return array;
706
- } else if(this.token.isOpeningBracket()) {
770
+ } else if (this.token.isOpeningBracket()) {
707
771
  const array = this.parseJSONArray();
708
- if(array === null) {
709
- throw new Error('Expected JSON array');
772
+ if (array === null) {
773
+ throw new Error("Expected JSON array");
710
774
  }
711
775
  return array;
712
776
  }
713
- throw new Error('Expected opening brace or bracket');
777
+ throw new Error("Expected opening brace or bracket");
714
778
  }
715
779
 
716
780
  private parseAssociativeArray(): AssociativeArray | null {
717
- if(!this.token.isOpeningBrace()) {
781
+ if (!this.token.isOpeningBrace()) {
718
782
  return null;
719
783
  }
720
784
  const array = new AssociativeArray();
721
785
  this.setNextToken();
722
- while(true) {
786
+ while (true) {
723
787
  this.skipWhitespaceAndComments();
724
- if(this.token.isClosingBrace()) {
788
+ if (this.token.isClosingBrace()) {
725
789
  break;
726
790
  }
727
- if(!this.token.isIdentifier() && !this.token.isKeyword()) {
728
- throw new Error('Expected identifier');
791
+ if (!this.token.isIdentifier() && !this.token.isKeyword()) {
792
+ throw new Error("Expected identifier");
729
793
  }
730
794
  const key = this.token.value;
731
- if(key === null) {
732
- throw new Error('Expected string');
795
+ if (key === null) {
796
+ throw new Error("Expected string");
733
797
  }
734
798
  this.setNextToken();
735
799
  this.skipWhitespaceAndComments();
736
- if(!this.token.isColon()) {
737
- throw new Error('Expected colon');
800
+ if (!this.token.isColon()) {
801
+ throw new Error("Expected colon");
738
802
  }
739
803
  this.setNextToken();
740
804
  this.skipWhitespaceAndComments();
741
805
  const value = this.parseExpression();
742
- if(value === null) {
743
- throw new Error('Expected expression');
806
+ if (value === null) {
807
+ throw new Error("Expected expression");
744
808
  }
745
809
  array.addKeyValue(new KeyValuePair(key, value));
746
810
  this.skipWhitespaceAndComments();
747
- if(this.token.isComma()) {
811
+ if (this.token.isComma()) {
748
812
  this.setNextToken();
749
813
  }
750
814
  }
@@ -753,23 +817,23 @@ class Parser extends BaseParser {
753
817
  }
754
818
 
755
819
  private parseJSONArray(): JSONArray | null {
756
- if(!this.token.isOpeningBracket()) {
820
+ if (!this.token.isOpeningBracket()) {
757
821
  return null;
758
822
  }
759
823
  const array = new JSONArray();
760
824
  this.setNextToken();
761
- while(true) {
825
+ while (true) {
762
826
  this.skipWhitespaceAndComments();
763
- if(this.token.isClosingBracket()) {
827
+ if (this.token.isClosingBracket()) {
764
828
  break;
765
829
  }
766
830
  const value = this.parseExpression();
767
- if(value === null) {
768
- throw new Error('Expected expression');
831
+ if (value === null) {
832
+ throw new Error("Expected expression");
769
833
  }
770
834
  array.addValue(value);
771
835
  this.skipWhitespaceAndComments();
772
- if(this.token.isComma()) {
836
+ if (this.token.isComma()) {
773
837
  this.setNextToken();
774
838
  }
775
839
  }
@@ -779,14 +843,14 @@ class Parser extends BaseParser {
779
843
 
780
844
  private expectAndSkipWhitespaceAndComments(): void {
781
845
  const skipped = this.skipWhitespaceAndComments();
782
- if(!skipped) {
783
- throw new Error('Expected whitespace or comment');
846
+ if (!skipped) {
847
+ throw new Error("Expected whitespace or comment");
784
848
  }
785
849
  }
786
850
 
787
851
  private skipWhitespaceAndComments(): boolean {
788
852
  let skipped: boolean = this.previousToken.isWhitespaceOrComment();
789
- while(this.token.isWhitespace() || this.token.isComment()) {
853
+ while (this.token.isWhitespace() || this.token.isComment()) {
790
854
  this.setNextToken();
791
855
  skipped = true;
792
856
  }
@@ -794,10 +858,10 @@ class Parser extends BaseParser {
794
858
  }
795
859
 
796
860
  private expectPreviousTokenToBeWhitespaceOrComment(): void {
797
- if(!this.previousToken.isWhitespaceOrComment()) {
798
- throw new Error('Expected whitespace or comment');
861
+ if (!this.previousToken.isWhitespaceOrComment()) {
862
+ throw new Error("Expected whitespace or comment");
799
863
  }
800
864
  }
801
865
  }
802
866
 
803
- export default Parser;
867
+ export default Parser;