⚙️ Nouvelle API d'évaluation
Modifie l'API de la fonction `evaluate` pour transmettre le contexte avec `this`, ce qui simplifie l'interface de ces fonctions. L'objet `this` (qui contient `this.parsedRules`, `this.situation`, `this.evaluate`, etc.) est un interpréteur Publicodes, mais nous n'avons pas besoin de créer une nouvelle abstraction car cet objet présente exactement la même interface que l'objet public exposé dans `publicodes/index.ts` et c'est donc l'interface publique qui est utilisée dans les appels internes.pull/1193/head
parent
c66e529fb7
commit
bc8c4d823a
|
@ -4,8 +4,5 @@
|
|||
"spellright.documentTypes": ["yaml", "git-commit", "markdown"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.tabSize": 2,
|
||||
"eslint.enable": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
"eslint.enable": true
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
import { EvaluatedNode, ParsedRule } from '.'
|
||||
import Engine, { EvaluatedNode, evaluationFunction } from '.'
|
||||
import { typeWarning } from './error'
|
||||
import { evaluateApplicability } from './evaluateRule'
|
||||
import { mergeMissing, evaluateNode } from './evaluation'
|
||||
import { mergeMissing } from './evaluation'
|
||||
import { convertNodeToUnit } from './nodeUnits'
|
||||
import { serializeUnit, areUnitConvertible } from './units'
|
||||
import { ParsedRule } from './types'
|
||||
import { areUnitConvertible, serializeUnit } from './units'
|
||||
|
||||
export const evaluateReference = (cache, situation, rules, node) => {
|
||||
const rule = rules[node.dottedName]
|
||||
export const evaluateReference: evaluationFunction = function(node) {
|
||||
const rule = this.parsedRules[node.dottedName]
|
||||
// When a rule exists in different version (created using the `replace` mecanism), we add
|
||||
// a redirection in the evaluation of references to use a potential active replacement
|
||||
const [
|
||||
applicableReplacements,
|
||||
replacementMissingVariableList
|
||||
] = getApplicableReplacements(
|
||||
] = getApplicableReplacements.call(
|
||||
this,
|
||||
node.explanation?.contextRuleName ?? '',
|
||||
cache,
|
||||
situation,
|
||||
rules,
|
||||
rule
|
||||
)
|
||||
|
||||
if (applicableReplacements.length) {
|
||||
if (applicableReplacements.length > 1) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -32,7 +30,7 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
- Restreindre sa portée en ajoutant une liste blanche (via le mot clé "dans") ou une liste noire (via le mot clé "sauf dans")
|
||||
`)
|
||||
}
|
||||
return applicableReplacements[0]
|
||||
return this.evaluateNode(applicableReplacements[0])
|
||||
}
|
||||
const addReplacementMissingVariable = node => ({
|
||||
...node,
|
||||
|
@ -46,7 +44,7 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
// En effet, l'évaluation dans le cas d'une variable qui a une formule, est coûteuse !
|
||||
const cacheName =
|
||||
dottedName + (node.explanation.filter ? ' .' + node.explanation.filter : '')
|
||||
const cached = cache[cacheName]
|
||||
const cached = this.cache[cacheName]
|
||||
|
||||
if (cached) return addReplacementMissingVariable(cached)
|
||||
|
||||
|
@ -55,7 +53,7 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
missingVariables: EvaluatedNode['missingVariables'],
|
||||
explanation?: Record<string, unknown>
|
||||
) => {
|
||||
cache[cacheName] = {
|
||||
this.cache[cacheName] = {
|
||||
...node,
|
||||
nodeValue,
|
||||
...(explanation && {
|
||||
|
@ -67,14 +65,10 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
...(explanation?.unit && { unit: explanation.unit }),
|
||||
missingVariables
|
||||
}
|
||||
return addReplacementMissingVariable(cache[cacheName])
|
||||
return addReplacementMissingVariable(this.cache[cacheName])
|
||||
}
|
||||
const applicabilityEvaluation = evaluateApplicability(
|
||||
cache,
|
||||
situation,
|
||||
rules,
|
||||
rule
|
||||
)
|
||||
const applicabilityEvaluation = evaluateApplicability.call(this, rule as any)
|
||||
|
||||
if (!applicabilityEvaluation.nodeValue) {
|
||||
return cacheNode(
|
||||
applicabilityEvaluation.nodeValue,
|
||||
|
@ -82,12 +76,12 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
applicabilityEvaluation
|
||||
)
|
||||
}
|
||||
if (situation[dottedName]) {
|
||||
if (this.parsedSituation[dottedName]) {
|
||||
// Conditional evaluation is required because some mecanisms like
|
||||
// "synchronisation" store raw JS objects in the situation.
|
||||
const situationValue = situation[dottedName]?.evaluate
|
||||
? evaluateNode(cache, situation, rules, situation[dottedName])
|
||||
: situation[dottedName]
|
||||
const situationValue = this.parsedSituation[dottedName]?.nodeKind
|
||||
? this.evaluateNode(this.parsedSituation[dottedName])
|
||||
: this.parsedSituation[dottedName]
|
||||
const unit =
|
||||
!situationValue.unit || serializeUnit(situationValue.unit) === ''
|
||||
? rule.unit
|
||||
|
@ -106,7 +100,7 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
}
|
||||
|
||||
if (rule.defaultValue != null) {
|
||||
const evaluation = evaluateNode(cache, situation, rules, rule.defaultValue)
|
||||
const evaluation = this.evaluateNode(rule.defaultValue)
|
||||
return cacheNode(evaluation.nodeValue ?? evaluation, {
|
||||
...evaluation.missingVariables,
|
||||
[dottedName]: 1
|
||||
|
@ -114,7 +108,7 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
}
|
||||
|
||||
if (rule.formule != null) {
|
||||
const evaluation = evaluateNode(cache, situation, rules, rule)
|
||||
const evaluation = this.evaluateNode(rule)
|
||||
return cacheNode(
|
||||
evaluation.nodeValue,
|
||||
evaluation.missingVariables,
|
||||
|
@ -130,23 +124,15 @@ Par défaut, seul le premier s'applique. Si vous voulez un autre comportement, v
|
|||
// See the unité-temporelle.yaml test suite for details
|
||||
// - filters on the variable to select one part of the variable's 'composantes'
|
||||
|
||||
export const evaluateReferenceTransforms = (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node
|
||||
) => {
|
||||
export const evaluateReferenceTransforms: evaluationFunction = function(node) {
|
||||
// Filter transformation
|
||||
const filteringSituation = {
|
||||
...situation,
|
||||
'_meta.filter': node.explanation.filter
|
||||
if (node.explanation.filter) {
|
||||
this.cache._meta.filter = node.explanation.filter
|
||||
}
|
||||
const filteredNode = this.evaluateNode(node.explanation.originalNode)
|
||||
if (node.explanation.filter) {
|
||||
delete this.cache._meta.filter
|
||||
}
|
||||
const filteredNode = evaluateNode(
|
||||
cache,
|
||||
node.explanation.filter ? filteringSituation : situation,
|
||||
parsedRules,
|
||||
node.explanation.originalNode
|
||||
)
|
||||
const { explanation, nodeValue } = filteredNode
|
||||
if (!explanation || nodeValue === null) {
|
||||
return filteredNode
|
||||
|
@ -157,7 +143,7 @@ export const evaluateReferenceTransforms = (
|
|||
return convertNodeToUnit(unit, filteredNode)
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
`Impossible de convertir la reference '${filteredNode.name}'`,
|
||||
e
|
||||
)
|
||||
|
@ -193,13 +179,11 @@ export const getApplicableReplacedBy = (contextRuleName, replacedBy) =>
|
|||
/**
|
||||
* Filter-out and apply all possible replacements at runtime.
|
||||
*/
|
||||
const getApplicableReplacements = (
|
||||
contextRuleName,
|
||||
cache,
|
||||
situation,
|
||||
rules,
|
||||
const getApplicableReplacements = function(
|
||||
this: Engine<string>,
|
||||
contextRuleName: string,
|
||||
rule: ParsedRule
|
||||
) => {
|
||||
) {
|
||||
let missingVariableList: Array<EvaluatedNode['missingVariables']> = []
|
||||
if (contextRuleName.startsWith('[evaluation]')) {
|
||||
return [[], []]
|
||||
|
@ -210,42 +194,37 @@ const getApplicableReplacements = (
|
|||
)
|
||||
// Remove remplacement defined in a not applicable node
|
||||
.filter(({ referenceNode }) => {
|
||||
const referenceRule = rules[referenceNode.dottedName]
|
||||
const referenceRule = this.parsedRules[referenceNode.dottedName]
|
||||
const {
|
||||
nodeValue: isApplicable,
|
||||
missingVariables
|
||||
} = evaluateApplicability(cache, situation, rules, referenceRule)
|
||||
} = evaluateApplicability.call(this, referenceRule as any)
|
||||
missingVariableList.push(missingVariables)
|
||||
return isApplicable
|
||||
})
|
||||
// Remove remplacement defined in a node whose situation value is false
|
||||
.filter(({ referenceNode }) => {
|
||||
const referenceRule = rules[referenceNode.dottedName]
|
||||
const situationValue = situation[referenceRule.dottedName]
|
||||
const referenceRule = this.parsedRules[referenceNode.dottedName]
|
||||
const situationValue = this.parsedSituation[referenceRule.dottedName]
|
||||
if (referenceNode.question && situationValue == null) {
|
||||
missingVariableList.push({ [referenceNode.dottedName]: 1 })
|
||||
}
|
||||
return situationValue?.nodeValue !== false
|
||||
return (situationValue as any)?.nodeValue !== false
|
||||
})
|
||||
// Remove remplacement defined in a boolean node whose evaluated value is false
|
||||
.filter(({ referenceNode }) => {
|
||||
const referenceRule = rules[referenceNode.dottedName]
|
||||
const referenceRule = this.parsedRules[referenceNode.dottedName]
|
||||
if (referenceRule.formule?.explanation?.operationType !== 'comparison') {
|
||||
return true
|
||||
}
|
||||
const { nodeValue: isApplicable, missingVariables } = evaluateNode(
|
||||
cache,
|
||||
situation,
|
||||
rules,
|
||||
const { nodeValue: isApplicable, missingVariables } = this.evaluateNode(
|
||||
referenceRule
|
||||
)
|
||||
missingVariableList.push(missingVariables)
|
||||
return isApplicable
|
||||
})
|
||||
.map(({ referenceNode, replacementNode }) =>
|
||||
replacementNode != null
|
||||
? evaluateNode(cache, situation, rules, replacementNode)
|
||||
: evaluateReference(cache, situation, rules, referenceNode)
|
||||
replacementNode != null ? replacementNode : referenceNode
|
||||
)
|
||||
.map(replacementNode => {
|
||||
const replacedRuleUnit = rule.unit
|
||||
|
|
|
@ -1,25 +1,15 @@
|
|||
import { map, pick, pipe } from 'ramda'
|
||||
import { evaluationFunction } from '.'
|
||||
import { typeWarning } from './error'
|
||||
import {
|
||||
bonus,
|
||||
evaluateNode,
|
||||
mergeMissing,
|
||||
mergeAllMissing
|
||||
} from './evaluation'
|
||||
import { bonus, mergeAllMissing, mergeMissing } from './evaluation'
|
||||
import { convertNodeToUnit } from './nodeUnits'
|
||||
import { EvaluatedNode, ParsedRule } from './types'
|
||||
|
||||
export const evaluateApplicability = (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node: ParsedRule
|
||||
): EvaluatedNode => {
|
||||
export const evaluateApplicability: evaluationFunction = function(node: any) {
|
||||
const evaluatedAttributes = pipe(
|
||||
pick(['non applicable si', 'applicable si', 'rendu non applicable']) as (
|
||||
x: any
|
||||
) => any,
|
||||
map(value => evaluateNode(cache, situation, parsedRules, value))
|
||||
map(value => this.evaluateNode(value))
|
||||
)(node) as any,
|
||||
{
|
||||
'non applicable si': notApplicable,
|
||||
|
@ -27,7 +17,7 @@ export const evaluateApplicability = (
|
|||
'rendu non applicable': disabled
|
||||
} = evaluatedAttributes,
|
||||
parentDependencies = node.parentDependencies.map(parent =>
|
||||
evaluateNode(cache, situation, parsedRules, parent)
|
||||
this.evaluateNode(parent)
|
||||
)
|
||||
|
||||
const anyDisabledParent = parentDependencies.find(
|
||||
|
@ -69,14 +59,9 @@ export const evaluateApplicability = (
|
|||
}
|
||||
}
|
||||
|
||||
export const evaluateFormula = (cache, situation, parsedRules, node) => {
|
||||
const explanation = evaluateNode(
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node.explanation
|
||||
),
|
||||
{ nodeValue, unit, missingVariables, temporalValue } = explanation
|
||||
export const evaluateFormula: evaluationFunction = function(node) {
|
||||
const explanation = this.evaluateNode(node.explanation)
|
||||
const { nodeValue, unit, missingVariables, temporalValue } = explanation
|
||||
|
||||
return {
|
||||
...node,
|
||||
|
@ -88,14 +73,9 @@ export const evaluateFormula = (cache, situation, parsedRules, node) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const evaluateRule = (cache, situation, parsedRules, node) => {
|
||||
cache._meta.contextRule.push(node.dottedName)
|
||||
const applicabilityEvaluation = evaluateApplicability(
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node
|
||||
)
|
||||
export const evaluateRule: evaluationFunction = function(node: any) {
|
||||
this.cache._meta.contextRule.push(node.dottedName)
|
||||
const applicabilityEvaluation = evaluateApplicability.call(this, node)
|
||||
const {
|
||||
missingVariables: condMissing,
|
||||
nodeValue: isApplicable
|
||||
|
@ -104,7 +84,7 @@ export const evaluateRule = (cache, situation, parsedRules, node) => {
|
|||
// evaluate the formula lazily, only if the applicability is known and true
|
||||
let evaluatedFormula =
|
||||
isApplicable && node.formule
|
||||
? evaluateNode(cache, situation, parsedRules, node.formule)
|
||||
? this.evaluateNode(node.formule)
|
||||
: node.formule
|
||||
|
||||
if (node.unit) {
|
||||
|
@ -124,7 +104,7 @@ export const evaluateRule = (cache, situation, parsedRules, node) => {
|
|||
)
|
||||
|
||||
const temporalValue = evaluatedFormula.temporalValue
|
||||
cache._meta.contextRule.pop()
|
||||
this.cache._meta.contextRule.pop()
|
||||
return {
|
||||
...node,
|
||||
...applicabilityEvaluation,
|
||||
|
@ -137,9 +117,9 @@ export const evaluateRule = (cache, situation, parsedRules, node) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const evaluateDisabledBy = (cache, situation, parsedRules, node) => {
|
||||
export const evaluateDisabledBy: evaluationFunction = function(node) {
|
||||
const isDisabledBy = node.explanation.isDisabledBy.map(disablerNode =>
|
||||
evaluateNode(cache, situation, parsedRules, disablerNode)
|
||||
this.evaluateNode(disablerNode)
|
||||
)
|
||||
const nodeValue = isDisabledBy.some(
|
||||
x => x.nodeValue !== false && x.nodeValue !== null
|
||||
|
@ -153,13 +133,8 @@ export const evaluateDisabledBy = (cache, situation, parsedRules, node) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const evaluateCondition = (cache, situation, parsedRules, node) => {
|
||||
const explanation = evaluateNode(
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node.explanation
|
||||
)
|
||||
export const evaluateCondition: evaluationFunction = function(node) {
|
||||
const explanation = this.evaluateNode(node.explanation)
|
||||
const nodeValue = explanation.nodeValue
|
||||
const missingVariables = explanation.missingVariables
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { add, evolve, fromPairs, keys, map, mergeWith, reduce } from 'ramda'
|
||||
import React from 'react'
|
||||
import Engine, { evaluationFunction } from '.'
|
||||
import { typeWarning } from './error'
|
||||
import {
|
||||
evaluateReference,
|
||||
|
@ -37,15 +38,6 @@ export const mergeAllMissing = missings =>
|
|||
export const mergeMissing = (left, right) =>
|
||||
mergeWith(add, left || {}, right || {})
|
||||
|
||||
export const evaluateNode = (cache, situation, parsedRules, node) => {
|
||||
if (!node.nodeKind) {
|
||||
throw Error('A node to evaluate must have a "nodeKind" attribute')
|
||||
} else if (!evaluationFunctions[node.nodeKind]) {
|
||||
throw Error(`Unknown "nodeKind": ${node.nodeKind}`)
|
||||
}
|
||||
return evaluationFunctions[node.nodeKind](cache, situation, parsedRules, node)
|
||||
}
|
||||
|
||||
function convertNodesToSameUnit(nodes, contextRule, mecanismName) {
|
||||
const firstNodeWithUnit = nodes.find(node => !!node.unit)
|
||||
if (!firstNodeWithUnit) {
|
||||
|
@ -67,49 +59,49 @@ function convertNodesToSameUnit(nodes, contextRule, mecanismName) {
|
|||
})
|
||||
}
|
||||
|
||||
export const evaluateArray = (reducer, start) => (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node
|
||||
) => {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
const evaluatedNodes = convertNodesToSameUnit(
|
||||
node.explanation.map(evaluate),
|
||||
cache._meta.contextRule,
|
||||
node.name
|
||||
)
|
||||
|
||||
const temporalValues = concatTemporals(
|
||||
evaluatedNodes.map(
|
||||
({ temporalValue, nodeValue }) => temporalValue ?? pureTemporal(nodeValue)
|
||||
export const evaluateArray: (
|
||||
reducer: Parameters<typeof reduce>[0],
|
||||
start: Parameters<typeof reduce>[1]
|
||||
) => evaluationFunction = (reducer, start) =>
|
||||
function(node: any) {
|
||||
const evaluate = this.evaluateNode.bind(this)
|
||||
const evaluatedNodes = convertNodesToSameUnit(
|
||||
node.explanation.map(evaluate),
|
||||
this.cache._meta.contextRule,
|
||||
node.name
|
||||
)
|
||||
)
|
||||
const temporalValue = mapTemporal(values => {
|
||||
if (values.some(value => value === null)) {
|
||||
return null
|
||||
}
|
||||
return reduce(reducer, start, values)
|
||||
}, temporalValues)
|
||||
|
||||
const baseEvaluation = {
|
||||
...node,
|
||||
missingVariables: mergeAllMissing(evaluatedNodes),
|
||||
explanation: evaluatedNodes,
|
||||
...(evaluatedNodes[0] && { unit: evaluatedNodes[0].unit })
|
||||
}
|
||||
if (temporalValue.length === 1) {
|
||||
const temporalValues = concatTemporals(
|
||||
evaluatedNodes.map(
|
||||
({ temporalValue, nodeValue }) =>
|
||||
temporalValue ?? pureTemporal(nodeValue)
|
||||
)
|
||||
)
|
||||
const temporalValue = mapTemporal(values => {
|
||||
if (values.some(value => value === null)) {
|
||||
return null
|
||||
}
|
||||
return reduce(reducer, start, values)
|
||||
}, temporalValues)
|
||||
|
||||
const baseEvaluation = {
|
||||
...node,
|
||||
missingVariables: mergeAllMissing(evaluatedNodes),
|
||||
explanation: evaluatedNodes,
|
||||
...(evaluatedNodes[0] && { unit: evaluatedNodes[0].unit })
|
||||
}
|
||||
if (temporalValue.length === 1) {
|
||||
return {
|
||||
...baseEvaluation,
|
||||
nodeValue: temporalValue[0].value
|
||||
}
|
||||
}
|
||||
return {
|
||||
...baseEvaluation,
|
||||
nodeValue: temporalValue[0].value
|
||||
temporalValue,
|
||||
nodeValue: temporalAverage(temporalValue as any)
|
||||
}
|
||||
}
|
||||
return {
|
||||
...baseEvaluation,
|
||||
temporalValue,
|
||||
nodeValue: temporalAverage(temporalValue)
|
||||
}
|
||||
}
|
||||
|
||||
export const defaultNode = (nodeValue: EvaluatedNode['nodeValue']) => ({
|
||||
nodeValue,
|
||||
|
@ -121,9 +113,10 @@ export const defaultNode = (nodeValue: EvaluatedNode['nodeValue']) => ({
|
|||
nodeKind: 'defaultNode'
|
||||
})
|
||||
|
||||
const evaluateDefaultNode = (cache, situation, parsedRules, node) => node
|
||||
const evaluateExplanationNode = (cache, situation, parsedRules, node) =>
|
||||
evaluateNode(cache, situation, parsedRules, node.explanation)
|
||||
const evaluateDefaultNode: evaluationFunction = node => node
|
||||
const evaluateExplanationNode: evaluationFunction = function(node) {
|
||||
return this.evaluateNode(node.explanation)
|
||||
}
|
||||
|
||||
export const parseObject = (recurse, objectShape, value) => {
|
||||
const recurseOne = key => defaultValue => {
|
||||
|
@ -139,71 +132,69 @@ export const parseObject = (recurse, objectShape, value) => {
|
|||
return evolve(transforms as any, objectShape)
|
||||
}
|
||||
|
||||
export const evaluateObject = (objectShape, effect) => (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node
|
||||
) => {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
const evaluations = map(evaluate, node.explanation)
|
||||
const temporalExplanations = mapTemporal(
|
||||
Object.fromEntries,
|
||||
concatTemporals(
|
||||
Object.entries(evaluations).map(([key, node]) =>
|
||||
zipTemporals(pureTemporal(key), liftTemporalNode(node))
|
||||
export const evaluateObject: (
|
||||
effet: (this: Engine<string>, explanations: any) => any
|
||||
) => evaluationFunction = effect =>
|
||||
function(node: any) {
|
||||
const evaluate = this.evaluateNode.bind(this)
|
||||
const evaluations = map(evaluate, node.explanation)
|
||||
const temporalExplanations = mapTemporal(
|
||||
Object.fromEntries,
|
||||
concatTemporals(
|
||||
Object.entries(evaluations).map(([key, node]) =>
|
||||
zipTemporals(pureTemporal(key), liftTemporalNode(node))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
const temporalExplanation = mapTemporal(explanations => {
|
||||
const evaluation = effect(explanations, cache, situation, parsedRules)
|
||||
return {
|
||||
...evaluation,
|
||||
explanation: {
|
||||
...explanations,
|
||||
...evaluation.explanation
|
||||
const temporalExplanation = mapTemporal(explanations => {
|
||||
const evaluation = effect.call(this, explanations)
|
||||
return {
|
||||
...evaluation,
|
||||
explanation: {
|
||||
...explanations,
|
||||
...evaluation.explanation
|
||||
}
|
||||
}
|
||||
}, temporalExplanations)
|
||||
|
||||
const sameUnitTemporalExplanation: Temporal<EvaluatedNode<
|
||||
string,
|
||||
number
|
||||
>> = convertNodesToSameUnit(
|
||||
temporalExplanation.map(x => x.value),
|
||||
this.cache._meta.contextRule,
|
||||
node.name
|
||||
).map((node, i) => ({
|
||||
...temporalExplanation[i],
|
||||
value: simplifyNodeUnit(node)
|
||||
}))
|
||||
|
||||
const temporalValue = mapTemporal(
|
||||
({ nodeValue }) => nodeValue,
|
||||
sameUnitTemporalExplanation
|
||||
)
|
||||
const nodeValue = temporalAverage(temporalValue)
|
||||
const baseEvaluation = {
|
||||
...node,
|
||||
nodeValue,
|
||||
unit: sameUnitTemporalExplanation[0].value.unit,
|
||||
explanation: evaluations,
|
||||
missingVariables: mergeAllMissing(Object.values(evaluations))
|
||||
}
|
||||
if (sameUnitTemporalExplanation.length === 1) {
|
||||
return {
|
||||
...baseEvaluation,
|
||||
explanation: sameUnitTemporalExplanation[0].value.explanation
|
||||
}
|
||||
}
|
||||
}, temporalExplanations)
|
||||
|
||||
const sameUnitTemporalExplanation: Temporal<EvaluatedNode<
|
||||
string,
|
||||
number
|
||||
>> = convertNodesToSameUnit(
|
||||
temporalExplanation.map(x => x.value),
|
||||
cache._meta.contextRule,
|
||||
node.name
|
||||
).map((node, i) => ({
|
||||
...temporalExplanation[i],
|
||||
value: simplifyNodeUnit(node)
|
||||
}))
|
||||
|
||||
const temporalValue = mapTemporal(
|
||||
({ nodeValue }) => nodeValue,
|
||||
sameUnitTemporalExplanation
|
||||
)
|
||||
const nodeValue = temporalAverage(temporalValue)
|
||||
const baseEvaluation = {
|
||||
...node,
|
||||
nodeValue,
|
||||
unit: sameUnitTemporalExplanation[0].value.unit,
|
||||
explanation: evaluations,
|
||||
missingVariables: mergeAllMissing(Object.values(evaluations))
|
||||
}
|
||||
if (sameUnitTemporalExplanation.length === 1) {
|
||||
return {
|
||||
...baseEvaluation,
|
||||
explanation: sameUnitTemporalExplanation[0].value.explanation
|
||||
temporalValue,
|
||||
temporalExplanation
|
||||
}
|
||||
}
|
||||
return {
|
||||
...baseEvaluation,
|
||||
temporalValue,
|
||||
temporalExplanation
|
||||
}
|
||||
}
|
||||
|
||||
const evaluationFunctions = {
|
||||
export const evaluationFunctions = {
|
||||
rule: evaluateRule,
|
||||
formula: evaluateFormula,
|
||||
disabledBy: evaluateDisabledBy,
|
||||
|
@ -215,7 +206,10 @@ const evaluationFunctions = {
|
|||
defaultNode: evaluateDefaultNode
|
||||
}
|
||||
|
||||
export function registerEvaluationFunction(nodeKind, evaluationFunction) {
|
||||
export function registerEvaluationFunction(
|
||||
nodeKind: string,
|
||||
evaluationFunction: any // TODO: type evaluationFunction
|
||||
) {
|
||||
if (evaluationFunctions[nodeKind]) {
|
||||
throw Error(
|
||||
`Multiple evaluation functions registered for the nodeKind \x1b[4m${nodeKind}`
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { map } from 'ramda'
|
||||
import { evaluationError, warning } from './error'
|
||||
import { evaluateNode } from './evaluation'
|
||||
import { evaluationFunctions } from './evaluation'
|
||||
import { convertNodeToUnit, simplifyNodeUnit } from './nodeUnits'
|
||||
import { parse } from './parse'
|
||||
import parseRules from './parseRules'
|
||||
import * as utils from './ruleUtils'
|
||||
import { EvaluatedNode, EvaluatedRule, ParsedRules, Rules } from './types'
|
||||
import { parseUnit } from './units'
|
||||
import * as utils from './ruleUtils'
|
||||
|
||||
const emptyCache = () => ({
|
||||
_meta: { contextRule: [] }
|
||||
|
@ -16,10 +16,14 @@ const emptyCache = () => ({
|
|||
type Cache = {
|
||||
_meta: {
|
||||
contextRule: Array<string>
|
||||
inversionFail?: {
|
||||
given: string
|
||||
estimated: string
|
||||
}
|
||||
inversionFail?:
|
||||
| {
|
||||
given: string
|
||||
estimated: string
|
||||
}
|
||||
| true
|
||||
inRecalcul?: boolean
|
||||
filter?: string
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,21 +34,26 @@ export type EvaluationOptions = Partial<{
|
|||
}>
|
||||
|
||||
export * from './components'
|
||||
export { default as cyclesLib } from './cyclesLib/index'
|
||||
export { formatValue, serializeValue } from './format'
|
||||
export { default as translateRules } from './translateRules'
|
||||
export { default as cyclesLib } from './cyclesLib/index'
|
||||
export * from './types'
|
||||
export { parseRules }
|
||||
export { utils }
|
||||
export type evaluationFunction = (
|
||||
this: Engine<string>,
|
||||
node: EvaluatedNode
|
||||
) => EvaluatedNode
|
||||
|
||||
export default class Engine<Names extends string> {
|
||||
parsedRules: ParsedRules<Names>
|
||||
parsedSituation: ParsedSituation<Names> = {}
|
||||
private cache: Cache
|
||||
cache: Cache
|
||||
private warnings: Array<string> = []
|
||||
|
||||
constructor(rules: string | Rules<Names> | ParsedRules<Names>) {
|
||||
this.cache = emptyCache()
|
||||
this.resetCache()
|
||||
this.parsedRules =
|
||||
typeof rules === 'string' || !(Object.values(rules)[0] as any)?.dottedName
|
||||
? parseRules(rules)
|
||||
|
@ -67,10 +76,7 @@ export default class Engine<Names extends string> {
|
|||
originalWarn(warning)
|
||||
}
|
||||
const result = simplifyNodeUnit(
|
||||
evaluateNode(
|
||||
this.cache,
|
||||
this.parsedSituation,
|
||||
this.parsedRules,
|
||||
this.evaluateNode(
|
||||
parse(
|
||||
this.parsedRules,
|
||||
{ dottedName: context },
|
||||
|
@ -156,4 +162,14 @@ export default class Engine<Names extends string> {
|
|||
getParsedRules(): ParsedRules<Names> {
|
||||
return this.parsedRules
|
||||
}
|
||||
|
||||
evaluateNode(node) {
|
||||
if (!node.nodeKind) {
|
||||
throw Error('The provided node must have a "nodeKind" attribute')
|
||||
} else if (!evaluationFunctions[node.nodeKind]) {
|
||||
throw Error(`Unknown "nodeKind": ${node.nodeKind}`)
|
||||
}
|
||||
|
||||
return evaluationFunctions[node.nodeKind].call(this, node)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { InfixMecanism } from '../components/mecanisms/common'
|
||||
import {
|
||||
bonus,
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -19,17 +19,11 @@ function MecanismApplicable({ explanation }) {
|
|||
)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const condition = evaluateAttribute(node.explanation.condition)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const condition = this.evaluateNode(node.explanation.condition)
|
||||
let valeur = node.explanation.valeur
|
||||
if (condition.nodeValue !== false) {
|
||||
valeur = evaluateAttribute(valeur)
|
||||
valeur = this.evaluateNode(valeur)
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { InfixMecanism } from '../components/mecanisms/common'
|
||||
import {
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -28,18 +28,12 @@ function roundWithPrecision(n: number, fractionDigits: number) {
|
|||
return +n.toFixed(fractionDigits)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const valeur = evaluateAttribute(node.explanation.valeur)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const valeur = this.evaluateNode(node.explanation.valeur)
|
||||
const nodeValue = valeur.nodeValue
|
||||
let arrondi = node.explanation.arrondi
|
||||
if (nodeValue !== false) {
|
||||
arrondi = evaluateAttribute(arrondi)
|
||||
arrondi = this.evaluateNode(arrondi)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { evaluationFunction } from '..'
|
||||
import Barème from '../components/mecanisms/Barème'
|
||||
import { evaluationError } from '../error'
|
||||
import {
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
|
@ -76,31 +76,27 @@ function evaluateBarème(tranches, assiette, evaluate, cache) {
|
|||
}
|
||||
})
|
||||
}
|
||||
const evaluate = (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node: ReturnType<typeof parse>
|
||||
) => {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
const assiette = evaluate(node.explanation.assiette)
|
||||
const multiplicateur = evaluate(node.explanation.multiplicateur)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const evaluateNode = this.evaluateNode.bind(this)
|
||||
const assiette = this.evaluateNode(node.explanation.assiette)
|
||||
const multiplicateur = this.evaluateNode(node.explanation.multiplicateur)
|
||||
const temporalTranchesPlafond = liftTemporal2(
|
||||
(assiette, multiplicateur) =>
|
||||
evaluatePlafondUntilActiveTranche(
|
||||
evaluate,
|
||||
evaluateNode,
|
||||
{
|
||||
parsedTranches: node.explanation.tranches,
|
||||
assiette,
|
||||
multiplicateur
|
||||
},
|
||||
cache
|
||||
this.cache
|
||||
),
|
||||
liftTemporalNode(assiette),
|
||||
liftTemporalNode(multiplicateur)
|
||||
)
|
||||
const temporalTranches = liftTemporal2(
|
||||
(tranches, assiette) => evaluateBarème(tranches, assiette, evaluate, cache),
|
||||
(tranches, assiette) =>
|
||||
evaluateBarème(tranches, assiette, evaluateNode, this.cache),
|
||||
temporalTranchesPlafond,
|
||||
liftTemporalNode(assiette)
|
||||
)
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
import { add, dissoc, filter, objOf } from 'ramda'
|
||||
import { evaluationFunction } from '..'
|
||||
import Composantes from '../components/mecanisms/Composantes'
|
||||
import { evaluateArray, registerEvaluationFunction } from '../evaluation'
|
||||
import { inferUnit } from '../units'
|
||||
import Composantes from '../components/mecanisms/Composantes'
|
||||
|
||||
export const evaluateComposantes = (cache, situation, parsedRules, node) => {
|
||||
export const evaluateComposantes: evaluationFunction = function(node) {
|
||||
const evaluationFilter = c =>
|
||||
!situation['_meta.filter'] ||
|
||||
!this.cache._meta.filter ||
|
||||
!c.composante ||
|
||||
((!c.composante['dû par'] ||
|
||||
!['employeur', 'salarié'].includes(situation['_meta.filter']) ||
|
||||
c.composante['dû par'] == situation['_meta.filter']) &&
|
||||
!['employeur', 'salarié'].includes(this.cache._meta.filter as any) ||
|
||||
c.composante['dû par'] == this.cache._meta.filter) &&
|
||||
(!c.composante['impôt sur le revenu'] ||
|
||||
!['déductible', 'non déductible'].includes(situation['_meta.filter']) ||
|
||||
c.composante['impôt sur le revenu'] == situation['_meta.filter']))
|
||||
|
||||
return evaluateArray(add, 0)(
|
||||
cache,
|
||||
dissoc('_meta.filter', situation),
|
||||
parsedRules,
|
||||
{
|
||||
...node,
|
||||
explanation: filter(evaluationFilter, node.explanation)
|
||||
}
|
||||
)
|
||||
!['déductible', 'non déductible'].includes(
|
||||
this.cache._meta.filter as any
|
||||
) ||
|
||||
c.composante['impôt sur le revenu'] == this.cache._meta.filter))
|
||||
return evaluateArray(add as any, 0).call(this, {
|
||||
...node,
|
||||
explanation: filter(evaluationFilter, node.explanation)
|
||||
})
|
||||
}
|
||||
|
||||
export const decompose = (recurse, k, v) => {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { is, map } from 'ramda'
|
||||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { Mecanism } from '../components/mecanisms/common'
|
||||
import {
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const [nodeValue, explanation] = node.explanation.reduce(
|
||||
([nodeValue, explanation], node) => {
|
||||
if (nodeValue === false) {
|
||||
return [nodeValue, [...explanation, node]]
|
||||
}
|
||||
const evaluatedNode = evaluateNode(cache, situation, parsedRules, node)
|
||||
const evaluatedNode = this.evaluateNode(node)
|
||||
return [
|
||||
nodeValue === false || nodeValue === null
|
||||
? nodeValue
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import { is, map, max, mergeWith, reduce } from 'ramda'
|
||||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { Mecanism } from '../components/mecanisms/common'
|
||||
import {
|
||||
collectNodeMissing,
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateOne = child =>
|
||||
evaluateNode(cache, situation, parsedRules, child)
|
||||
const explanation = map(evaluateOne, node.explanation)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const explanation = node.explanation.map(child => this.evaluateNode(child))
|
||||
|
||||
const anyTrue = explanation.find(e => e.nodeValue === true)
|
||||
const anyNull = explanation.find(e => e.nodeValue === null)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { Mecanism } from '../components/mecanisms/common'
|
||||
import { convertToDate, convertToString } from '../date'
|
||||
import {
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
parseObject,
|
||||
|
@ -34,15 +34,9 @@ const objectShape = {
|
|||
"jusqu'à": defaultNode(todayString)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const from = evaluateAttribute(node.explanation.depuis)
|
||||
const to = evaluateAttribute(node.explanation["jusqu'à"])
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const from = this.evaluateNode(node.explanation.depuis)
|
||||
const to = this.evaluateNode(node.explanation["jusqu'à"])
|
||||
let nodeValue
|
||||
if ([from, to].some(({ nodeValue }) => nodeValue === null)) {
|
||||
nodeValue = null
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { lensPath, over } from 'ramda'
|
||||
import { evaluationFunction } from '..'
|
||||
import grille from '../components/mecanisms/Grille'
|
||||
import {
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
|
@ -52,15 +52,10 @@ const evaluateGrille = (tranches, evaluate) =>
|
|||
}
|
||||
})
|
||||
|
||||
const evaluate = (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node: ReturnType<typeof parse>
|
||||
) => {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
const assiette = evaluate(node.explanation.assiette)
|
||||
const multiplicateur = evaluate(node.explanation.multiplicateur)
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const evaluate = this.evaluateNode.bind(this)
|
||||
const assiette = this.evaluateNode(node.explanation.assiette)
|
||||
const multiplicateur = this.evaluateNode(node.explanation.multiplicateur)
|
||||
const temporalTranchesPlafond = liftTemporal2(
|
||||
(assiette, multiplicateur) =>
|
||||
evaluatePlafondUntilActiveTranche(
|
||||
|
@ -70,7 +65,7 @@ const evaluate = (
|
|||
assiette,
|
||||
multiplicateur
|
||||
},
|
||||
cache
|
||||
this.cache
|
||||
),
|
||||
liftTemporalNode(assiette),
|
||||
liftTemporalNode(multiplicateur)
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { evaluationFunction } from '..'
|
||||
import InversionNumérique from '../components/mecanisms/InversionNumérique'
|
||||
import { evaluateNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { registerEvaluationFunction } from '../evaluation'
|
||||
import { convertNodeToUnit } from '../nodeUnits'
|
||||
import uniroot from '../uniroot'
|
||||
import { parseUnit } from '../units'
|
||||
|
||||
export const evaluateInversion = (oldCache, situation, parsedRules, node) => {
|
||||
export const evaluateInversion: evaluationFunction = function(node) {
|
||||
// TODO : take applicability into account here
|
||||
let inversedWith = node.explanation.inversionCandidates.find(
|
||||
n => situation[n.dottedName] != undefined
|
||||
n => this.parsedSituation[n.dottedName] != undefined
|
||||
)
|
||||
if (!inversedWith) {
|
||||
return {
|
||||
|
@ -21,28 +22,24 @@ export const evaluateInversion = (oldCache, situation, parsedRules, node) => {
|
|||
nodeValue: null
|
||||
}
|
||||
}
|
||||
inversedWith = evaluateNode(oldCache, situation, parsedRules, inversedWith)
|
||||
let inversionCache
|
||||
function resetInversionCache() {
|
||||
inversionCache = {
|
||||
_meta: { ...oldCache._meta }
|
||||
inversedWith = this.evaluateNode(inversedWith)
|
||||
const originalCache = { ...this.cache }
|
||||
const originalSituation = { ...this.parsedSituation }
|
||||
const evaluateWithValue = (n: number) => {
|
||||
this.cache = {
|
||||
_meta: { ...originalCache._meta }
|
||||
}
|
||||
return inversionCache
|
||||
this.parsedSituation = {
|
||||
...originalSituation,
|
||||
[inversedWith.dottedName]: undefined,
|
||||
[node.explanation.ruleToInverse]: {
|
||||
nodeValue: n,
|
||||
unit: this.parsedRules[node.explanation.ruleToInverse].unit
|
||||
}
|
||||
}
|
||||
return this.evaluateNode(inversedWith)
|
||||
}
|
||||
const evaluateWithValue = (n: number) =>
|
||||
evaluateNode(
|
||||
resetInversionCache(),
|
||||
{
|
||||
...situation,
|
||||
[inversedWith.dottedName]: undefined,
|
||||
[node.explanation.ruleToInverse]: {
|
||||
nodeValue: n,
|
||||
unit: parsedRules[node.explanation.ruleToInverse].unit
|
||||
}
|
||||
},
|
||||
parsedRules,
|
||||
inversedWith
|
||||
)
|
||||
|
||||
// si fx renvoie null pour une valeur numérique standard, disons 2000, on peut
|
||||
// considérer que l'inversion est impossible du fait de variables manquantes
|
||||
// TODO fx peut être null pour certains x, et valide pour d'autres : on peut implémenter ici le court-circuit
|
||||
|
@ -68,13 +65,15 @@ export const evaluateInversion = (oldCache, situation, parsedRules, node) => {
|
|||
1
|
||||
)
|
||||
if (nodeValue === undefined) {
|
||||
oldCache._meta.inversionFail = true
|
||||
originalCache._meta.inversionFail = true
|
||||
} else {
|
||||
// For performance reason, we transfer the inversion cache
|
||||
Object.entries(inversionCache).forEach(([k, value]) => {
|
||||
oldCache[k] = value
|
||||
Object.entries(this.cache).forEach(([k, value]) => {
|
||||
originalCache[k] = value
|
||||
})
|
||||
}
|
||||
this.cache = originalCache
|
||||
this.parsedSituation = originalSituation
|
||||
return {
|
||||
...node,
|
||||
nodeValue: nodeValue ?? null,
|
||||
|
@ -103,9 +102,9 @@ export const mecanismInversion = dottedName => (recurse, v) => {
|
|||
jsx: InversionNumérique,
|
||||
category: 'mecanism',
|
||||
name: 'inversion numérique',
|
||||
nodeKind: 'inversion numérique',
|
||||
nodeKind: 'inversion',
|
||||
type: 'numeric'
|
||||
}
|
||||
}
|
||||
|
||||
registerEvaluationFunction('inversion numérique', evaluateInversion)
|
||||
registerEvaluationFunction('inversion', evaluateInversion)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { InfixMecanism } from '../components/mecanisms/common'
|
||||
import {
|
||||
bonus,
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -19,17 +19,11 @@ function MecanismNonApplicable({ explanation }) {
|
|||
)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const condition = evaluateAttribute(node.explanation.condition)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const condition = this.evaluateNode(node.explanation.condition)
|
||||
let valeur = node.explanation.valeur
|
||||
if (condition.nodeValue !== true) {
|
||||
valeur = evaluateAttribute(valeur)
|
||||
valeur = this.evaluateNode(valeur)
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
|
|
|
@ -8,10 +8,7 @@ export const mecanismOnePossibility = dottedName => (recurse, v) => ({
|
|||
nodeKind: 'une possibilité'
|
||||
})
|
||||
|
||||
registerEvaluationFunction(
|
||||
'une possibilité',
|
||||
(cache, situation, parsedRules, node) => ({
|
||||
...node,
|
||||
missingVariables: { [node.context]: 1 }
|
||||
})
|
||||
)
|
||||
registerEvaluationFunction('une possibilité', node => ({
|
||||
...node,
|
||||
missingVariables: { [node.context]: 1 }
|
||||
}))
|
||||
|
|
|
@ -12,11 +12,11 @@ import {
|
|||
subtract
|
||||
} from 'ramda'
|
||||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { Operation } from '../components/mecanisms/common'
|
||||
import { convertToDate } from '../date'
|
||||
import { typeWarning } from '../error'
|
||||
import {
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -50,11 +50,8 @@ const parse = (k, symbol) => (recurse, v) => {
|
|||
}
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const explanation = map(
|
||||
node => evaluateNode(cache, situation, parsedRules, node),
|
||||
node.explanation
|
||||
)
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const explanation = map(node => this.evaluateNode(node), node.explanation)
|
||||
let [node1, node2] = explanation
|
||||
const missingVariables = mergeAllMissing([node1, node2])
|
||||
|
||||
|
@ -70,7 +67,7 @@ const evaluate = (cache, situation, parsedRules, node) => {
|
|||
}
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
`Dans l'expression '${
|
||||
node.operator
|
||||
}', la partie gauche (unité: ${serializeUnit(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { InfixMecanism } from '../components/mecanisms/common'
|
||||
import { typeWarning } from '../error'
|
||||
import {
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -26,25 +26,19 @@ function MecanismPlafond({ explanation }) {
|
|||
)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const valeur = evaluateAttribute(node.explanation.valeur)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const valeur = this.evaluateNode(node.explanation.valeur)
|
||||
|
||||
let nodeValue = valeur.nodeValue
|
||||
let plafond = node.explanation.plafond
|
||||
if (nodeValue !== false) {
|
||||
plafond = evaluateAttribute(plafond)
|
||||
plafond = this.evaluateNode(plafond)
|
||||
if (valeur.unit) {
|
||||
try {
|
||||
plafond = convertNodeToUnit(valeur.unit, plafond)
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
"L'unité du plafond n'est pas compatible avec celle de la valeur à encadrer",
|
||||
e
|
||||
)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { InfixMecanism } from '../components/mecanisms/common'
|
||||
import { typeWarning } from '../error'
|
||||
import {
|
||||
evaluateNode,
|
||||
makeJsx,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
|
@ -26,24 +26,18 @@ function MecanismPlancher({ explanation }) {
|
|||
)
|
||||
}
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
const valeur = evaluateAttribute(node.explanation.valeur)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const valeur = this.evaluateNode(node.explanation.valeur)
|
||||
let nodeValue = valeur.nodeValue
|
||||
let plancher = node.explanation.plancher
|
||||
if (nodeValue !== false) {
|
||||
plancher = evaluateAttribute(plancher)
|
||||
plancher = this.evaluateNode(plancher)
|
||||
if (valeur.unit) {
|
||||
try {
|
||||
plancher = convertNodeToUnit(valeur.unit, plancher)
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
"L'unité du plancher n'est pas compatible avec celle de la valeur à encadrer",
|
||||
e
|
||||
)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { evaluationFunction } from '..'
|
||||
import Product from '../components/mecanisms/Product'
|
||||
import { typeWarning } from '../error'
|
||||
import {
|
||||
|
@ -35,13 +36,18 @@ export const mecanismProduct = (recurse, v) => {
|
|||
}
|
||||
}
|
||||
|
||||
const effect = ({ assiette, taux, facteur, plafond }, cache) => {
|
||||
const productEffect: evaluationFunction = function({
|
||||
assiette,
|
||||
taux,
|
||||
facteur,
|
||||
plafond
|
||||
}: any) {
|
||||
if (assiette.unit) {
|
||||
try {
|
||||
plafond = convertNodeToUnit(assiette.unit, plafond)
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
"Impossible de convertir l'unité du plafond du produit dans celle de l'assiette",
|
||||
e
|
||||
)
|
||||
|
@ -78,6 +84,6 @@ const effect = ({ assiette, taux, facteur, plafond }, cache) => {
|
|||
})
|
||||
}
|
||||
|
||||
const evaluate = evaluateObject(objectShape, effect)
|
||||
const evaluate = evaluateObject(productEffect)
|
||||
|
||||
registerEvaluationFunction('produit', evaluate)
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
import { evaluationFunction } from '..'
|
||||
import Recalcul from '../components/mecanisms/Recalcul'
|
||||
import {
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
import { defaultNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { EvaluatedNode } from '../types'
|
||||
import { serializeUnit } from '../units'
|
||||
|
||||
const evaluateRecalcul = (cache, situation, parsedRules, node) => {
|
||||
if (cache._meta.inRecalcul) {
|
||||
return defaultNode(false)
|
||||
const evaluateRecalcul: evaluationFunction = function(node) {
|
||||
if (this.cache._meta.inRecalcul) {
|
||||
return (defaultNode(false) as any) as EvaluatedNode
|
||||
}
|
||||
|
||||
const amendedSituation = node.explanation.amendedSituation
|
||||
.map(([originRule, replacement]) => [
|
||||
evaluateNode(cache, situation, parsedRules, originRule),
|
||||
evaluateNode(cache, situation, parsedRules, replacement)
|
||||
this.evaluateNode(originRule),
|
||||
this.evaluateNode(replacement)
|
||||
])
|
||||
.filter(
|
||||
([originRule, replacement]) =>
|
||||
|
@ -22,25 +20,25 @@ const evaluateRecalcul = (cache, situation, parsedRules, node) => {
|
|||
serializeUnit(originRule.unit) !== serializeUnit(replacement.unit)
|
||||
)
|
||||
|
||||
const originalCache = this.cache
|
||||
const originalSituation = this.parsedSituation
|
||||
// Optimisation : no need for recalcul if situation is the same
|
||||
const recalculCache = Object.keys(amendedSituation).length
|
||||
? { _meta: { ...cache._meta, inRecalcul: true } } // Create an empty cache
|
||||
: cache
|
||||
this.cache = Object.keys(amendedSituation).length
|
||||
? { _meta: { ...this.cache._meta, inRecalcul: true } } // Create an empty cache
|
||||
: this.cache
|
||||
this.parsedSituation = {
|
||||
...this.parsedSituation,
|
||||
...Object.fromEntries(
|
||||
amendedSituation.map(([originRule, replacement]) => [
|
||||
originRule.dottedName,
|
||||
replacement
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
const evaluatedNode = evaluateNode(
|
||||
recalculCache,
|
||||
{
|
||||
...situation,
|
||||
...Object.fromEntries(
|
||||
amendedSituation.map(([originRule, replacement]) => [
|
||||
originRule.dottedName,
|
||||
replacement
|
||||
])
|
||||
)
|
||||
},
|
||||
parsedRules,
|
||||
node.explanation.recalcul
|
||||
)
|
||||
const evaluatedNode = this.evaluateNode(node.explanation.recalcul)
|
||||
this.cache = originalCache
|
||||
this.parsedSituation = originalSituation
|
||||
return {
|
||||
...node,
|
||||
nodeValue: evaluatedNode.nodeValue,
|
||||
|
|
|
@ -16,51 +16,49 @@ const objectShape = {
|
|||
plafond: defaultNode(Infinity)
|
||||
}
|
||||
|
||||
const evaluate = evaluateObject(
|
||||
objectShape,
|
||||
({ assiette, abattement, plafond }, cache) => {
|
||||
const assietteValue = assiette.nodeValue
|
||||
if (assietteValue == null) return { nodeValue: null }
|
||||
if (assiette.unit) {
|
||||
try {
|
||||
plafond = convertNodeToUnit(assiette.unit, plafond)
|
||||
if (serializeUnit(abattement.unit) !== '%') {
|
||||
abattement = convertNodeToUnit(assiette.unit, abattement)
|
||||
}
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contextRule,
|
||||
"Impossible de convertir les unités de l'allègement entre elles",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
const nodeValue = abattement
|
||||
? abattement.nodeValue == null
|
||||
? assietteValue === 0
|
||||
? 0
|
||||
: null
|
||||
: serializeUnit(abattement.unit) === '%'
|
||||
? max(
|
||||
0,
|
||||
assietteValue -
|
||||
min(
|
||||
plafond.nodeValue,
|
||||
(abattement.nodeValue / 100) * assietteValue
|
||||
)
|
||||
)
|
||||
: max(0, assietteValue - min(plafond.nodeValue, abattement.nodeValue))
|
||||
: assietteValue
|
||||
return {
|
||||
nodeValue,
|
||||
unit: assiette.unit,
|
||||
explanation: {
|
||||
plafond,
|
||||
abattement
|
||||
const evaluate = evaluateObject(function({
|
||||
assiette,
|
||||
abattement,
|
||||
plafond
|
||||
}: any) {
|
||||
const assietteValue = assiette.nodeValue
|
||||
if (assietteValue == null) return { nodeValue: null }
|
||||
if (assiette.unit) {
|
||||
try {
|
||||
plafond = convertNodeToUnit(assiette.unit, plafond)
|
||||
if (serializeUnit(abattement.unit) !== '%') {
|
||||
abattement = convertNodeToUnit(assiette.unit, abattement)
|
||||
}
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
this.cache._meta.contextRule,
|
||||
"Impossible de convertir les unités de l'allègement entre elles",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
const nodeValue = abattement
|
||||
? abattement.nodeValue == null
|
||||
? assietteValue === 0
|
||||
? 0
|
||||
: null
|
||||
: serializeUnit(abattement.unit) === '%'
|
||||
? max(
|
||||
0,
|
||||
assietteValue -
|
||||
min(plafond.nodeValue, (abattement.nodeValue / 100) * assietteValue)
|
||||
)
|
||||
: max(0, assietteValue - min(plafond.nodeValue, abattement.nodeValue))
|
||||
: assietteValue
|
||||
return {
|
||||
nodeValue,
|
||||
unit: assiette.unit,
|
||||
explanation: {
|
||||
plafond,
|
||||
abattement
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const mecanismReduction = (recurse, v) => {
|
||||
const explanation = parseObject(recurse, objectShape, v)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { map } from 'ramda'
|
||||
import { evaluationFunction } from '..'
|
||||
import { convertToString, getYear } from '../date'
|
||||
import { evaluationError } from '../error'
|
||||
import { evaluateNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { registerEvaluationFunction } from '../evaluation'
|
||||
import {
|
||||
createTemporalEvaluation,
|
||||
groupByYear,
|
||||
|
@ -84,19 +85,19 @@ function getMonthlyCumulatedValuesOverYear(
|
|||
return cumulatedPeriods
|
||||
}
|
||||
|
||||
function evaluate(cache, situation, parsedRules, node) {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
|
||||
function recalculWith(newSituation, node) {
|
||||
return evaluateNode(
|
||||
{ _meta: cache._meta },
|
||||
{ ...situation, ...newSituation },
|
||||
parsedRules,
|
||||
node
|
||||
)
|
||||
const evaluate: evaluationFunction = function(node) {
|
||||
const recalculWith = (newSituation, node) => {
|
||||
const originalCache = this.cache
|
||||
const originalSituation = this.parsedSituation
|
||||
this.cache = { _meta: originalCache._meta }
|
||||
this.parsedSituation = { ...originalSituation, ...newSituation }
|
||||
const res = this.evaluateNode(node)
|
||||
this.cache = originalCache
|
||||
this.parsedSituation = originalSituation
|
||||
return res
|
||||
}
|
||||
|
||||
function regulariseYear(temporalEvaluation: Temporal<Evaluation<number>>) {
|
||||
const regulariseYear = (temporalEvaluation: Temporal<Evaluation<number>>) => {
|
||||
if (temporalEvaluation.filter(({ value }) => value !== false).length <= 1) {
|
||||
return temporalEvaluation
|
||||
}
|
||||
|
@ -107,10 +108,10 @@ function evaluate(cache, situation, parsedRules, node) {
|
|||
value: Record<string, unknown>
|
||||
}>).reduce<Record<string, Temporal<Evaluation<number>>>>(
|
||||
(acc, { dottedName, value }) => {
|
||||
const evaluation = evaluate(value)
|
||||
const evaluation = this.evaluateNode(value)
|
||||
if (!evaluation.unit.denominators.some(unit => unit === 'mois')) {
|
||||
evaluationError(
|
||||
cache._meta.contextRule,
|
||||
this.cache._meta.contextRule,
|
||||
`Dans le mécanisme régularisation, la valeur cumulée '${dottedName}' n'est pas une variable numérique définie sur le mois`
|
||||
)
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ function evaluate(cache, situation, parsedRules, node) {
|
|||
return temporalRégularisée as Temporal<Evaluation<number>>
|
||||
}
|
||||
|
||||
const evaluation = evaluate(node.explanation.rule)
|
||||
const evaluation = this.evaluateNode(node.explanation.rule)
|
||||
const temporalValue = evaluation.temporalValue
|
||||
const evaluationWithRegularisation = groupByYear(
|
||||
temporalValue as Temporal<Evaluation<number>>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { evaluateArray, registerEvaluationFunction } from '../evaluation'
|
|||
import { inferUnit } from '../units'
|
||||
|
||||
const evaluate = evaluateArray(
|
||||
(x, y) => (x === false && y === false ? false : x + y),
|
||||
(x: any, y: any) => (x === false && y === false ? false : x + y),
|
||||
false
|
||||
)
|
||||
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import { path } from 'ramda'
|
||||
import React from 'react'
|
||||
import { evaluationFunction } from '..'
|
||||
import { RuleLinkWithContext } from '../components/RuleLink'
|
||||
import { evaluateNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { registerEvaluationFunction } from '../evaluation'
|
||||
|
||||
const evaluate = (cache, situation, parsedRules, node) => {
|
||||
const APIExplanation = evaluateNode(
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node.explanation.API
|
||||
)
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const APIExplanation = this.evaluateNode(node.explanation.API)
|
||||
const valuePath = node.explanation.chemin.split(' . ')
|
||||
const nodeValue =
|
||||
APIExplanation.nodeValue == null
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { evaluationFunction } from '..'
|
||||
import tauxProgressif from '../components/mecanisms/TauxProgressif'
|
||||
import {
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
mergeAllMissing,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
|
@ -29,15 +29,10 @@ export default function parse(parse, v) {
|
|||
}
|
||||
}
|
||||
|
||||
const evaluate = (
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node: ReturnType<typeof parse>
|
||||
) => {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
const assiette = evaluate(node.explanation.assiette)
|
||||
const multiplicateur = evaluate(node.explanation.multiplicateur)
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const evaluate = this.evaluateNode.bind(this)
|
||||
const assiette = this.evaluateNode(node.explanation.assiette)
|
||||
const multiplicateur = this.evaluateNode(node.explanation.multiplicateur)
|
||||
const tranches = evaluatePlafondUntilActiveTranche(
|
||||
evaluate,
|
||||
{
|
||||
|
@ -45,7 +40,7 @@ const evaluate = (
|
|||
assiette,
|
||||
multiplicateur
|
||||
},
|
||||
cache
|
||||
this.cache
|
||||
)
|
||||
|
||||
const evaluatedNode = {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { evaluateNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { evaluationFunction } from '..'
|
||||
import { registerEvaluationFunction } from '../evaluation'
|
||||
import {
|
||||
createTemporalEvaluation,
|
||||
narrowTemporalValue,
|
||||
|
@ -6,26 +7,14 @@ import {
|
|||
temporalAverage
|
||||
} from '../temporal'
|
||||
|
||||
function evaluate(
|
||||
cache: any,
|
||||
situation: any,
|
||||
parsedRules: any,
|
||||
node: ReturnType<typeof parseVariableTemporelle>
|
||||
) {
|
||||
const evaluateAttribute = evaluateNode.bind(
|
||||
null,
|
||||
cache,
|
||||
situation,
|
||||
parsedRules
|
||||
)
|
||||
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const start =
|
||||
node.explanation.period.start &&
|
||||
evaluateAttribute(node.explanation.period.start)
|
||||
this.evaluateNode(node.explanation.period.start)
|
||||
const end =
|
||||
node.explanation.period.end &&
|
||||
evaluateAttribute(node.explanation.period.end)
|
||||
const value = evaluateAttribute(node.explanation.value)
|
||||
this.evaluateNode(node.explanation.period.end)
|
||||
const value = this.evaluateNode(node.explanation.value)
|
||||
const period = {
|
||||
start: start?.nodeValue || null,
|
||||
end: end?.nodeValue || null
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
import { or } from 'ramda'
|
||||
import { evaluationFunction } from '..'
|
||||
import Variations from '../components/mecanisms/Variations'
|
||||
import { typeWarning } from '../error'
|
||||
import {
|
||||
bonus,
|
||||
defaultNode,
|
||||
evaluateNode,
|
||||
registerEvaluationFunction
|
||||
} from '../evaluation'
|
||||
import { bonus, defaultNode, registerEvaluationFunction } from '../evaluation'
|
||||
import { convertNodeToUnit } from '../nodeUnits'
|
||||
import {
|
||||
liftTemporal2,
|
||||
|
@ -82,14 +78,7 @@ const devariateExplanation = (
|
|||
return explanation
|
||||
}
|
||||
|
||||
function evaluate(
|
||||
cache,
|
||||
situation,
|
||||
parsedRules,
|
||||
node: ReturnType<typeof parse>
|
||||
) {
|
||||
const evaluate = evaluateNode.bind(null, cache, situation, parsedRules)
|
||||
|
||||
const evaluate: evaluationFunction = function(node: any) {
|
||||
const [temporalValue, explanation, unit] = node.explanation.reduce(
|
||||
(
|
||||
[evaluation, explanations, unit, previousConditions],
|
||||
|
@ -108,7 +97,7 @@ function evaluate(
|
|||
previousConditions
|
||||
]
|
||||
}
|
||||
const evaluatedCondition = evaluate(condition)
|
||||
const evaluatedCondition = this.evaluateNode(condition)
|
||||
const currentCondition = liftTemporal2(
|
||||
(previousCond, currentCond) =>
|
||||
previousCond === null ? previousCond : !previousCond && currentCond,
|
||||
|
@ -132,13 +121,13 @@ function evaluate(
|
|||
previousConditions
|
||||
]
|
||||
}
|
||||
let evaluatedConsequence = evaluate(consequence)
|
||||
let evaluatedConsequence = this.evaluateNode(consequence)
|
||||
|
||||
try {
|
||||
evaluatedConsequence = convertNodeToUnit(unit, evaluatedConsequence)
|
||||
} catch (e) {
|
||||
typeWarning(
|
||||
cache._meta.contexRule,
|
||||
this.cache._meta.contextRule,
|
||||
`L'unité de la branche n° ${i +
|
||||
1} du mécanisme 'variations' n'est pas compatible avec celle d'une branche précédente`,
|
||||
e
|
||||
|
|
|
@ -45,16 +45,14 @@ Vérifiez que tous les champs à droite des deux points sont remplis`
|
|||
syntaxError(
|
||||
rule.dottedName,
|
||||
`
|
||||
Les valeure booléenes true / false ne sont acceptée.
|
||||
Les valeurs booléennes true / false ne sont acceptées.
|
||||
Utilisez leur contrepartie française : 'oui' / 'non'`
|
||||
)
|
||||
}
|
||||
const node =
|
||||
typeof rawNode === 'object' ? rawNode : parseExpression(rule, '' + rawNode)
|
||||
|
||||
const parsedNode = parseMecanism(rules, rule, parsedRules)(node)
|
||||
parsedNode.evaluate = parsedNode.evaluate ?? ((_, __, ___, node) => node)
|
||||
return parsedNode
|
||||
return parseMecanism(rules, rule, parsedRules)(node)
|
||||
}
|
||||
|
||||
const compiledGrammar = Grammar.fromCompiled(grammar)
|
||||
|
|
|
@ -27,6 +27,7 @@ export type ParsedRule<Name extends string = string> = Rule & {
|
|||
dottedName: Name
|
||||
name: string
|
||||
title: string
|
||||
nodeKind: string
|
||||
parentDependencies: Array<any>
|
||||
rawRule: Rule
|
||||
unit?: Unit
|
||||
|
@ -37,7 +38,6 @@ export type ParsedRule<Name extends string = string> = Rule & {
|
|||
API?: string
|
||||
icons?: string
|
||||
formule?: any
|
||||
evaluate?: () => EvaluatedRule<Name>
|
||||
explanation?: any
|
||||
isDisabledBy: Array<any>
|
||||
replacedBy: Array<{
|
||||
|
@ -74,10 +74,11 @@ export type EvaluatedNode<
|
|||
T extends Types = Types
|
||||
> = {
|
||||
nodeValue: Evaluation<T>
|
||||
explanation?: Record<string, any>
|
||||
explanation: Record<string, any>
|
||||
isDefault?: boolean
|
||||
jsx: React.FunctionComponent<EvaluatedNode>
|
||||
category?: string
|
||||
dottedName: Names
|
||||
missingVariables: Partial<Record<Names, number>>
|
||||
} & (T extends number
|
||||
? {
|
||||
|
|
Loading…
Reference in New Issue