Skip to content

Commit 9369c81

Browse files
committed
fix: issues in stringify adding parenthesis when needed
1 parent 14d1ed5 commit 9369c81

File tree

2 files changed

+29
-22
lines changed

2 files changed

+29
-22
lines changed

src/stringify.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isArray } from './is'
2-
import { extendOperators, operators } from './operators'
2+
import { extendOperators, leftAssociativeOperators, operators } from './operators'
33
import { unquotedPropertyRegex } from './regexps'
44
import type {
55
JSONPath,
@@ -37,6 +37,9 @@ export const stringify = (query: JSONQuery, options?: JSONQueryStringifyOptions)
3737
const customOperators = options?.operators ?? []
3838
const allOperators = extendOperators(operators, customOperators)
3939
const allOperatorsMap = Object.assign({}, ...allOperators)
40+
const allLeftAssociativeOperators = leftAssociativeOperators.concat(
41+
customOperators.filter((op) => op.leftAssociative).map((op) => op.op)
42+
)
4043

4144
const _stringify = (query: JSONQuery, indent: string, parenthesis = false) =>
4245
isArray(query)
@@ -73,7 +76,10 @@ export const stringify = (query: JSONQuery, options?: JSONQueryStringifyOptions)
7376
const childName = child?.[0]
7477
const precedence = allOperators.findIndex((group) => name in group)
7578
const childPrecedence = allOperators.findIndex((group) => childName in group)
76-
const parenthesis = precedence <= childPrecedence && (index > 0 || name === childName)
79+
const parenthesis =
80+
precedence < childPrecedence ||
81+
(precedence === childPrecedence && index > 0) ||
82+
(name === childName && !allLeftAssociativeOperators.includes(op))
7783

7884
return _stringify(child, indent + space, parenthesis)
7985
})

test-suite/stringify.test.json

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@
4848
"category": "operator",
4949
"description": "should wrap operators with the same precedence in parenthesis when needed",
5050
"tests": [
51-
{ "input": ["multiply", 2, 3, 4], "output": "2 * 3 * 4" },
52-
{ "input": ["multiply", ["multiply", 2, 3], 4], "output": "(2 * 3) * 4" },
51+
{ "input": ["pow", ["pow", 2, 3], 4], "output": "(2 ^ 3) ^ 4" },
52+
{ "input": ["pow", 2, ["pow", 3, 4]], "output": "2 ^ (3 ^ 4)" },
53+
{ "input": ["multiply", ["multiply", 2, 3], 4], "output": "2 * 3 * 4" },
5354
{ "input": ["multiply", 2, ["multiply", 3, 4]], "output": "2 * (3 * 4)" },
54-
{ "input": ["divide", 2, 3, 4], "output": "2 / 3 / 4" },
55-
{ "input": ["divide", ["divide", 2, 3], 4], "output": "(2 / 3) / 4" },
55+
{ "input": ["divide", ["divide", 2, 3], 4], "output": "2 / 3 / 4" },
5656
{ "input": ["divide", 2, ["divide", 3, 4]], "output": "2 / (3 / 4)" },
5757
{ "input": ["divide", ["multiply", 2, 3], 4], "output": "2 * 3 / 4" },
5858
{ "input": ["divide", 2, ["multiply", 3, 4]], "output": "2 / (3 * 4)" },
@@ -62,20 +62,19 @@
6262
"output": "2 / (3 * 4) / (5 * 6)"
6363
},
6464
{ "input": ["multiply", ["divide", 2, 3], 4], "output": "2 / 3 * 4" },
65-
{ "input": ["mod", 2, 3, 4], "output": "2 % 3 % 4" },
66-
{ "input": ["mod", ["mod", 2, 3], 4], "output": "(2 % 3) % 4" },
65+
{ "input": ["mod", ["mod", 2, 3], 4], "output": "2 % 3 % 4" },
6766
{ "input": ["mod", 2, ["mod", 3, 4]], "output": "2 % (3 % 4)" },
6867
{ "input": ["mod", ["multiply", 2, 3], 4], "output": "2 * 3 % 4" },
6968
{ "input": ["multiply", ["mod", 2, 3], 4], "output": "2 % 3 * 4" },
70-
{ "input": ["add", 2, 3, 4], "output": "2 + 3 + 4" },
71-
{ "input": ["add", ["add", 2, 3], 4], "output": "(2 + 3) + 4" },
69+
{ "input": ["add", ["add", 2, 3], 4], "output": "2 + 3 + 4" },
7270
{ "input": ["add", 2, ["add", 3, 4]], "output": "2 + (3 + 4)" },
73-
{ "input": ["subtract", 2, 3, 4], "output": "2 - 3 - 4" },
74-
{ "input": ["subtract", ["subtract", 2, 3], 4], "output": "(2 - 3) - 4" },
71+
{ "input": ["subtract", ["subtract", 2, 3], 4], "output": "2 - 3 - 4" },
7572
{ "input": ["subtract", 2, ["subtract", 3, 4]], "output": "2 - (3 - 4)" },
7673
{ "input": ["subtract", ["add", 2, 3], 4], "output": "2 + 3 - 4" },
7774
{ "input": ["subtract", 2, ["add", 3, 4]], "output": "2 - (3 + 4)" },
78-
{ "input": ["add", ["subtract", 2, 3], 4], "output": "2 - 3 + 4" }
75+
{ "input": ["add", ["subtract", 2, 3], 4], "output": "2 - 3 + 4" },
76+
{ "input": ["eq", ["eq", 2, 3], 4], "output": "(2 == 3) == 4" },
77+
{ "input": ["eq", 2, ["eq", 3, 4]], "output": "2 == (3 == 4)" }
7978
]
8079
},
8180
{
@@ -86,27 +85,29 @@
8685
{ "input": ["multiply", ["pow", 2, 3], 4], "output": "2 ^ 3 * 4" },
8786
{ "input": ["multiply", 2, ["pow", 3, 4]], "output": "2 * 3 ^ 4" },
8887
{ "input": ["pow", 2, ["multiply", 3, 4]], "output": "2 ^ (3 * 4)" },
88+
{ "input": ["pow", ["multiply", 2, 3], 4], "output": "(2 * 3) ^ 4" },
8989
{ "input": ["add", ["multiply", 2, 3], 4], "output": "2 * 3 + 4" },
9090
{ "input": ["add", 2, ["multiply", 3, 4]], "output": "2 + 3 * 4" },
9191
{ "input": ["multiply", 2, ["add", 3, 4]], "output": "2 * (3 + 4)" },
92+
{ "input": ["multiply", ["add", 2, 3], 4], "output": "(2 + 3) * 4" },
9293
{ "input": ["gt", ["add", 2, 3], 4], "output": "2 + 3 > 4" },
94+
{ "input": ["gt", 2, ["add", 3, 4]], "output": "2 > 3 + 4" },
9395
{ "input": ["add", 2, ["gt", 3, 4]], "output": "2 + (3 > 4)" },
96+
{ "input": ["add", ["gt", 2, 3], 4], "output": "(2 > 3) + 4" },
9497
{ "input": ["eq", ["gt", 2, 3], 4], "output": "2 > 3 == 4" },
9598
{ "input": ["gt", 2, ["eq", 3, 4]], "output": "2 > (3 == 4)" },
9699
{ "input": ["and", ["eq", 2, 3], 4], "output": "2 == 3 and 4" },
97100
{ "input": ["eq", 2, ["and", 3, 4]], "output": "2 == (3 and 4)" },
101+
{ "input": ["eq", ["and", 2, 3], 4], "output": "(2 and 3) == 4" },
98102
{ "input": ["or", ["and", 2, 3], 4], "output": "2 and 3 or 4" },
99103
{ "input": ["and", 2, ["or", 3, 4]], "output": "2 and (3 or 4)" },
100104
{ "input": ["and", ["gt", 2, 3], 4], "output": "2 > 3 and 4" },
101-
{ "input": ["gt", 2, ["and", 3, 4]], "output": "2 > (3 and 4)" }
102-
]
103-
},
104-
{
105-
"category": "operator",
106-
"description": "should wrap operators in without vararg support in parenthesis",
107-
"tests": [
108-
{ "input": ["pow", ["pow", 2, 3], 4], "output": "(2 ^ 3) ^ 4" },
109-
{ "input": ["pow", 2, ["pow", 3, 4]], "output": "2 ^ (3 ^ 4)" }
105+
{ "input": ["gt", 2, ["and", 3, 4]], "output": "2 > (3 and 4)" },
106+
{ "input": ["gt", ["and", 2, 3], 4], "output": "(2 and 3) > 4" },
107+
{ "input": ["pipe", ["and", 2, 3], 4], "output": "2 and 3 | 4" },
108+
{ "input": ["pipe", 2, ["and", 3, 4]], "output": "2 | 3 and 4" },
109+
{ "input": ["and", ["pipe", 2, 3], 4], "output": "(2 | 3) and 4" },
110+
{ "input": ["and", 2, ["pipe", 3, 4]], "output": "2 and (3 | 4)" }
110111
]
111112
},
112113
{

0 commit comments

Comments
 (0)