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/dist/flowquery.min.js +1 -1
- package/dist/tokenization/string_walker.d.ts.map +1 -1
- package/dist/tokenization/string_walker.js +13 -12
- package/dist/tokenization/string_walker.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/tokenization/string_walker.py +1 -1
- package/flowquery-py/tests/parsing/test_parser.py +46 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/tokenization/string_walker.ts +19 -16
- package/tests/parsing/parser.test.ts +45 -0
package/package.json
CHANGED
|
@@ -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 ===
|
|
84
|
+
return this.currentChar === "/" && this.nextChar === "/";
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
public multiLineCommentStart(): boolean {
|
|
88
|
-
return this.currentChar ===
|
|
88
|
+
return this.currentChar === "/" && this.nextChar === "*";
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
public multiLineCommentEnd(): boolean {
|
|
92
|
-
return this.currentChar ===
|
|
92
|
+
return this.currentChar === "*" && this.nextChar === "/";
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
public newLine(): boolean {
|
|
96
|
-
if (this.currentChar ===
|
|
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 ===
|
|
103
|
+
return this.currentChar === "\\" && this.nextChar === char;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
public escapedBrace(): boolean {
|
|
107
|
-
return (
|
|
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() ===
|
|
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");
|