2017-03-14 10:42:44 +00:00
import React from 'react'
2017-06-27 17:53:37 +00:00
import { rules , findRuleByDottedName , disambiguateRuleReference , findRuleByName } from './rules'
2017-04-24 18:03:38 +00:00
import { evaluateVariable } from './variables'
2017-02-22 16:55:36 +00:00
import R from 'ramda'
2017-03-03 09:43:43 +00:00
import knownMecanisms from './known-mecanisms.yaml'
2017-03-07 17:25:25 +00:00
import { Parser } from 'nearley'
import Grammar from './grammar.ne'
2017-03-15 17:13:46 +00:00
import { Node , Leaf } from './traverse-common-jsx'
2017-06-29 12:26:24 +00:00
import { mecanismOneOf , mecanismAllOf , mecanismNumericalLogic , mecanismSum , mecanismProduct ,
mecanismPercentage , mecanismScale , mecanismMax , mecanismError , mecanismComplement } from "./mecanisms"
2017-07-13 19:55:59 +00:00
import { evaluateNode , rewriteNode , collectNodeMissing , makeJsx } from './evaluation'
2017-03-07 17:25:25 +00:00
2017-03-08 16:47:12 +00:00
let nearley = ( ) => new Parser ( Grammar . ParserRules , Grammar . ParserStart )
2017-01-09 17:17:51 +00:00
2017-03-06 16:35:30 +00:00
/ *
Dans ce fichier , les règles YAML sont parsées .
Elles expriment un langage orienté expression , les expressions étant
- préfixes quand elles sont des 'mécanismes' ( des mot - clefs représentant des calculs courants dans la loi )
- infixes pour les feuilles : des tests d 'égalité, d' inclusion , des comparaisons sur des variables ou tout simplement la variable elle - même , ou une opération effectuée sur la variable
* /
2017-02-22 16:55:36 +00:00
/ *
- > Notre règle est naturellement un AST ( car notation préfixe dans le YAML )
- > préliminaire : les expression infixes devront être parsées ,
par exemple ainsi : https : //github.com/Engelberg/instaparse#transforming-the-tree
- > Notre règle entière est un AST , qu ' il faut maintenant traiter :
- faire le calcul ( déterminer les valeurs de chaque noeud )
- trouver les branches complètes pour déterminer les autres branches courtcircuitées
- ex . rule . formule est courtcircuitée si rule . non applicable est vrai
2017-04-24 18:03:38 +00:00
- les feuilles de 'une de ces conditions' sont courtcircuitées si l 'une d' elle est vraie
2017-02-22 16:55:36 +00:00
- les feuilles de "toutes ces conditions" sont courtcircuitées si l 'une d' elle est fausse
- ...
( - bonus : utiliser ces informations pour l ' ordre de priorité des variables inconnues )
- si une branche est incomplète et qu 'elle est de type numérique, déterminer les bornes si c' est possible .
Ex . - pour une multiplication , si l 'assiette est connue mais que l ' applicabilité est inconnue ,
les bornes seront [ 0 , multiplication . value = assiette * taux ]
- si taux = effectif entreprise >= 20 ? 1 % : 2 % et que l ' applicabilité est connue ,
bornes = [ assiette * 1 % , assiette * 2 % ]
- transformer l ' arbre en JSX pour afficher le calcul * et son état en prenant en compte les variables renseignées et calculées * de façon sympathique dans un butineur Web tel que Mozilla Firefox .
- surement plein d ' autres applications ...
* /
2017-07-17 17:39:49 +00:00
let fillVariableNode = ( rules , rule ) => ( parseResult ) => {
return createVariableNode ( rules , rule ) ( parseResult )
2017-07-09 14:39:31 +00:00
}
2017-07-17 17:39:49 +00:00
let fillFilteredVariableNode = ( rules , rule ) => ( filter , parseResult ) => {
2017-07-16 21:58:06 +00:00
let evaluateFiltered = originalEval => ( situation , parsedRules , node ) => {
let newSituation = name => name == "sys.filter" ? filter : situation ( name )
return originalEval ( newSituation , parsedRules , node )
}
2017-07-17 17:39:49 +00:00
let node = fillVariableNode ( rules , rule ) ( parseResult )
2017-07-16 21:58:06 +00:00
return {
... node ,
evaluate : evaluateFiltered ( node . evaluate )
}
}
2017-07-17 17:39:49 +00:00
let createVariableNode = ( rules , rule ) => ( parseResult ) => {
2017-07-09 14:39:31 +00:00
let evaluate = ( situation , parsedRules , node ) => {
let dottedName = node . dottedName ,
2017-07-09 16:48:00 +00:00
variable = findRuleByDottedName ( parsedRules , dottedName ) ,
2017-07-09 14:39:31 +00:00
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 (
2017-07-16 21:58:06 +00:00
situation ,
2017-07-09 16:48:00 +00:00
parsedRules ,
variable
2017-07-09 14:39:31 +00:00
) ,
2017-07-16 21:58:06 +00:00
situationValue = evaluateVariable ( situation , dottedName , variable ) ,
2017-07-17 12:01:48 +00:00
nodeValue = situationValue
2017-07-09 14:39:31 +00:00
!= null ? situationValue
: ! variableIsCalculable
? null
: parsedRule . nodeValue ,
explanation = parsedRule ,
missingVariables = variableIsCalculable ? [ ] : ( nodeValue == null ? [ dottedName ] : [ ] )
2017-07-12 22:01:44 +00:00
let collectMissing = node =>
variableIsCalculable ? collectNodeMissing ( parsedRule ) : node . missingVariables
2017-07-11 14:00:10 +00:00
2017-07-09 14:39:31 +00:00
return {
2017-07-13 10:25:46 +00:00
... rewriteNode ( node , nodeValue , explanation , collectMissing ) ,
2017-07-09 14:39:31 +00:00
missingVariables ,
}
}
2017-07-17 17:39:49 +00:00
let { fragments } = parseResult ,
2017-03-08 16:49:22 +00:00
variablePartialName = fragments . join ( ' . ' ) ,
2017-07-09 14:39:31 +00:00
dottedName = disambiguateRuleReference ( rules , rule , variablePartialName )
2017-03-08 16:49:22 +00:00
2017-07-13 20:44:14 +00:00
let jsx = ( nodeValue , explanation ) =>
2017-07-13 19:55:59 +00:00
< Leaf
classes = "variable"
name = { fragments . join ( ' . ' ) }
value = { nodeValue }
/ >
2017-03-08 16:49:22 +00:00
return {
2017-07-09 14:39:31 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-07-09 22:14:22 +00:00
name : variablePartialName ,
2017-03-08 16:49:22 +00:00
category : 'variable' ,
2017-07-13 19:55:59 +00:00
fragments ,
2017-05-09 15:14:13 +00:00
dottedName ,
2017-07-13 19:55:59 +00:00
type : 'boolean | numeric'
2017-03-08 16:49:22 +00:00
}
}
2017-05-09 13:39:42 +00:00
let buildNegatedVariable = variable => {
2017-07-13 10:12:19 +00:00
let evaluate = ( situation , parsedRules , node ) => {
2017-07-17 17:39:49 +00:00
let explanation = evaluateNode ( situation , parsedRules , node . explanation ) ,
2017-07-13 10:12:19 +00:00
nodeValue = explanation . nodeValue == null ? null : ! explanation . nodeValue
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-13 10:12:19 +00:00
}
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
2017-07-13 19:55:59 +00:00
< Node
2017-05-09 13:39:42 +00:00
classes = "inlineExpression negation"
2017-07-13 19:55:59 +00:00
value = { node . nodeValue }
2017-05-09 13:39:42 +00:00
child = {
< span className = "nodeContent" >
< span className = "operator" > ¬ < / s p a n >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation ) }
2017-05-09 13:39:42 +00:00
< / s p a n >
}
/ >
2017-07-13 19:55:59 +00:00
return {
evaluate ,
jsx ,
category : 'mecanism' ,
name : 'négation' ,
type : 'boolean' ,
explanation : variable
2017-05-09 13:39:42 +00:00
}
}
2017-07-17 17:39:49 +00:00
let treat = ( rules , rule ) => rawNode => {
2017-06-27 21:09:03 +00:00
// inner functions
2017-07-17 17:39:49 +00:00
let reTreat = treat ( rules , rule ) ,
2017-06-27 21:09:03 +00:00
treatString = rawNode => {
/ * O n a à f a i r e à u n s t r i n g , d o n c à u n e e x p r e s s i o n i n f i x e .
Elle sera traité avec le parser obtenu grâce à NearleyJs et notre grammaire .
On obtient un objet de type Variable ( avec potentiellement un 'modifier' , par exemple temporel ( TODO ) ) , CalcExpression ou Comparison .
Cet objet est alors rebalancé à 'treat' .
* /
2017-03-08 16:47:12 +00:00
2017-06-27 21:09:03 +00:00
let [ parseResult , ... additionnalResults ] = nearley ( ) . feed ( rawNode ) . results
if ( additionnalResults && additionnalResults . length > 0 )
throw "Attention ! L'expression <" + rawNode + '> ne peut être traitée de façon univoque'
2017-06-29 10:03:01 +00:00
if ( ! R . contains ( parseResult . category ) ( [ 'variable' , 'calcExpression' , 'filteredVariable' , 'comparison' , 'negatedVariable' ] ) )
2017-06-27 21:09:03 +00:00
throw "Attention ! Erreur de traitement de l'expression : " + rawNode
if ( parseResult . category == 'variable' )
2017-07-17 17:39:49 +00:00
return fillVariableNode ( rules , rule ) ( parseResult )
2017-06-29 10:03:01 +00:00
if ( parseResult . category == 'filteredVariable' ) {
2017-07-17 17:39:49 +00:00
return fillFilteredVariableNode ( rules , rule ) ( parseResult . filter , parseResult . variable )
2017-06-29 10:03:01 +00:00
}
2017-06-27 21:09:03 +00:00
if ( parseResult . category == 'negatedVariable' )
return buildNegatedVariable (
2017-07-17 17:39:49 +00:00
fillVariableNode ( rules , rule ) ( parseResult . variable )
2017-06-27 21:09:03 +00:00
)
if ( parseResult . category == 'calcExpression' ) {
2017-07-09 16:48:00 +00:00
let evaluate = ( situation , parsedRules , node ) => {
let
operatorFunctionName = {
'*' : 'multiply' ,
'/' : 'divide' ,
'+' : 'add' ,
'-' : 'subtract'
} [ node . operator ] ,
2017-07-11 14:00:10 +00:00
explanation = R . map ( R . curry ( evaluateNode ) ( situation , parsedRules ) , node . explanation ) ,
value1 = explanation [ 0 ] . nodeValue ,
value2 = explanation [ 1 ] . nodeValue ,
2017-07-09 16:48:00 +00:00
operatorFunction = R [ operatorFunctionName ] ,
nodeValue = value1 == null || value2 == null ?
null
: operatorFunction ( value1 , value2 )
2017-07-11 14:00:10 +00:00
let collectMissing = node => R . chain ( collectNodeMissing , node . explanation )
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let fillFiltered = parseResult => fillFilteredVariableNode ( rules , rule ) ( parseResult . filter , parseResult . variable )
let fillVariable = fillVariableNode ( rules , rule ) ,
2017-06-27 21:09:03 +00:00
filledExplanation = parseResult . explanation . map (
R . cond ( [
2017-06-29 10:03:01 +00:00
[ R . propEq ( 'category' , 'variable' ) , fillVariable ] ,
[ R . propEq ( 'category' , 'filteredVariable' ) , fillFiltered ] ,
2017-06-27 21:09:03 +00:00
[ R . propEq ( 'category' , 'value' ) , node =>
2017-07-09 16:48:00 +00:00
( {
2017-07-13 20:44:14 +00:00
evaluate : ( situation , parsedRules , me ) => ( { ... me , nodeValue : parseInt ( node . nodeValue ) } ) ,
jsx : nodeValue => < span className = "value" > { nodeValue } < / s p a n >
2017-07-09 16:48:00 +00:00
} )
2017-06-27 21:09:03 +00:00
]
] )
) ,
2017-07-09 16:48:00 +00:00
operator = parseResult . operator
2017-06-27 21:09:03 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-06-27 21:09:03 +00:00
classes = "inlineExpression calcExpression"
2017-07-13 19:55:59 +00:00
value = { nodeValue }
2017-06-27 21:09:03 +00:00
child = {
< span className = "nodeContent" >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation [ 0 ] ) }
2017-06-27 21:09:03 +00:00
< span className = "operator" > { parseResult . operator } < / s p a n >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation [ 1 ] ) }
2017-06-27 21:09:03 +00:00
< / s p a n >
}
/ >
2017-07-13 19:55:59 +00:00
return {
evaluate ,
jsx ,
operator ,
text : rawNode ,
category : 'calcExpression' ,
type : 'numeric' ,
explanation : filledExplanation
2017-06-27 21:09:03 +00:00
}
}
2017-07-09 16:48:00 +00:00
2017-06-27 21:09:03 +00:00
if ( parseResult . category == 'comparison' ) {
//TODO mutualise code for 'comparison' & 'calclExpression'. Harmonise their names
2017-07-09 16:48:00 +00:00
let evaluate = ( situation , parsedRules , node ) => {
let
comparatorFunctionName = {
'<' : 'lt' ,
'<=' : 'lte' ,
'>' : 'gt' ,
'>=' : 'gte'
//TODO '='
} [ node . operator ] ,
comparatorFunction = R [ comparatorFunctionName ] ,
2017-07-11 14:00:10 +00:00
explanation = R . map ( R . curry ( evaluateNode ) ( situation , parsedRules ) , node . explanation ) ,
value1 = explanation [ 0 ] . nodeValue ,
value2 = explanation [ 1 ] . nodeValue ,
2017-07-09 16:48:00 +00:00
nodeValue = value1 == null || value2 == null ?
null
: comparatorFunction ( value1 , value2 )
2017-07-11 14:00:10 +00:00
let collectMissing = node => R . chain ( collectNodeMissing , node . explanation )
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let fillFiltered = parseResult => fillVariableNode ( rules , rule ) ( parseResult . variable )
let fillVariable = fillVariableNode ( rules , rule ) ,
2017-06-27 21:09:03 +00:00
filledExplanation = parseResult . explanation . map (
R . cond ( [
2017-07-09 16:48:00 +00:00
[ R . propEq ( 'category' , 'variable' ) , fillVariable ] ,
[ R . propEq ( 'category' , 'filteredVariable' ) , fillFiltered ] ,
2017-06-27 21:09:03 +00:00
[ R . propEq ( 'category' , 'value' ) , node =>
2017-07-09 16:48:00 +00:00
( {
2017-07-13 20:44:14 +00:00
evaluate : ( situation , parsedRules , me ) => ( { ... me , nodeValue : parseInt ( node . nodeValue ) } ) ,
jsx : nodeValue => < span className = "value" > { nodeValue } < / s p a n >
2017-07-09 16:48:00 +00:00
} )
2017-06-27 21:09:03 +00:00
]
] )
) ,
2017-07-09 16:48:00 +00:00
operator = parseResult . operator
2017-06-27 21:09:03 +00:00
2017-07-13 20:44:14 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-13 19:55:59 +00:00
classes = "inlineExpression calcExpression"
value = { nodeValue }
child = {
< span className = "nodeContent" >
{ makeJsx ( explanation [ 0 ] ) }
< span className = "operator" > { parseResult . operator } < / s p a n >
{ makeJsx ( explanation [ 1 ] ) }
< / s p a n >
}
/ >
2017-06-27 21:09:03 +00:00
return {
2017-07-09 16:48:00 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-07-09 16:48:00 +00:00
operator ,
2017-06-27 21:09:03 +00:00
text : rawNode ,
category : 'comparison' ,
type : 'boolean' ,
explanation : filledExplanation ,
}
}
} ,
treatNumber = rawNode => {
2017-03-09 15:42:52 +00:00
return {
2017-06-27 23:19:38 +00:00
text : "" + rawNode ,
2017-06-27 21:09:03 +00:00
category : 'number' ,
nodeValue : rawNode ,
2017-03-09 15:42:52 +00:00
type : 'numeric' ,
2017-06-27 21:09:03 +00:00
jsx :
< span className = "number" >
{ rawNode }
< / s p a n >
2017-03-09 15:42:52 +00:00
}
2017-06-27 21:09:03 +00:00
} ,
treatOther = rawNode => {
console . log ( ) // eslint-disable-line no-console
throw 'Cette donnée : ' + rawNode + ' doit être un Number, String ou Object'
} ,
2017-06-27 23:02:36 +00:00
treatObject = rawNode => {
let mecanisms = R . intersection ( R . keys ( rawNode ) , R . keys ( knownMecanisms ) )
if ( mecanisms . length != 1 ) {
console . log ( 'Erreur : On ne devrait reconnaître que un et un seul mécanisme dans cet objet' , rawNode )
throw 'OUPS !'
2017-06-27 21:09:03 +00:00
}
2017-04-24 18:03:38 +00:00
2017-06-27 23:02:36 +00:00
let k = R . head ( mecanisms ) ,
v = rawNode [ k ]
2017-06-28 07:06:52 +00:00
let dispatch = {
'une de ces conditions' : mecanismOneOf ,
'toutes ces conditions' : mecanismAllOf ,
'logique numérique' : mecanismNumericalLogic ,
'taux' : mecanismPercentage ,
'somme' : mecanismSum ,
'multiplication' : mecanismProduct ,
'barème' : mecanismScale ,
'le maximum de' : mecanismMax ,
2017-06-29 12:26:24 +00:00
'complément' : mecanismComplement ,
2017-07-09 14:39:31 +00:00
'une possibilité' : R . always ( { } )
2017-06-28 07:06:52 +00:00
} ,
action = R . pathOr ( mecanismError , [ k ] , dispatch )
2017-04-06 16:34:00 +00:00
2017-06-28 07:31:37 +00:00
return action ( reTreat , k , v )
2017-03-03 09:43:43 +00:00
}
2017-02-22 16:55:36 +00:00
2017-06-27 21:09:03 +00:00
let onNodeType = R . cond ( [
[ R . is ( String ) , treatString ] ,
[ R . is ( Number ) , treatNumber ] ,
2017-06-27 22:38:55 +00:00
[ R . is ( Object ) , treatObject ] ,
[ R . T , treatOther ]
2017-06-27 21:09:03 +00:00
] )
2017-07-09 16:48:00 +00:00
2017-07-11 15:39:50 +00:00
let defaultEvaluate = ( situationGate , parsedRules , node ) => node
2017-07-09 16:48:00 +00:00
let parsedNode = onNodeType ( rawNode )
return parsedNode . evaluate ? parsedNode :
{ ... parsedNode , evaluate : defaultEvaluate }
2017-02-22 16:55:36 +00:00
}
2017-05-07 17:45:44 +00:00
//TODO c'est moche :
export let computeRuleValue = ( formuleValue , condValue ) =>
condValue === undefined
? formuleValue
: formuleValue === 0
? 0
: condValue === null
? null
: condValue === true
? 0
: formuleValue
2017-07-17 17:39:49 +00:00
export let treatRuleRoot = ( rules , rule ) => {
2017-07-09 14:39:31 +00:00
let evaluate = ( situationGate , parsedRules , r ) => {
let
2017-07-11 14:00:10 +00:00
evaluated = R . evolve ( {
formule : R . curry ( evaluateNode ) ( situationGate , parsedRules ) ,
"non applicable si" : R . curry ( evaluateNode ) ( situationGate , parsedRules )
} , r ) ,
formuleValue = evaluated . formule && evaluated . formule . nodeValue ,
condition = R . prop ( 'non applicable si' , evaluated ) ,
condValue = condition && condition . nodeValue ,
2017-07-09 14:39:31 +00:00
nodeValue = computeRuleValue ( formuleValue , condValue )
2017-07-11 14:00:10 +00:00
return { ... evaluated , nodeValue }
}
let collectMissing = node => {
let cond = R . prop ( 'non applicable si' , node ) ,
condMissing = cond ? collectNodeMissing ( cond ) : [ ] ,
2017-07-28 08:22:22 +00:00
collectInFormule = ( cond && cond . nodeValue != undefined ) ? ! cond . nodeValue : true ,
2017-07-11 14:00:10 +00:00
formule = node . formule ,
2017-07-28 08:22:22 +00:00
formMissing = collectInFormule ? ( formule ? collectNodeMissing ( formule ) : [ ] ) : [ ]
2017-07-11 14:00:10 +00:00
return R . concat ( condMissing , formMissing )
2017-07-09 14:39:31 +00:00
}
let parsedRoot = R . evolve ( { // -> Voilà les attributs que peut comporter, pour l'instant, une Variable.
2017-02-22 16:55:36 +00:00
// 'meta': pas de traitement pour l'instant
// 'cond' : Conditions d'applicabilité de la règle
2017-03-16 18:30:30 +00:00
'non applicable si' : value => {
2017-07-09 16:48:00 +00:00
let evaluate = ( situationGate , parsedRules , node ) => {
2017-07-13 10:25:46 +00:00
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-11 14:00:10 +00:00
let explanation = evaluateNode ( situationGate , parsedRules , node . explanation ) ,
nodeValue = explanation . nodeValue
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let child = treat ( rules , rule ) ( value )
2017-04-11 15:44:53 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-13 19:55:59 +00:00
classes = "ruleProp mecanism cond"
name = "non applicable si"
value = { nodeValue }
child = {
explanation . category === 'variable' ? < div className = "node" > makeJsx ( explanation ) < / d i v >
: makeJsx ( explanation )
}
/ >
2017-03-16 18:30:30 +00:00
return {
2017-07-09 16:48:00 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-03-16 18:30:30 +00:00
category : 'ruleProp' ,
rulePropType : 'cond' ,
name : 'non applicable si' ,
type : 'boolean' ,
2017-07-13 19:55:59 +00:00
explanation : child
2017-03-16 18:30:30 +00:00
}
2017-03-01 10:21:53 +00:00
}
2017-03-16 18:30:30 +00:00
,
// [n'importe quel mécanisme booléen] : expression booléenne (simple variable, négation, égalité, comparaison numérique, test d'inclusion court / long) || l'une de ces conditions || toutes ces conditions
// 'applicable si': // pareil mais inversé !
2017-02-22 16:55:36 +00:00
2017-03-16 18:30:30 +00:00
// 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 => {
2017-07-09 16:48:00 +00:00
let evaluate = ( situationGate , parsedRules , node ) => {
2017-07-13 10:25:46 +00:00
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-11 14:00:10 +00:00
let explanation = evaluateNode ( situationGate , parsedRules , node . explanation ) ,
nodeValue = explanation . nodeValue
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let child = treat ( rules , rule ) ( value )
2017-07-11 14:00:10 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-13 19:55:59 +00:00
classes = "ruleProp mecanism formula"
name = "formule"
value = { nodeValue }
child = { makeJsx ( explanation ) }
/ >
2017-03-16 18:30:30 +00:00
return {
2017-07-09 16:48:00 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-03-16 18:30:30 +00:00
category : 'ruleProp' ,
rulePropType : 'formula' ,
name : 'formule' ,
type : 'numeric' ,
2017-07-13 19:55:59 +00:00
explanation : child
2017-03-16 18:30:30 +00:00
}
2017-03-01 10:21:53 +00:00
}
,
2017-02-22 16:55:36 +00:00
// TODO les mécanismes de composantes et de variations utilisables un peu partout !
// TODO 'temporal': information concernant les périodes : à définir !
// TODO 'intéractions': certaines variables vont en modifier d'autres : ex. Fillon va réduire voir annuler (set 0) une liste de cotisations
// ... ?
2017-07-09 14:39:31 +00:00
} ) ( rule )
2017-03-20 11:17:49 +00:00
2017-07-09 14:39:31 +00:00
return {
... parsedRoot ,
2017-07-11 14:00:10 +00:00
evaluate ,
collectMissing
2017-03-16 18:30:30 +00:00
}
2017-07-09 14:39:31 +00:00
}
2017-02-22 16:55:36 +00:00
2017-02-10 14:12:00 +00:00
/ * A n a l y s e t h e s e t o f s e l e c t e d r u l e s , a n d a d d d e r i v e d i n f o r m a t i o n t o t h e m :
- do they need variables that are not present in the user situation ?
- if not , do they have a computed value or are they non applicable ?
* /
2017-03-27 13:02:50 +00:00
2017-07-09 14:39:31 +00:00
export let analyseSituation = ( rules , rootVariable ) => situationGate => {
2017-07-09 22:14:22 +00:00
let { root , parsedRules } = analyseTopDown ( rules , rootVariable ) ( situationGate )
return root
}
export let analyseTopDown = ( rules , rootVariable ) => situationGate => {
2017-07-17 17:39:49 +00:00
let treatOne = rule => treatRuleRoot ( rules , rule ) ,
2017-07-09 14:39:31 +00:00
parsedRules = R . map ( treatOne , rules ) ,
2017-07-09 22:14:22 +00:00
rootRule = findRuleByName ( parsedRules , rootVariable ) ,
root = evaluateNode ( situationGate , parsedRules , rootRule )
2017-01-26 12:19:04 +00:00
2017-07-09 22:14:22 +00:00
return {
root ,
parsedRules
}
2017-07-09 14:39:31 +00:00
}
2017-01-10 14:39:40 +00:00
2017-01-19 15:27:27 +00:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Ce qui suit est la première tentative d ' écriture du principe du moteur et de la syntaxe * /
2017-01-09 17:17:51 +00:00
// let types = {
/ *
( expression ) :
| ( variable )
| ( négation )
| ( égalité )
| ( comparaison numérique )
| ( test d ' inclusion court )
* /
// }
/ *
Variable :
- applicable si : ( boolean logic )
- non applicable si : ( boolean logic )
- concerne : ( expression )
- ne concerne pas : ( expression )
( boolean logic ) :
toutes ces conditions : ( [ expression | boolean logic ] )
2017-04-24 18:03:38 +00:00
une de ces conditions : ( [ expression | boolean logic ] )
2017-01-09 17:17:51 +00:00
conditions exclusives : ( [ expression | boolean logic ] )
"If you write a regular expression, walk away for a cup of coffee, come back, and can't easily understand what you just wrote, then you should look for a clearer way to express what you're doing."
Les expressions sont le seul mécanisme relativement embêtant pour le moteur . Dans un premier temps , il les gerera au moyen d 'expressions régulières, puis il faudra probablement mieux s' équiper avec un "javascript parser generator" :
https : //medium.com/@daffl/beyond-regex-writing-a-parser-in-javascript-8c9ed10576a6
( variable ) : ( string )
( négation ) :
! ( variable )
( égalité ) :
( variable ) = ( variable . type )
( comparaison numérique ) :
| ( variable ) < ( variable . type )
| ( variable ) <= ( variable . type )
| ( variable ) > ( variable . type )
| ( variable ) <= ( variable . type )
( test d ' inclusion court ) :
( variable ) ⊂ [ variable . type ]
in Variable . formule :
- composantes
- linéaire
- barème en taux marginaux
- test d 'inclusion: (test d' inclusion )
( test d ' inclusion ) :
variable : ( variable )
possibilités : [ variable . type ]
# pas nécessaire pour le CDD
in Variable
- variations : [ si ]
( si ) :
si : ( expression )
# corps
* /