2018-01-08 15:07:26 +00:00
import {
2018-04-12 13:43:02 +00:00
add ,
2018-01-08 15:07:26 +00:00
any ,
equals ,
evolve ,
2019-01-14 14:14:57 +00:00
filter ,
2019-04-11 13:23:46 +00:00
fromPairs ,
is ,
keys ,
map ,
mergeWith ,
reduce ,
values
2018-01-08 15:07:26 +00:00
} from 'ramda'
2019-11-28 11:03:23 +00:00
import React from 'react'
import { typeWarning } from './error'
import { convertNodeToUnit , simplifyNodeUnit } from './nodeUnits'
2017-07-13 10:25:46 +00:00
2017-07-31 16:16:25 +00:00
export let makeJsx = node =>
2018-01-03 15:54:19 +00:00
typeof node . jsx == 'function'
2019-07-20 16:30:42 +00:00
? node . jsx ( node . nodeValue , node . explanation , node . lazyEval , node . unit )
2017-07-31 16:16:25 +00:00
: node . jsx
2017-07-13 19:55:59 +00:00
2018-04-12 13:43:02 +00:00
export let collectNodeMissing = node => node . missingVariables || { }
2018-06-29 13:46:42 +00:00
export let bonus = ( missings , hasCondition = true ) =>
hasCondition ? map ( x => x + 0.0001 , missings || { } ) : missings
export let mergeAllMissing = missings =>
reduce ( mergeWith ( add ) , { } , map ( collectNodeMissing , missings ) )
export let mergeMissing = ( left , right ) =>
mergeWith ( add , left || { } , right || { } )
2017-07-13 10:25:46 +00:00
2019-11-28 11:03:23 +00:00
export let evaluateNode = ( cache , situationGate , parsedRules , node ) => {
let evaluatedNode = node . evaluate
? node . evaluate ( cache , situationGate , parsedRules , node )
: node
if ( typeof evaluatedNode . nodeValue !== 'number' ) {
return evaluatedNode
}
evaluatedNode = node . unité
? convertNodeToUnit ( node . unit , evaluatedNode )
: simplifyNodeUnit ( evaluatedNode )
return evaluatedNode
}
const sameUnitValues = ( explanation , contextRule , mecanismName ) => {
2020-02-19 16:47:21 +00:00
const firstNodeWithUnit = explanation . find ( node => ! ! node . unit )
2020-02-21 15:39:54 +00:00
if ( ! firstNodeWithUnit ) {
return [ undefined , explanation . map ( ( { nodeValue } ) => nodeValue ) ]
}
2019-11-28 11:03:23 +00:00
const values = explanation . map ( node => {
try {
2020-02-21 15:39:54 +00:00
return convertNodeToUnit ( firstNodeWithUnit ? . unit , node ) . nodeValue
2019-11-28 11:03:23 +00:00
} catch ( e ) {
typeWarning (
contextRule ,
2020-02-21 15:39:54 +00:00
` Dans le mécanisme ${ mecanismName } , les unités des éléments suivants sont incompatibles entre elles : \n \t \t ${ node ? . name ||
node ? . rawNode } \ n \ t \ t$ { firstNodeWithUnit ? . name ||
firstNodeWithUnit ? . rawNode } ' ` ,
2019-11-28 11:03:23 +00:00
e
)
return node . nodeValue
}
} )
2020-02-19 16:47:21 +00:00
return [ firstNodeWithUnit . unit , values ]
2019-11-28 11:03:23 +00:00
}
2017-07-13 10:25:46 +00:00
2018-01-03 15:54:19 +00:00
export let evaluateArray = ( reducer , start ) => (
cache ,
situationGate ,
parsedRules ,
node
) => {
let evaluateOne = child =>
evaluateNode ( cache , situationGate , parsedRules , child ) ,
2018-01-08 15:07:26 +00:00
explanation = map ( evaluateOne , node . explanation ) ,
2019-11-28 11:03:23 +00:00
[ unit , values ] = sameUnitValues (
explanation ,
cache . _meta . contextRule ,
node . name
) ,
nodeValue = values . some ( value => value === null )
2018-01-03 15:54:19 +00:00
? null
2018-04-10 11:00:03 +00:00
: reduce ( reducer , start , values ) ,
2018-06-29 13:46:42 +00:00
missingVariables =
node . nodeValue == null ? mergeAllMissing ( explanation ) : { }
2019-11-28 11:03:23 +00:00
return {
... node ,
nodeValue ,
explanation ,
missingVariables ,
unit
}
2017-07-16 21:58:06 +00:00
}
2018-01-08 15:07:26 +00:00
export let evaluateArrayWithFilter = ( evaluationFilter , reducer , start ) => (
2018-01-03 15:54:19 +00:00
cache ,
situationGate ,
parsedRules ,
node
) => {
let evaluateOne = child =>
evaluateNode ( cache , situationGate , parsedRules , child ) ,
2018-01-08 15:07:26 +00:00
explanation = map (
2018-01-03 15:54:19 +00:00
evaluateOne ,
2018-01-08 15:07:26 +00:00
filter ( evaluationFilter ( situationGate ) , node . explanation )
2018-01-03 15:54:19 +00:00
) ,
2019-11-28 11:03:23 +00:00
[ unit , values ] = sameUnitValues (
explanation ,
cache . _meta . contextRule ,
node . name
) ,
2018-01-08 15:07:26 +00:00
nodeValue = any ( equals ( null ) , values )
2018-01-03 15:54:19 +00:00
? null
2018-04-10 11:00:03 +00:00
: reduce ( reducer , start , values ) ,
2018-06-29 13:46:42 +00:00
missingVariables =
node . nodeValue == null ? mergeAllMissing ( explanation ) : { }
2017-07-13 10:25:46 +00:00
2019-11-28 11:03:23 +00:00
return { ... node , nodeValue , explanation , missingVariables , unit }
2017-07-13 10:25:46 +00:00
}
2019-02-14 17:00:31 +00:00
export let defaultNode = nodeValue => ( {
nodeValue ,
// eslint-disable-next-line
jsx : nodeValue => < span className = "value" > { nodeValue } < / s p a n > ,
isDefault : true
} )
2017-07-13 10:25:46 +00:00
export let parseObject = ( recurse , objectShape , value ) => {
let recurseOne = key => defaultValue => {
2018-12-05 17:58:38 +00:00
if ( ! value [ key ] && ! defaultValue )
throw new Error (
2020-02-25 18:47:54 +00:00
` Il manque une clé ' ${ key } ' dans ${ JSON . stringify ( value ) } `
2018-12-05 17:58:38 +00:00
)
2018-01-03 15:54:19 +00:00
return value [ key ] ? recurse ( value [ key ] ) : defaultValue
}
2018-01-08 15:07:26 +00:00
let transforms = fromPairs ( map ( k => [ k , recurseOne ( k ) ] , keys ( objectShape ) ) )
return evolve ( transforms , objectShape )
2017-07-13 10:25:46 +00:00
}
2018-01-03 15:54:19 +00:00
export let evaluateObject = ( objectShape , effect ) => (
cache ,
situationGate ,
parsedRules ,
node
) => {
let evaluateOne = child =>
2018-06-29 13:46:42 +00:00
evaluateNode ( cache , situationGate , parsedRules , child )
2017-07-13 10:25:46 +00:00
2018-01-08 15:07:26 +00:00
let transforms = map ( k => [ k , evaluateOne ] , keys ( objectShape ) ) ,
2019-01-14 14:14:57 +00:00
automaticExplanation = evolve ( fromPairs ( transforms ) ) ( node . explanation )
// the result of effect can either be just a nodeValue, or an object {additionalExplanation, nodeValue}. The latter is useful for a richer JSX visualisation of the mecanism : the view should not duplicate code to recompute intermediate values (e.g. for a marginal 'barème', the marginal 'tranche')
2020-02-19 16:47:21 +00:00
let evaluated = effect (
automaticExplanation ,
cache ,
situationGate ,
parsedRules
) ,
2019-01-14 14:14:57 +00:00
explanation = is ( Object , evaluated )
? { ... automaticExplanation , ... evaluated . additionalExplanation }
: automaticExplanation ,
nodeValue = is ( Object , evaluated ) ? evaluated . nodeValue : evaluated ,
2018-04-12 13:43:02 +00:00
missingVariables = mergeAllMissing ( values ( explanation ) )
2019-11-28 11:03:23 +00:00
return simplifyNodeUnit ( {
... node ,
nodeValue ,
explanation ,
missingVariables ,
unit : explanation . unit
} )
2019-02-21 16:55:07 +00:00
}