Skip to content

Commit 8808be0

Browse files
committed
Implement an "above" optimization.
1 parent 39b8bc7 commit 8808be0

File tree

3 files changed

+26
-16
lines changed

3 files changed

+26
-16
lines changed

defaultMethods.js

+21-15
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ const defaultMethods = {
217217
) {
218218
context = above[iter++]
219219
key = key.substring(3)
220+
// A performance optimization that allows you to pass the previous above array without spreading it as the last argument
221+
if (iter === above.length && Array.isArray(context)) {
222+
iter = 0
223+
above = context
224+
context = above[iter++]
225+
}
220226
}
221227

222228
const notFound = b === undefined ? null : b
@@ -311,21 +317,21 @@ const defaultMethods = {
311317
if (typeof defaultValue !== 'undefined') {
312318
return `await asyncIterators.reduce(${selector} || [], (a,b) => methods[${
313319
buildState.methods.length - 1
314-
}]({ accumulator: a, current: b }, [null, context, ...above]), ${defaultValue})`
320+
}]({ accumulator: a, current: b }, [null, context, above]), ${defaultValue})`
315321
}
316322
return `await asyncIterators.reduce(${selector} || [], (a,b) => methods[${
317323
buildState.methods.length - 1
318-
}]({ accumulator: a, current: b }, [null, context, ...above]))`
324+
}]({ accumulator: a, current: b }, [null, context, above]))`
319325
}
320326
}
321327
if (typeof defaultValue !== 'undefined') {
322328
return `(${selector} || []).reduce((a,b) => methods[${
323329
buildState.methods.length - 1
324-
}]({ accumulator: a, current: b }, [null, context, ...above]), ${defaultValue})`
330+
}]({ accumulator: a, current: b }, [null, context, above]), ${defaultValue})`
325331
}
326332
return `(${selector} || []).reduce((a,b) => methods[${
327333
buildState.methods.length - 1
328-
}]({ accumulator: a, current: b }, [null, context, ...above]))`
334+
}]({ accumulator: a, current: b }, [null, context, above]))`
329335
},
330336
method: (input, context, above, engine) => {
331337
if (!Array.isArray(input)) throw new InvalidControlInput(input)
@@ -345,7 +351,7 @@ const defaultMethods = {
345351
current
346352
},
347353
{
348-
above: [selector, context, ...above]
354+
above: [selector, context, above]
349355
}
350356
)
351357
}
@@ -375,7 +381,7 @@ const defaultMethods = {
375381
current
376382
},
377383
{
378-
above: [selector, context, ...above]
384+
above: [selector, context, above]
379385
}
380386
)
381387
},
@@ -398,19 +404,19 @@ const defaultMethods = {
398404
[Sync]: (data, buildState) => isSyncDeep(data, buildState.engine, buildState),
399405
method: (args, context, above, engine) => {
400406
if (!Array.isArray(args)) throw new Error('Data for pipe must be an array')
401-
let answer = engine.run(args[0], context, { above: [args, context, ...above] })
402-
for (let i = 1; i < args.length; i++) answer = engine.run(args[i], answer, { above: [args, context, ...above] })
407+
let answer = engine.run(args[0], context, { above: [args, context, above] })
408+
for (let i = 1; i < args.length; i++) answer = engine.run(args[i], answer, { above: [args, context, above] })
403409
return answer
404410
},
405411
asyncMethod: async (args, context, above, engine) => {
406412
if (!Array.isArray(args)) throw new Error('Data for pipe must be an array')
407-
let answer = await engine.run(args[0], context, { above: [args, context, ...above] })
408-
for (let i = 1; i < args.length; i++) answer = await engine.run(args[i], answer, { above: [args, context, ...above] })
413+
let answer = await engine.run(args[0], context, { above: [args, context, above] })
414+
for (let i = 1; i < args.length; i++) answer = await engine.run(args[i], answer, { above: [args, context, above] })
409415
return answer
410416
},
411417
compile: (args, buildState) => {
412418
let res = buildState.compile`${args[0]}`
413-
for (let i = 1; i < args.length; i++) res = buildState.compile`${build(args[i], { ...buildState, extraArguments: 'above' })}(${res}, [null, context, ...above])`
419+
for (let i = 1; i < args.length; i++) res = buildState.compile`${build(args[i], { ...buildState, extraArguments: 'above' })}(${res}, [null, context, above])`
414420
return res
415421
},
416422
deterministic: (data, buildState) => {
@@ -499,7 +505,7 @@ function createArrayIterativeMethod (name, useTruthy = false) {
499505

500506
return selector[name]((i, index) => {
501507
const result = engine.run(mapper, i, {
502-
above: [{ item: selector, index }, context, ...above]
508+
above: [{ item: selector, index }, context, above]
503509
})
504510
return useTruthy ? engine.truthy(result) : result
505511
})
@@ -513,7 +519,7 @@ function createArrayIterativeMethod (name, useTruthy = false) {
513519
})) || []
514520
return asyncIterators[name](selector, (i, index) => {
515521
const result = engine.run(mapper, i, {
516-
above: [{ item: selector, index }, context, ...above]
522+
above: [{ item: selector, index }, context, above]
517523
})
518524
return useTruthy ? engine.truthy(result) : result
519525
})
@@ -533,11 +539,11 @@ function createArrayIterativeMethod (name, useTruthy = false) {
533539
if (async) {
534540
if (!isSyncDeep(mapper, buildState.engine, buildState)) {
535541
buildState.detectAsync = true
536-
return buildState.compile`await asyncIterators[${name}](${selector} || [], async (i, x) => ${build(mapper, mapState)}(i, x, [{ item: null }, context, ...above]))`
542+
return buildState.compile`await asyncIterators[${name}](${selector} || [], async (i, x) => ${build(mapper, mapState)}(i, x, [{ item: null }, context, above]))`
537543
}
538544
}
539545

540-
return buildState.compile`(${selector} || [])[${name}]((i, x) => ${build(mapper, mapState)}(i, x, [{ item: null }, context, ...above]))`
546+
return buildState.compile`(${selector} || [])[${name}]((i, x) => ${build(mapper, mapState)}(i, x, [{ item: null }, context, above]))`
541547
},
542548
traverse: false
543549
}

general.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ describe('Various Test Cases', () => {
178178
}
179179
})
180180

181+
it('is able to reach far up in the traversal', async () => {
182+
for (const engine of [...normalEngines, ...permissiveEngines]) await testEngine(engine, { map: [[1, 2, 3], { map: [[1], { var: '../../../../name' }] }] }, { name: 'Bob' }, [['Bob'], ['Bob'], ['Bob']])
183+
})
184+
181185
it('disables interpreted optimization when it realizes it will not be faster', async () => {
182186
for (const engine of [...normalEngines, ...permissiveEngines]) {
183187
const disableInterpretedOptimization = engine.disableInterpretedOptimization

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "json-logic-engine",
3-
"version": "3.0.3",
3+
"version": "3.0.4",
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)