diff --git a/source/engine/traverse.js b/source/engine/traverse.js
index f41e67fc5..d6d2c91e3 100644
--- a/source/engine/traverse.js
+++ b/source/engine/traverse.js
@@ -53,26 +53,21 @@ let withFilter = (rules, filter) =>
R.concat(rules,[{name:"filter", nodeValue:filter, ns:"sys", dottedName: "sys . filter"}])
let fillVariableNode = (rules, rule, situationGate) => (parseResult) => {
- let variableNode = createVariableNode(rules, rule, situationGate)(parseResult)
- return evaluateNode(situationGate,[],variableNode)
+ return createVariableNode(rules, rule, situationGate)(parseResult)
}
let createVariableNode = (rules, rule, situationGate) => (parseResult) => {
let evaluate = (situation, parsedRules, node) => {
let dottedName = node.dottedName,
- variable = findRuleByDottedName(rules, dottedName),
+ variable = findRuleByDottedName(parsedRules, dottedName),
variableIsCalculable = variable.formule != null,
//TODO perf : mettre un cache sur les variables !
// On le fait pas pour l'instant car ça peut compliquer les fonctionnalités futures
// et qu'il n'y a aucun problème de perf aujourd'hui
parsedRule = variableIsCalculable && evaluateNode(
situationGate,
- [],
- treatRuleRoot(
- situationGate,
- rules,
- variable
- )
+ parsedRules,
+ variable
),
situationValue = evaluateVariable(situationGate, dottedName, variable),
@@ -167,6 +162,31 @@ let treat = (situationGate, rules, rule) => rawNode => {
)
if (parseResult.category == 'calcExpression') {
+ let evaluate = (situation, parsedRules, node) => {
+ let
+ operatorFunctionName = {
+ '*': 'multiply',
+ '/': 'divide',
+ '+': 'add',
+ '-': 'subtract'
+ }[node.operator],
+ value1 = evaluateNode(situation,parsedRules,node.explanation[0]).nodeValue,
+ value2 = evaluateNode(situation,parsedRules,node.explanation[1]).nodeValue,
+ operatorFunction = R[operatorFunctionName],
+ nodeValue = value1 == null || value2 == null ?
+ null
+ : operatorFunction(value1, value2)
+
+ return {
+ ...node,
+ nodeValue,
+ jsx: {
+ ...node.jsx,
+ value: nodeValue
+ }
+ }
+ }
+
let
fillVariable = fillVariableNode(rules, rule, situationGate),
fillFiltered = parseResult => fillVariableNode(withFilter(rules,parseResult.filter), rule, situationGate)(parseResult.variable),
@@ -175,33 +195,24 @@ let treat = (situationGate, rules, rule) => rawNode => {
[R.propEq('category', 'variable'), fillVariable],
[R.propEq('category', 'filteredVariable'), fillFiltered],
[R.propEq('category', 'value'), node =>
- R.assoc('jsx',
- {node.nodeValue}
- )(node)
+ ({
+ evaluate: (situation, parsedRules, me) => ({...node, nodeValue: parseInt(node.nodeValue)}),
+ jsx: {node.nodeValue}
+ })
]
])
),
- [{nodeValue: value1}, {nodeValue: value2}] = filledExplanation,
- operatorFunctionName = {
- '*': 'multiply',
- '/': 'divide',
- '+': 'add',
- '-': 'subtract'
- }[parseResult.operator],
- operatorFunction = R[operatorFunctionName],
- nodeValue = value1 == null || value2 == null ?
- null
- : operatorFunction(value1, value2)
+ operator = parseResult.operator
return {
+ evaluate,
+ operator,
text: rawNode,
- nodeValue,
category: 'calcExpression',
type: 'numeric',
explanation: filledExplanation,
jsx:
{filledExplanation[0].jsx}
@@ -212,41 +223,61 @@ let treat = (situationGate, rules, rule) => rawNode => {
/>
}
}
+
if (parseResult.category == 'comparison') {
//TODO mutualise code for 'comparison' & 'calclExpression'. Harmonise their names
+ let evaluate = (situation, parsedRules, node) => {
+ let
+ comparatorFunctionName = {
+ '<': 'lt',
+ '<=': 'lte',
+ '>': 'gt',
+ '>=': 'gte'
+ //TODO '='
+ }[node.operator],
+ comparatorFunction = R[comparatorFunctionName],
+ value1 = evaluateNode(situation,parsedRules,node.explanation[0]).nodeValue,
+ value2 = evaluateNode(situation,parsedRules,node.explanation[1]).nodeValue,
+ nodeValue = value1 == null || value2 == null ?
+ null
+ : comparatorFunction(value1, value2)
+
+ return {
+ ...node,
+ nodeValue,
+ jsx: {
+ ...node.jsx,
+ value: nodeValue
+ }
+ }
+ }
+
let
+ fillVariable = fillVariableNode(rules, rule, situationGate),
+ fillFiltered = parseResult => fillVariableNode(withFilter(rules,parseResult.filter), rule, situationGate)(parseResult.variable),
filledExplanation = parseResult.explanation.map(
R.cond([
- [R.propEq('category', 'variable'), fillVariableNode(rules, rule, situationGate)],
+ [R.propEq('category', 'variable'), fillVariable],
+ [R.propEq('category', 'filteredVariable'), fillFiltered],
[R.propEq('category', 'value'), node =>
- R.assoc('jsx',
- {node.nodeValue}
- )(node)
+ ({
+ evaluate: (situation, parsedRules, me) => ({...node, nodeValue: parseInt(node.nodeValue)}),
+ jsx: {node.nodeValue}
+ })
]
])
),
- [{nodeValue: value1}, {nodeValue: value2}] = filledExplanation,
- comparatorFunctionName = {
- '<': 'lt',
- '<=': 'lte',
- '>': 'gt',
- '>=': 'gte'
- //TODO '='
- }[parseResult.operator],
- comparatorFunction = R[comparatorFunctionName],
- nodeValue = value1 == null || value2 == null ?
- null
- : comparatorFunction(value1, value2)
+ operator = parseResult.operator
return {
+ evaluate,
+ operator,
text: rawNode,
- nodeValue: nodeValue,
category: 'comparison',
type: 'boolean',
explanation: filledExplanation,
jsx:
{filledExplanation[0].jsx}
@@ -308,7 +339,14 @@ let treat = (situationGate, rules, rule) => rawNode => {
[R.is(Object), treatObject],
[R.T, treatOther]
])
- return onNodeType(rawNode)
+
+ let defaultEvaluate = (situationGate, parsedRules, node) => {
+ return node
+ }
+ let parsedNode = onNodeType(rawNode)
+
+ return parsedNode.evaluate ? parsedNode :
+ {...parsedNode, evaluate: defaultEvaluate}
}
//TODO c'est moche :
@@ -326,8 +364,9 @@ export let computeRuleValue = (formuleValue, condValue) =>
export let treatRuleRoot = (situationGate, rules, rule) => {
let evaluate = (situationGate, parsedRules, r) => {
let
- formuleValue = r.formule.nodeValue,
- condValue = R.path(['non applicable si', 'nodeValue'])(r),
+ formuleValue = r.formule && evaluateNode(situationGate, parsedRules, r.formule).nodeValue,
+ condition = R.prop('non applicable si',r),
+ condValue = condition && evaluateNode(situationGate, parsedRules, condition).nodeValue,
nodeValue = computeRuleValue(formuleValue, condValue)
return {...r, nodeValue}
@@ -339,21 +378,30 @@ export let treatRuleRoot = (situationGate, rules, rule) => {
// 'cond' : Conditions d'applicabilité de la règle
'non applicable si': value => {
- let
- child = treat(situationGate, rules, rule)(value),
- nodeValue = child.nodeValue
+ let evaluate = (situationGate, parsedRules, node) => {
+ let nodeValue = evaluateNode(situationGate, parsedRules, node.explanation).nodeValue
+ return {
+ ...node,
+ nodeValue,
+ jsx: {
+ ...node.jsx,
+ value: nodeValue
+ }
+ }
+ }
+
+ let child = treat(situationGate, rules, rule)(value)
return {
+ evaluate,
category: 'ruleProp',
rulePropType: 'cond',
name: 'non applicable si',
type: 'boolean',
- nodeValue: child.nodeValue,
explanation: child,
jsx: {child.jsx}
: child.jsx
@@ -368,21 +416,30 @@ export let treatRuleRoot = (situationGate, rules, rule) => {
// note: pour certaines variables booléennes, ex. appartenance à régime Alsace-Moselle, la formule et le non applicable si se rejoignent
// [n'importe quel mécanisme numérique] : multiplication || barème en taux marginaux || le maximum de || le minimum de || ...
'formule': value => {
- let
- child = treat(situationGate, rules, rule)(value),
- nodeValue = child.nodeValue
+ let evaluate = (situationGate, parsedRules, node) => {
+ let nodeValue = evaluateNode(situationGate, parsedRules, node.explanation).nodeValue
+ return {
+ ...node,
+ nodeValue,
+ jsx: {
+ ...node.jsx,
+ value: nodeValue
+ }
+ }
+ }
+
+ let child = treat(situationGate, rules, rule)(value)
return {
+ evaluate,
category: 'ruleProp',
rulePropType: 'formula',
name: 'formule',
type: 'numeric',
- nodeValue: nodeValue,
explanation: child,
shortCircuit: R.pathEq(['non applicable si', 'nodeValue'], true),
jsx: dix", espace: "top"},
+ {nom: "dix", formule: 10, espace: "top"}],
rules = rawRules.map(enrichRule)
- expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',93-17)
- });
-
- it('should handle components in complements', function() {
- let rawRules = [
- {nom: "startHere", formule: {complément: {cible: "dix",
- composantes: [{montant: 93},{montant: 93}]
- }}, espace: "top"},
- {nom: "dix", formule: 17, espace: "top"}],
- rules = rawRules.map(enrichRule)
- expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',2*(93-17))
+ expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',true)
});
/* TODO: make this pass
@@ -170,6 +168,24 @@ describe('analyseSituation with mecanisms', function() {
expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',3200)
});
+ it('should handle complements', function() {
+ let rawRules = [
+ {nom: "startHere", formule: {complément: {cible: "dix", montant: 93}}, espace: "top"},
+ {nom: "dix", formule: 17, espace: "top"}],
+ rules = rawRules.map(enrichRule)
+ expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',93-17)
+ });
+
+ it('should handle components in complements', function() {
+ let rawRules = [
+ {nom: "startHere", formule: {complément: {cible: "dix",
+ composantes: [{montant: 93},{montant: 93}]
+ }}, espace: "top"},
+ {nom: "dix", formule: 17, espace: "top"}],
+ rules = rawRules.map(enrichRule)
+ expect(analyseSituation(rules,"startHere")(stateSelector)).to.have.property('nodeValue',2*(93-17))
+ });
+
it('should handle filtering on components', function() {
let rawRules = [
{nom: "startHere", espace: "top", formule: "composed (salarié)"},