Skip to content

Commit 155f810

Browse files
Merge pull request #41 from json-logic/proposal/arithmetic
Add tests for the arithmetic proposal
2 parents 77c4a72 + 414bdb7 commit 155f810

9 files changed

+781
-33
lines changed

compatible.test.js

+22-16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ for (const file of files) {
1313
}
1414
}
1515

16+
function correction (x) {
17+
// eslint-disable-next-line no-compare-neg-zero
18+
if (x === -0) return 0
19+
return x
20+
}
21+
1622
// eslint-disable-next-line no-labels
1723
inline: {
1824
const logic = new LogicEngine(undefined, { compatible: true })
@@ -25,13 +31,13 @@ inline: {
2531
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
2632
testCase[1]
2733
)}`, () => {
28-
expect(logic.run(testCase[0], testCase[1])).toStrictEqual(testCase[2])
34+
expect(correction(logic.run(testCase[0], testCase[1]))).toStrictEqual(testCase[2])
2935
})
3036

3137
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
3238
testCase[1]
3339
)} (async)`, async () => {
34-
expect(await asyncLogic.run(testCase[0], testCase[1])).toStrictEqual(
40+
expect(correction(await asyncLogic.run(testCase[0], testCase[1]))).toStrictEqual(
3541
testCase[2]
3642
)
3743
})
@@ -40,26 +46,26 @@ inline: {
4046
testCase[1]
4147
)} (built)`, () => {
4248
const f = logic.build(testCase[0])
43-
expect(f(testCase[1])).toStrictEqual(testCase[2])
49+
expect(correction(f(testCase[1]))).toStrictEqual(testCase[2])
4450
})
4551

4652
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
4753
testCase[1]
4854
)} (asyncBuilt)`, async () => {
4955
const f = await asyncLogic.build(testCase[0])
50-
expect(await f(testCase[1])).toStrictEqual(testCase[2])
56+
expect(correction(await f(testCase[1]))).toStrictEqual(testCase[2])
5157
})
5258

5359
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
5460
testCase[1]
5561
)} (noOptimization)`, () => {
56-
expect(logicWithoutOptimization.run(testCase[0], testCase[1])).toStrictEqual(testCase[2])
62+
expect(correction(logicWithoutOptimization.run(testCase[0], testCase[1]))).toStrictEqual(testCase[2])
5763
})
5864

5965
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
6066
testCase[1]
6167
)} (asyncNoOptimization)`, async () => {
62-
expect(await asyncLogicWithoutOptimization.run(testCase[0], testCase[1])).toStrictEqual(
68+
expect(correction(await asyncLogicWithoutOptimization.run(testCase[0], testCase[1]))).toStrictEqual(
6369
testCase[2]
6470
)
6571
})
@@ -68,14 +74,14 @@ inline: {
6874
testCase[1]
6975
)} (builtNoOptimization)`, () => {
7076
const f = logicWithoutOptimization.build(testCase[0])
71-
expect(f(testCase[1])).toStrictEqual(testCase[2])
77+
expect(correction(f(testCase[1]))).toStrictEqual(testCase[2])
7278
})
7379

7480
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
7581
testCase[1]
7682
)} (asyncBuiltNoOptimization)`, async () => {
7783
const f = await asyncLogicWithoutOptimization.build(testCase[0])
78-
expect(await f(testCase[1])).toStrictEqual(testCase[2])
84+
expect(correction(await f(testCase[1]))).toStrictEqual(testCase[2])
7985
})
8086
})
8187
})
@@ -97,13 +103,13 @@ notInline: {
97103
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
98104
testCase[1]
99105
)}`, () => {
100-
expect(logic.run(testCase[0], testCase[1])).toStrictEqual(testCase[2])
106+
expect(correction(logic.run(testCase[0], testCase[1]))).toStrictEqual(testCase[2])
101107
})
102108

103109
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
104110
testCase[1]
105111
)} (async)`, async () => {
106-
expect(await asyncLogic.run(testCase[0], testCase[1])).toStrictEqual(
112+
expect(correction(await asyncLogic.run(testCase[0], testCase[1]))).toStrictEqual(
107113
testCase[2]
108114
)
109115
})
@@ -112,26 +118,26 @@ notInline: {
112118
testCase[1]
113119
)} (built)`, () => {
114120
const f = logic.build(testCase[0])
115-
expect(f(testCase[1])).toStrictEqual(testCase[2])
121+
expect(correction(f(testCase[1]))).toStrictEqual(testCase[2])
116122
})
117123

118124
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
119125
testCase[1]
120126
)} (asyncBuilt)`, async () => {
121127
const f = await asyncLogic.build(testCase[0])
122-
expect(await f(testCase[1])).toStrictEqual(testCase[2])
128+
expect(correction(await f(testCase[1]))).toStrictEqual(testCase[2])
123129
})
124130

125131
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
126132
testCase[1]
127133
)} (noOptimization)`, () => {
128-
expect(logicWithoutOptimization.run(testCase[0], testCase[1])).toStrictEqual(testCase[2])
134+
expect(correction(logicWithoutOptimization.run(testCase[0], testCase[1]))).toStrictEqual(testCase[2])
129135
})
130136

131137
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
132138
testCase[1]
133139
)} (asyncNoOptimization)`, async () => {
134-
expect(await asyncLogicWithoutOptimization.run(testCase[0], testCase[1])).toStrictEqual(
140+
expect(correction(await asyncLogicWithoutOptimization.run(testCase[0], testCase[1]))).toStrictEqual(
135141
testCase[2]
136142
)
137143
})
@@ -140,14 +146,14 @@ notInline: {
140146
testCase[1]
141147
)} (builtNoOptimization)`, () => {
142148
const f = logicWithoutOptimization.build(testCase[0])
143-
expect(f(testCase[1])).toStrictEqual(testCase[2])
149+
expect(correction(f(testCase[1]))).toStrictEqual(testCase[2])
144150
})
145151

146152
test(`${JSON.stringify(testCase[0])} ${JSON.stringify(
147153
testCase[1]
148154
)} (asyncBuiltNoOptimization)`, async () => {
149155
const f = await asyncLogicWithoutOptimization.build(testCase[0])
150-
expect(await f(testCase[1])).toStrictEqual(testCase[2])
156+
expect(correction(await f(testCase[1]))).toStrictEqual(testCase[2])
151157
})
152158
})
153159
}

compiler.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ function isDeepSync (method, engine) {
112112

113113
if (Array.isArray(method)) return method.every(i => isDeepSync(i, engine))
114114

115-
if (typeof method === 'object') {
115+
if (method && typeof method === 'object') {
116116
const func = Object.keys(method)[0]
117117

118118
const lower = method[func]
@@ -307,7 +307,7 @@ function processBuiltString (method, str, buildState) {
307307
str = str.replace(`__%%%${x}%%%__`, item)
308308
})
309309

310-
const final = `(values, methods, notTraversed, asyncIterators, engine, above, coerceArray) => ${buildState.asyncDetected ? 'async' : ''} (context ${buildState.extraArguments ? ',' + buildState.extraArguments : ''}) => { const result = ${str}; return result }`
310+
const final = `(values, methods, notTraversed, asyncIterators, engine, above, coerceArray) => ${buildState.asyncDetected ? 'async' : ''} (context ${buildState.extraArguments ? ',' + buildState.extraArguments : ''}) => { let prev; const result = ${str}; return result }`
311311
// console.log(str)
312312
// console.log(final)
313313
// eslint-disable-next-line no-eval

defaultMethods.js

+30-15
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ function isSyncDeep (method, engine, buildState) {
5252

5353
const defaultMethods = {
5454
'+': (data) => {
55+
if (!data) return 0
5556
if (typeof data === 'string') return +data
5657
if (typeof data === 'number') return +data
58+
if (typeof data === 'boolean') return +data
5759
let res = 0
5860
for (let i = 0; i < data.length; i++) res += +data[i]
5961
return res
@@ -64,20 +66,22 @@ const defaultMethods = {
6466
return res
6567
},
6668
'/': (data) => {
67-
let res = data[0]
69+
let res = +data[0]
6870
for (let i = 1; i < data.length; i++) res /= +data[i]
6971
return res
7072
},
7173
'-': (data) => {
74+
if (!data) return 0
7275
if (typeof data === 'string') return -data
7376
if (typeof data === 'number') return -data
77+
if (typeof data === 'boolean') return -data
7478
if (data.length === 1) return -data[0]
7579
let res = data[0]
7680
for (let i = 1; i < data.length; i++) res -= +data[i]
7781
return res
7882
},
7983
'%': (data) => {
80-
let res = data[0]
84+
let res = +data[0]
8185
for (let i = 1; i < data.length; i++) res %= +data[i]
8286
return res
8387
},
@@ -446,7 +450,18 @@ const defaultMethods = {
446450
return result ? buildState.compile`!(${result})` : false
447451
}
448452
},
449-
merge: (arrays) => (Array.isArray(arrays) ? [].concat(...arrays) : [arrays]),
453+
merge: (args) => {
454+
if (!Array.isArray(args)) return [args]
455+
const result = []
456+
for (let i = 0; i < args.length; i++) {
457+
if (Array.isArray(args[i])) {
458+
for (let j = 0; j < args[i].length; j++) {
459+
result.push(args[i][j])
460+
}
461+
} else result.push(args[i])
462+
}
463+
return result
464+
},
450465
every: createArrayIterativeMethod('every'),
451466
filter: createArrayIterativeMethod('filter', true),
452467
reduce: {
@@ -752,16 +767,16 @@ Object.keys(defaultMethods).forEach((item) => {
752767
defaultMethods['<'].compile = function (data, buildState) {
753768
if (!Array.isArray(data)) return false
754769
if (data.length < 2) return false
755-
let res = buildState.compile`(${data[0]} < ${data[1]})`
756-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} < ${data[i]})`
770+
let res = buildState.compile`(${data[0]} < (prev = ${data[1]}))`
771+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev < ${data[i]})`
757772
return res
758773
}
759774
// @ts-ignore Allow custom attribute
760775
defaultMethods['<='].compile = function (data, buildState) {
761776
if (!Array.isArray(data)) return false
762777
if (data.length < 2) return false
763-
let res = buildState.compile`(${data[0]} <= ${data[1]})`
764-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} <= ${data[i]})`
778+
let res = buildState.compile`(${data[0]} <= (prev = ${data[1]}))`
779+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev <= ${data[i]})`
765780
return res
766781
}
767782
// @ts-ignore Allow custom attribute
@@ -782,32 +797,32 @@ defaultMethods.max.compile = function (data, buildState) {
782797
defaultMethods['>'].compile = function (data, buildState) {
783798
if (!Array.isArray(data)) return false
784799
if (data.length < 2) return false
785-
let res = buildState.compile`(${data[0]} > ${data[1]})`
786-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} > ${data[i]})`
800+
let res = buildState.compile`(${data[0]} > (prev = ${data[1]}))`
801+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev > ${data[i]})`
787802
return res
788803
}
789804
// @ts-ignore Allow custom attribute
790805
defaultMethods['>='].compile = function (data, buildState) {
791806
if (!Array.isArray(data)) return false
792807
if (data.length < 2) return false
793-
let res = buildState.compile`(${data[0]} >= ${data[1]})`
794-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} >= ${data[i]})`
808+
let res = buildState.compile`(${data[0]} >= (prev = ${data[1]}))`
809+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev >= ${data[i]})`
795810
return res
796811
}
797812
// @ts-ignore Allow custom attribute
798813
defaultMethods['=='].compile = function (data, buildState) {
799814
if (!Array.isArray(data)) return false
800815
if (data.length < 2) return false
801-
let res = buildState.compile`(${data[0]} == ${data[1]})`
802-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} == ${data[i]})`
816+
let res = buildState.compile`(${data[0]} == (prev = ${data[1]}))`
817+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev == ${data[i]})`
803818
return res
804819
}
805820
// @ts-ignore Allow custom attribute
806821
defaultMethods['!='].compile = function (data, buildState) {
807822
if (!Array.isArray(data)) return false
808823
if (data.length < 2) return false
809-
let res = buildState.compile`(${data[0]} != ${data[1]})`
810-
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && ${data[i - 1]} != ${data[i]})`
824+
let res = buildState.compile`(${data[0]} != (prev = ${data[1]}))`
825+
for (let i = 2; i < data.length; i++) res = buildState.compile`(${res} && prev != ${data[i]})`
811826
return res
812827
}
813828
// @ts-ignore Allow custom attribute

suites/chained.json

+6
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,11 @@
5858
},
5959
"result": 149212,
6060
"description": "Max with Logic Chaining (Complex)"
61+
},
62+
{
63+
"description": "Addition Chained w/ Merge",
64+
"rule": { "+": { "merge": [{ "val": "x" }, { "val": "y" }] }},
65+
"result": 6,
66+
"data": { "x": [1, 2], "y": 3 }
6167
}
6268
]

0 commit comments

Comments
 (0)