• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TotalTechGeek / json-logic-engine / 12308415913

13 Dec 2024 02:24AM UTC coverage: 92.947% (+0.7%) from 92.254%
12308415913

push

github

TotalTechGeek
Add access to iterator values

811 of 907 branches covered (89.42%)

Branch coverage included in aggregate %.

7 of 7 new or added lines in 2 files covered. (100.0%)

21 existing lines in 1 file now uncovered.

810 of 837 relevant lines covered (96.77%)

31455.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.53
/async_optimizer.js
1
// This is the synchronous version of the optimizer; which the Async one should be based on.
2
import { isDeterministic } from './compiler.js'
3
import { map } from './async_iterators.js'
4
import { isSync, Sync } from './constants.js'
5
import declareSync from './utilities/declareSync.js'
6
import { coerceArray } from './utilities/coerceArray.js'
7

8
/**
9
 * Turns an expression like { '+': [1, 2] } into a function that can be called with data.
10
 * @param {*} logic
11
 * @param {*} engine
12
 * @param {string} methodName
13
 * @param {any[]} above
14
 * @returns A method that can be called to execute the logic.
15
 */
16
function getMethod (logic, engine, methodName, above) {
17
  const method = engine.methods[methodName]
16,482✔
18
  const called = method.asyncMethod ? method.asyncMethod : method.method ? method.method : method
16,482✔
19

20
  if (method.traverse === false) {
16,482✔
21
    if (typeof method[Sync] === 'function' && method[Sync](logic, { engine })) {
3,624✔
22
      const called = method.method ? method.method : method
2,178!
23
      return declareSync((data, abv) => called(logic[methodName], data, abv || above, engine.fallback), true)
2,178✔
24
    }
25

26
    const args = logic[methodName]
1,446✔
27
    return (data, abv) => called(args, data, abv || above, engine)
1,614✔
28
  }
29

30
  let args = logic[methodName]
12,858✔
31
  if (!args || typeof args !== 'object') args = [args]
12,858✔
32

33
  if (Array.isArray(args)) {
12,858✔
34
    const optimizedArgs = args.map(l => optimize(l, engine, above))
22,950✔
35

36
    if (isSync(optimizedArgs) && (method.method || method[Sync])) {
12,660✔
37
      const called = method.method ? method.method : method
12,606✔
38
      return declareSync((data, abv) => {
12,606✔
39
        const evaluatedArgs = optimizedArgs.map(l => typeof l === 'function' ? l(data, abv) : l)
24,996✔
40
        return called(evaluatedArgs, data, abv || above, engine.fallback)
14,178✔
41
      }, true)
42
    }
43

44
    return async (data, abv) => {
54✔
45
      const evaluatedArgs = await map(optimizedArgs, l => typeof l === 'function' ? l(data, abv) : l)
78✔
46
      return called(evaluatedArgs, data, abv || above, engine)
54✔
47
    }
48
  } else {
49
    const optimizedArgs = optimize(args, engine, above)
198✔
50

51
    if (isSync(optimizedArgs) && (method.method || method[Sync])) {
198✔
52
      const called = method.method ? method.method : method
174!
53
      return declareSync((data, abv) => called(coerceArray(typeof optimizedArgs === 'function' ? optimizedArgs(data, abv) : optimizedArgs, method.optimizeUnary), data, abv || above, engine), true)
174!
54
    }
55

56
    return async (data, abv) => {
24✔
57
      return called(coerceArray(typeof optimizedArgs === 'function' ? await optimizedArgs(data, abv) : optimizedArgs, method.optimizeUnary), data, abv || above, engine)
48!
58
    }
59
  }
60
}
61

62
/**
63
 * Processes the logic for the engine once so that it doesn't need to be traversed again.
64
 * @param {*} logic
65
 * @param {*} engine
66
 * @param {any[]} above
67
 * @returns A function that optimizes the logic for the engine in advance.
68
 */
69
export function optimize (logic, engine, above = []) {
×
70
  engine.fallback.allowFunctions = engine.allowFunctions
40,470✔
71
  if (Array.isArray(logic)) {
40,470✔
72
    const arr = logic.map(l => optimize(l, engine, above))
1,560✔
73
    if (isSync(arr)) return declareSync((data, abv) => arr.map(l => typeof l === 'function' ? l(data, abv) : l), true)
1,536✔
74
    return async (data, abv) => map(arr, l => typeof l === 'function' ? l(data, abv) : l)
24!
75
  };
76

77
  if (logic && typeof logic === 'object') {
39,606✔
78
    const keys = Object.keys(logic)
16,506✔
79
    const methodName = keys[0]
16,506✔
80

81
    const isData = engine.isData(logic, methodName)
16,506✔
82
    if (isData) return () => logic
16,506✔
83

84
    // If we have a deterministic function, we can just return the result of the evaluation,
85
    // basically inlining the operation.
86
    const deterministic = !engine.disableInline && isDeterministic(logic, engine, { engine })
16,494✔
87

88
    if (methodName in engine.methods) {
16,488✔
89
      const result = getMethod(logic, engine, methodName, above)
16,482✔
90
      if (deterministic) {
16,482✔
91
        let computed
92

93
        if (isSync(result)) {
9,654✔
94
          return declareSync(() => {
9,024✔
95
            if (!computed) computed = result()
9,060✔
96
            return computed
9,048✔
97
          }, true)
98
        }
99

100
        // For async, it's a little less straightforward since it could be a promise,
101
        // so we'll make it a closure.
102
        return async () => {
630✔
103
          if (!computed) computed = await result()
1,086✔
104
          return computed
1,086✔
105
        }
106
      }
107
      return result
6,828✔
108
    }
109
  }
110

111
  return logic
23,106✔
112
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc