Skip to content

Commit d8d40cf

Browse files
committed
Add one additional optimization to the async optimizer to allow for async optimizations on traverse: false w/ async method defs
1 parent 9ea3eb1 commit d8d40cf

File tree

5 files changed

+41
-13
lines changed

5 files changed

+41
-13
lines changed

asyncLogic.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import defaultMethods from './defaultMethods.js'
55
import LogicEngine from './logic.js'
66
import asyncPool from './asyncPool.js'
7-
import { Sync, isSync } from './constants.js'
7+
import { isSync } from './constants.js'
88
import declareSync from './utilities/declareSync.js'
99
import { buildAsync } from './compiler.js'
1010
import omitUndefined from './utilities/omitUndefined.js'

async_optimizer.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ function getMethod (logic, engine, methodName, above) {
1616
const method = engine.methods[methodName]
1717
const called = method.asyncMethod ? method.asyncMethod : method.method ? method.method : method
1818

19-
// Todo: Like "deterministic", we should add "sync" to the method object to determine if the structure can be run synchronously.
2019
if (method.traverse === false) {
20+
if (typeof method[Sync] === 'function' && method[Sync](logic, { engine })) {
21+
const called = method.method ? method.method : method
22+
return declareSync((data, abv) => called(logic[methodName], data, abv || above, engine), true)
23+
}
24+
2125
const args = logic[methodName]
2226
return (data, abv) => called(args, data, abv || above, engine)
2327
}

defaultMethods.js

+30-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ function isDeterministic (method, engine, buildState) {
3333
return true
3434
}
3535

36+
function isSyncDeep (method, engine, buildState) {
37+
if (Array.isArray(method)) {
38+
return method.every((i) => isSyncDeep(i, engine, buildState))
39+
}
40+
41+
if (method && typeof method === 'object') {
42+
const func = Object.keys(method)[0]
43+
const lower = method[func]
44+
if (engine.isData(method, func)) return true
45+
if (!engine.methods[func]) throw new Error(`Method '${func}' was not found in the Logic Engine.`)
46+
if (engine.methods[func].traverse === false) return typeof engine.methods[func][Sync] === 'function' ? engine.methods[func][Sync](lower, buildState) : engine.methods[func][Sync]
47+
return typeof engine.methods[func][Sync] === 'function' ? engine.methods[func][Sync](lower, buildState) : engine.methods[func][Sync] && isSyncDeep(lower, engine, buildState)
48+
}
49+
50+
return true
51+
}
52+
3653
const defaultMethods = {
3754
'+': (data) => {
3855
if (typeof data === 'string') return +data
@@ -77,7 +94,7 @@ const defaultMethods = {
7794
method: (input, context, above, engine) => {
7895
if (!Array.isArray(input)) throw new InvalidControlInput(input)
7996

80-
if (input.length === 1) return engine.run(input[0], context, { above })
97+
if (input.length === 1) return (engine.fallback || engine).run(input[0], context, { above })
8198
if (input.length < 2) return null
8299

83100
input = [...input]
@@ -91,14 +108,15 @@ const defaultMethods = {
91108
const check = input.shift()
92109
const onTrue = input.shift()
93110

94-
const test = engine.run(check, context, { above })
111+
const test = (engine.fallback || engine).run(check, context, { above })
95112

96113
// if the condition is true, run the true branch
97-
if (engine.truthy(test)) return engine.run(onTrue, context, { above })
114+
if (engine.truthy(test)) return (engine.fallback || engine).run(onTrue, context, { above })
98115
}
99116

100-
return engine.run(onFalse, context, { above })
117+
return (engine.fallback || engine).run(onFalse, context, { above })
101118
},
119+
[Sync]: (data, buildState) => isSyncDeep(data, buildState.engine, buildState),
102120
deterministic: (data, buildState) => {
103121
return isDeterministic(data, buildState.engine, buildState)
104122
},
@@ -316,15 +334,15 @@ const defaultMethods = {
316334
method: (input, context, above, engine) => {
317335
if (!Array.isArray(input)) throw new InvalidControlInput(input)
318336
let [selector, mapper, defaultValue] = input
319-
defaultValue = engine.run(defaultValue, context, {
337+
defaultValue = (engine.fallback || engine).run(defaultValue, context, {
320338
above
321339
})
322340
selector =
323-
engine.run(selector, context, {
341+
(engine.fallback || engine).run(selector, context, {
324342
above
325343
}) || []
326344
const func = (accumulator, current) => {
327-
return engine.run(
345+
return (engine.fallback || engine).run(
328346
mapper,
329347
{
330348
accumulator,
@@ -340,6 +358,7 @@ const defaultMethods = {
340358
}
341359
return selector.reduce(func, defaultValue)
342360
},
361+
[Sync]: (data, buildState) => isSyncDeep(data, buildState.engine, buildState),
343362
asyncMethod: async (input, context, above, engine) => {
344363
if (!Array.isArray(input)) throw new InvalidControlInput(input)
345364
let [selector, mapper, defaultValue] = input
@@ -385,7 +404,7 @@ const defaultMethods = {
385404
const item = object[key]
386405
Object.defineProperty(accumulator, key, {
387406
enumerable: true,
388-
value: engine.run(item, context, { above })
407+
value: (engine.fallback || engine).run(item, context, { above })
389408
})
390409
return accumulator
391410
}, {})
@@ -445,16 +464,17 @@ function createArrayIterativeMethod (name, useTruthy = false) {
445464
})
446465
)
447466
},
467+
[Sync]: (data, buildState) => isSyncDeep(data, buildState.engine, buildState),
448468
method: (input, context, above, engine) => {
449469
if (!Array.isArray(input)) throw new InvalidControlInput(input)
450470
let [selector, mapper] = input
451471
selector =
452-
engine.run(selector, context, {
472+
(engine.fallback || engine).run(selector, context, {
453473
above
454474
}) || []
455475

456476
return selector[name]((i, index) => {
457-
const result = engine.run(mapper, i, {
477+
const result = (engine.fallback || engine).run(mapper, i, {
458478
above: [{ item: selector, index }, context, ...above]
459479
})
460480
return useTruthy ? engine.truthy(result) : result

general.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ describe('Various Test Cases', () => {
8282
for (const engine of permissiveEngines) await testEngine(engine, {}, {}, {})
8383
})
8484

85+
it('Should work with preserve', async () => {
86+
for (const engine of [...permissiveEngines, ...normalEngines]) await testEngine(engine, { preserve: { x: 5 } }, null, { x: 5 })
87+
})
88+
8589
it('Should return the object when an unrecognized method is used.', async () => {
8690
for (const engine of permissiveEngines) {
8791
await testEngine(engine, { unknown: true }, {}, { unknown: true })

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "json-logic-engine",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "Construct complex rules with JSON & process them.",
55
"main": "./dist/cjs/index.js",
66
"module": "./dist/esm/index.js",

0 commit comments

Comments
 (0)