UNPKG

2.91 kBJavaScriptView Raw
1import _ from 'lodash';
2import context from './context';
3import { decide as decideV1 } from './interpreter_v1';
4import parse from './parse';
5import { reduceDecisionRules } from './reducer';
6import semver from 'semver';
7import { CraftAiDecisionError, CraftAiNullDecisionError } from './errors';
8import { decide as decideV2, distribution } from './interpreter_v2';
9import { formatDecisionRules, formatProperty } from './formatter';
10
11const DECISION_FORMAT_VERSION = '1.1.0';
12
13export function decide(tree, ...args) {
14 const { _version, configuration, trees } = parse(tree);
15 const ctx = configuration ? context(configuration, ...args) : _.extend({}, ...args);
16 return _decide(configuration, trees, ctx, _version);
17}
18
19function _decide(configuration, trees, ctx, _version) {
20 if (semver.satisfies(_version, '>=1.0.0 <2.0.0')) {
21 return decideV1(configuration, trees, ctx);
22 }
23 if (semver.satisfies(_version, '>=2.0.0 <3.0.0')) {
24 return decideV2(configuration, trees, ctx);
25 }
26 throw new CraftAiDecisionError(`Invalid decision tree format, "${_version}" is not a valid version.`);
27}
28
29function reduceNodes(tree, fn, initialAccValue) {
30 let nodes = [];
31 nodes.push(tree);
32 const recursiveNext = (acc) => {
33 if (nodes.length == 0) {
34 // No more nodes
35 return acc;
36 }
37
38 const node = nodes.pop();
39 if (node.children) {
40 nodes = node.children.concat(nodes);
41 }
42
43 const updatedAcc = fn(acc, node);
44 return recursiveNext(updatedAcc);
45 };
46 return recursiveNext(initialAccValue);
47}
48
49export function getDecisionRulesProperties(tree) {
50 const { configuration, trees } = parse(tree);
51 return _(trees)
52 .values()
53 .reduce(
54 (properties, tree) => reduceNodes(
55 tree,
56 (properties, node) => {
57 if (node.children) { // Skip leaves
58 return properties.concat(node.children[0].decision_rule.property);
59 }
60 return properties;
61 },
62 properties),
63 _([])
64 )
65 .uniq()
66 .map((property) => _.extend(configuration.context[property], {
67 property: property
68 }))
69 .value();
70}
71
72export function decideFromContextsArray(tree, contexts) {
73 const { _version, configuration, trees } = parse(tree);
74 return _.map(contexts, (contextsItem) => {
75 let ctx;
76 if (_.isArray(contextsItem)) {
77 ctx = context(configuration, ...contextsItem);
78 }
79 else {
80 ctx = context(configuration, contextsItem);
81 }
82 try {
83 return _decide(configuration, trees, ctx, _version);
84 }
85 catch (error) {
86 if (error instanceof CraftAiNullDecisionError) {
87 const { message, metadata } = error;
88 return {
89 _version: DECISION_FORMAT_VERSION,
90 context: ctx,
91 error: { message, metadata }
92 };
93 }
94 else {
95 throw error;
96 }
97 }
98 });
99}
100
101export { formatDecisionRules, formatProperty, reduceDecisionRules, distribution };