flowquery 1.0.29 → 1.0.30

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.29",
3
+ "version": "1.0.30",
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",
@@ -798,12 +798,7 @@ class Parser extends BaseParser {
798
798
  expression.addNode(lookup);
799
799
  return true;
800
800
  }
801
- } else if (
802
- this.token.isLeftParenthesis() &&
803
- (this.peek()?.isIdentifierOrKeyword() ||
804
- this.peek()?.isColon() ||
805
- this.peek()?.isRightParenthesis())
806
- ) {
801
+ } else if (this.token.isLeftParenthesis() && this.looksLikeNodePattern()) {
807
802
  // Possible graph pattern expression
808
803
  const pattern = this.parsePatternExpression();
809
804
  if (pattern !== null) {
@@ -865,6 +860,42 @@ class Parser extends BaseParser {
865
860
  return false;
866
861
  }
867
862
 
863
+ /**
864
+ * Peeks ahead from a left parenthesis to determine whether the
865
+ * upcoming tokens form a graph-node pattern (e.g. (n:Label), (n),
866
+ * (:Label), ()) rather than a parenthesised expression (e.g.
867
+ * (variable.property), (a + b)).
868
+ *
869
+ * The heuristic is:
870
+ * • ( followed by `:` or `)` → node pattern
871
+ * • ( identifier, then `:` or `{` or `)` → node pattern
872
+ * • anything else → parenthesised expression
873
+ */
874
+ private looksLikeNodePattern(): boolean {
875
+ const savedIndex = this.tokenIndex;
876
+ this.setNextToken(); // skip '('
877
+ this.skipWhitespaceAndComments();
878
+
879
+ if (this.token.isColon() || this.token.isRightParenthesis()) {
880
+ this.tokenIndex = savedIndex;
881
+ return true;
882
+ }
883
+
884
+ if (this.token.isIdentifierOrKeyword()) {
885
+ this.setNextToken(); // skip identifier
886
+ this.skipWhitespaceAndComments();
887
+ const result =
888
+ this.token.isColon() ||
889
+ this.token.isOpeningBrace() ||
890
+ this.token.isRightParenthesis();
891
+ this.tokenIndex = savedIndex;
892
+ return result;
893
+ }
894
+
895
+ this.tokenIndex = savedIndex;
896
+ return false;
897
+ }
898
+
868
899
  private parseExpression(): Expression | null {
869
900
  const expression = new Expression();
870
901
  while (true) {
@@ -1098,3 +1098,61 @@ test("Test WHERE with NOT ENDS WITH", () => {
1098
1098
  "--- Reference (s)"
1099
1099
  );
1100
1100
  });
1101
+
1102
+ test("Test parenthesized expression with addition", () => {
1103
+ const parser = new Parser();
1104
+ const ast = parser.parse("WITH 1 AS n RETURN (n + 2)");
1105
+ // prettier-ignore
1106
+ expect(ast.print()).toBe(
1107
+ "ASTNode\n" +
1108
+ "- With\n" +
1109
+ "-- Expression (n)\n" +
1110
+ "--- Number (1)\n" +
1111
+ "- Return\n" +
1112
+ "-- Expression\n" +
1113
+ "--- Expression\n" +
1114
+ "---- Add\n" +
1115
+ "----- Reference (n)\n" +
1116
+ "----- Number (2)"
1117
+ );
1118
+ });
1119
+
1120
+ test("Test parenthesized expression with property access", () => {
1121
+ const parser = new Parser();
1122
+ const ast = parser.parse("WITH {a: 1} AS obj RETURN (obj.a)");
1123
+ // prettier-ignore
1124
+ expect(ast.print()).toBe(
1125
+ "ASTNode\n" +
1126
+ "- With\n" +
1127
+ "-- Expression (obj)\n" +
1128
+ "--- AssociativeArray\n" +
1129
+ "---- KeyValuePair\n" +
1130
+ "----- String (a)\n" +
1131
+ "----- Expression\n" +
1132
+ "------ Number (1)\n" +
1133
+ "- Return\n" +
1134
+ "-- Expression\n" +
1135
+ "--- Expression\n" +
1136
+ "---- Lookup\n" +
1137
+ "----- Identifier (a)\n" +
1138
+ "----- Reference (obj)"
1139
+ );
1140
+ });
1141
+
1142
+ test("Test parenthesized expression with multiplication", () => {
1143
+ const parser = new Parser();
1144
+ const ast = parser.parse("WITH 5 AS x RETURN (x * 3)");
1145
+ // prettier-ignore
1146
+ expect(ast.print()).toBe(
1147
+ "ASTNode\n" +
1148
+ "- With\n" +
1149
+ "-- Expression (x)\n" +
1150
+ "--- Number (5)\n" +
1151
+ "- Return\n" +
1152
+ "-- Expression\n" +
1153
+ "--- Expression\n" +
1154
+ "---- Multiply\n" +
1155
+ "----- Reference (x)\n" +
1156
+ "----- Number (3)"
1157
+ );
1158
+ });