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

TotalTechGeek / json-logic-engine / 12308424092

13 Dec 2024 02:25AM UTC coverage: 92.919% (-0.03%) from 92.947%
12308424092

Pull #39

github

web-flow
Merge 2844d1ffa into d45204af2
Pull Request #39: Separate out the val proposal

866 of 969 branches covered (89.37%)

Branch coverage included in aggregate %.

42 of 44 new or added lines in 1 file covered. (95.45%)

1 existing line in 1 file now uncovered.

853 of 881 relevant lines covered (96.82%)

30107.14 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]
17,082✔
18
  const called = method.asyncMethod ? method.asyncMethod : method.method ? method.method : method
17,082✔
19

20
  if (method.traverse === false) {
17,082✔
21
    if (typeof method[Sync] === 'function' && method[Sync](logic, { engine })) {
3,768✔
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,590✔
27
    return (data, abv) => called(args, data, abv || above, engine)
1,758✔
28
  }
29

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

33
  if (Array.isArray(args)) {
13,314✔
34
    const optimizedArgs = args.map(l => optimize(l, engine, above))
23,670✔
35

36
    if (isSync(optimizedArgs) && (method.method || method[Sync])) {
13,116✔
37
      const called = method.method ? method.method : method
13,062✔
38
      return declareSync((data, abv) => {
13,062✔
39
        const evaluatedArgs = optimizedArgs.map(l => typeof l === 'function' ? l(data, abv) : l)
26,724✔
40
        return called(evaluatedArgs, data, abv || above, engine.fallback)
15,258✔
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
42,198✔
71
  if (Array.isArray(logic)) {
42,198✔
72
    const arr = logic.map(l => optimize(l, engine, above))
2,016✔
73
    if (isSync(arr)) return declareSync((data, abv) => arr.map(l => typeof l === 'function' ? l(data, abv) : l), true)
2,136✔
74
    return async (data, abv) => map(arr, l => typeof l === 'function' ? l(data, abv) : l)
24!
75
  };
76

77
  if (logic && typeof logic === 'object') {
41,118✔
78
    const keys = Object.keys(logic)
17,106✔
79
    const methodName = keys[0]
17,106✔
80

81
    const isData = engine.isData(logic, methodName)
17,106✔
82
    if (isData) return () => logic
17,106✔
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 })
17,094✔
87

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

93
        if (isSync(result)) {
9,690✔
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 () => {
666✔
103
          if (!computed) computed = await result()
1,158✔
104
          return computed
1,158✔
105
        }
106
      }
107
      return result
7,392✔
108
    }
109
  }
110

111
  return logic
24,018✔
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