Skip to content

Commit 95936f5

Browse files
authored
Merge branch 'json-logic:master' into master
2 parents 2d8e1eb + 9605498 commit 95936f5

File tree

5 files changed

+63
-11
lines changed

5 files changed

+63
-11
lines changed

asyncLogic.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,16 @@ class AsyncLogicEngine {
5656
*/
5757
truthy (value) {
5858
if (!value) return value
59-
if (Array.isArray(value) && value.length === 0) return false
60-
// Uncomment the following line to switch empty object to falsy.
61-
// if (value && typeof value === 'object') return Object.keys(value).length > 0
59+
// The following check could be erased, as it'd be caught by the iterator check,
60+
// but it's here for performance reasons.
61+
if (Array.isArray(value)) return value.length > 0
62+
if (typeof value === 'object') {
63+
if (value[Symbol.iterator]) {
64+
if ('length' in value && value.length === 0) return false
65+
if ('size' in value && value.size === 0) return false
66+
}
67+
if (value.constructor.name === 'Object') return Object.keys(value).length > 0
68+
}
6269
return value
6370
}
6471

general.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,32 @@ describe('Various Test Cases', () => {
153153
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { max: 5 }, {}, 5)
154154
})
155155

156+
it('sees empty structures as false', async () => {
157+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: {} }, false)
158+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: [] }, false)
159+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new Map() }, false)
160+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new Set() }, false)
161+
})
162+
163+
it('sees filled structures as true', async () => {
164+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: { a: 1 } }, true)
165+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: [1] }, true)
166+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new Map([[1, 'a']]) }, true)
167+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new Set([1]) }, true)
168+
})
169+
170+
it('sees classes as true', async () => {
171+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new Date() }, true)
172+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: new RegExp() }, true)
173+
174+
class Empty {}
175+
const empty = new Empty()
176+
177+
assert.strictEqual(Object.keys(empty).length, 0, 'Should have no keys')
178+
179+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { if: [{ var: 'x' }, true, false] }, { x: empty }, true)
180+
})
181+
156182
it('is able to handle path escaping in a var call', async () => {
157183
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { var: 'hello\\.world' }, { 'hello.world': 2 }, 2)
158184
})

logic.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ class LogicEngine {
4747
*/
4848
truthy (value) {
4949
if (!value) return value
50-
if (Array.isArray(value) && value.length === 0) return false
51-
// Uncomment the following line to switch empty object to falsy.
52-
// if (typeof value === 'object') return Object.keys(value).length > 0
50+
// The following check could be erased, as it'd be caught by the iterator check,
51+
// but it's here for performance reasons.
52+
if (Array.isArray(value)) return value.length > 0
53+
if (typeof value === 'object') {
54+
if (value[Symbol.iterator]) {
55+
if ('length' in value && value.length === 0) return false
56+
if ('size' in value && value.size === 0) return false
57+
}
58+
if (value.constructor.name === 'Object') return Object.keys(value).length > 0
59+
}
5360
return value
5461
}
5562

suites/control/if.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
},
2222
"Object checks",
2323
{
24-
"description": "Objects are always truthy, even without keys.",
24+
"description": "Empty object is falsy.",
2525
"rule": { "if": [{}, "apple", "banana"] },
2626
"data": null,
27-
"result": "apple"
27+
"result": "banana"
2828
},
2929
{
30-
"description": "Objects are always truthy, with keys defined",
30+
"description": "Objects are truthy, with keys defined",
3131
"rule": { "if": [{ "val": [] }, "apple", "banana"] },
3232
"data": { "some": "value" },
3333
"result": "apple"
@@ -240,6 +240,12 @@
240240
"description": "Returns first truthy value, some conditions truthy (8)",
241241
"rule": { "if": [{}, "apple", 0, "banana", 7, "carrot", "date"] },
242242
"data": null,
243+
"result": "carrot"
244+
},
245+
{
246+
"description": "Returns first truthy value, some conditions truthy (9)",
247+
"rule": { "if": [{ "val": "a" }, "apple", 0, "banana", 7, "carrot", "date"] },
248+
"data": { "a": { "b": 1 } },
243249
"result": "apple"
244250
},
245251
"Bad Arguments",

suites/truthiness.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,16 @@
3737
"result": false,
3838
"data": null
3939
},
40+
{
41+
"description": "Truthy: {}, Direct",
42+
"rule": { "!!": {} },
43+
"result": false,
44+
"data": null
45+
},
4046
{
4147
"description": "Truthy: {}",
4248
"rule": { "!!": [{}] },
43-
"result": true,
49+
"result": false,
4450
"data": null
4551
},
4652
{
@@ -59,7 +65,7 @@
5965
{
6066
"description": "Truthy: Zero Key Object",
6167
"rule": { "!!": { "val": "obj" } },
62-
"result": true,
68+
"result": false,
6369
"data": { "obj": {} }
6470
},
6571
{

0 commit comments

Comments
 (0)