flowquery 1.0.24 → 1.0.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowquery",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "description": "A declarative query language for data processing pipelines.",
5
5
  "main": "dist/index.node.js",
6
6
  "types": "dist/index.node.d.ts",
@@ -2,10 +2,10 @@ import StringUtils from "../utils/string_utils";
2
2
 
3
3
  /**
4
4
  * Utility class for walking through a string character by character during tokenization.
5
- *
5
+ *
6
6
  * Provides methods to check for specific character patterns, move through the string,
7
7
  * and extract substrings. Used by the Tokenizer to process input text.
8
- *
8
+ *
9
9
  * @example
10
10
  * ```typescript
11
11
  * const walker = new StringWalker("WITH x as variable");
@@ -20,7 +20,7 @@ class StringWalker {
20
20
 
21
21
  /**
22
22
  * Creates a new StringWalker for the given text.
23
- *
23
+ *
24
24
  * @param text - The input text to walk through
25
25
  */
26
26
  constructor(text: string) {
@@ -81,42 +81,45 @@ class StringWalker {
81
81
  }
82
82
 
83
83
  public singleLineCommentStart(): boolean {
84
- return this.currentChar === '/' && this.nextChar === '/';
84
+ return this.currentChar === "/" && this.nextChar === "/";
85
85
  }
86
86
 
87
87
  public multiLineCommentStart(): boolean {
88
- return this.currentChar === '/' && this.nextChar === '*';
88
+ return this.currentChar === "/" && this.nextChar === "*";
89
89
  }
90
90
 
91
91
  public multiLineCommentEnd(): boolean {
92
- return this.currentChar === '*' && this.nextChar === '/';
92
+ return this.currentChar === "*" && this.nextChar === "/";
93
93
  }
94
94
 
95
95
  public newLine(): boolean {
96
- if (this.currentChar === '\n') {
96
+ if (this.currentChar === "\n") {
97
97
  return true;
98
98
  }
99
99
  return false;
100
100
  }
101
101
 
102
102
  public escaped(char: string): boolean {
103
- return this.currentChar === '\\' && this.nextChar === char;
103
+ return this.currentChar === "\\" && this.nextChar === char;
104
104
  }
105
105
 
106
106
  public escapedBrace(): boolean {
107
- return (this.currentChar === '{' && this.nextChar === '{') || (this.currentChar === '}' && this.nextChar === '}');
107
+ return (
108
+ (this.currentChar === "{" && this.nextChar === "{") ||
109
+ (this.currentChar === "}" && this.nextChar === "}")
110
+ );
108
111
  }
109
112
 
110
113
  public openingBrace(): boolean {
111
- return this.currentChar === '{';
114
+ return this.currentChar === "{";
112
115
  }
113
116
 
114
117
  public closingBrace(): boolean {
115
- return this.currentChar === '}';
118
+ return this.currentChar === "}";
116
119
  }
117
120
 
118
121
  public checkForUnderScore(): boolean {
119
- const foundUnderScore = this.currentChar === '_';
122
+ const foundUnderScore = this.currentChar === "_";
120
123
  if (foundUnderScore) {
121
124
  this._position++;
122
125
  }
@@ -141,7 +144,7 @@ class StringWalker {
141
144
 
142
145
  public checkForQuote(): string | null {
143
146
  const quoteChar = this.currentChar;
144
- if (quoteChar === '"' || quoteChar === "'" || quoteChar === '`') {
147
+ if (quoteChar === '"' || quoteChar === "'" || quoteChar === "`") {
145
148
  this._position++;
146
149
  return quoteChar;
147
150
  }
@@ -163,7 +166,7 @@ class StringWalker {
163
166
  }
164
167
 
165
168
  public checkForFStringStart(): boolean {
166
- return this.currentChar.toLowerCase() === 'f' && ['\'', '"', '`'].includes(this.nextChar);
169
+ return this.currentChar.toLowerCase() === "f" && ["'", '"', "`"].includes(this.nextChar);
167
170
  }
168
171
 
169
172
  public moveNext(): void {
@@ -187,8 +190,8 @@ class StringWalker {
187
190
 
188
191
  public word_continuation(word: string): boolean {
189
192
  const next = this.text[this.position + word.length];
190
- return StringUtils.word_valid_chars.includes(next);
193
+ return next !== undefined && StringUtils.word_valid_chars.includes(next.toLowerCase());
191
194
  }
192
195
  }
193
196
 
194
- export default StringWalker;
197
+ export default StringWalker;
@@ -264,6 +264,51 @@ test("Test lookup with JSON array", () => {
264
264
  expect(_return.firstChild().value()).toBe(2);
265
265
  });
266
266
 
267
+ test("Test lookup with from keyword as property name", () => {
268
+ const parser = new Parser();
269
+ const ast = parser.parse("with {from: 1, to: 2} as x return x.from, x.to");
270
+ expect(ast.print()).toBe(
271
+ "ASTNode\n" +
272
+ "- With\n" +
273
+ "-- Expression (x)\n" +
274
+ "--- AssociativeArray\n" +
275
+ "---- KeyValuePair\n" +
276
+ "----- String (from)\n" +
277
+ "----- Expression\n" +
278
+ "------ Number (1)\n" +
279
+ "---- KeyValuePair\n" +
280
+ "----- String (to)\n" +
281
+ "----- Expression\n" +
282
+ "------ Number (2)\n" +
283
+ "- Return\n" +
284
+ "-- Expression\n" +
285
+ "--- Lookup\n" +
286
+ "---- Identifier (from)\n" +
287
+ "---- Reference (x)\n" +
288
+ "-- Expression\n" +
289
+ "--- Lookup\n" +
290
+ "---- Identifier (to)\n" +
291
+ "---- Reference (x)"
292
+ );
293
+ });
294
+
295
+ test("Test camelCase alias starting with keyword", () => {
296
+ const parser = new Parser();
297
+ const ast = parser.parse("LOAD JSON FROM '/data.json' AS x RETURN x.from AS fromUser");
298
+ expect(ast.print()).toContain("Lookup");
299
+ expect(ast.print()).toContain("Identifier (from)");
300
+ });
301
+
302
+ test("Test from keyword property in create virtual subquery", () => {
303
+ const parser = new Parser();
304
+ // Should not throw - email.from should be parsed correctly even with FROM being a keyword
305
+ expect(() => {
306
+ parser.parse(
307
+ "CREATE VIRTUAL (:Email) AS { LOAD JSON FROM '/data/emails.json' AS email RETURN email.id AS id, email.from AS fromUser }"
308
+ );
309
+ }).not.toThrow();
310
+ });
311
+
267
312
  test("Test lookup with reserved keyword property names", () => {
268
313
  const parser = new Parser();
269
314
  const ast = parser.parse("with {end: 1, null: 2, case: 3} as x return x.end, x.null, x.case");