diff --git a/publicodes/source/parseReference.ts b/publicodes/source/parseReference.ts index b1a1117b3..77700aefa 100644 --- a/publicodes/source/parseReference.ts +++ b/publicodes/source/parseReference.ts @@ -9,6 +9,32 @@ import { disambiguateRuleReference } from './ruleUtils' import { EvaluatedNode, ParsedRule } from './types' import { areUnitConvertible, serializeUnit } from './units' +/** + * Statically filter out replacements from `replaceBy`. + * Note: whitelist and blacklist filtering are applicable to the replacement + * itself or any parent namespace. + */ +export const getApplicableReplacedBy = (contextRuleName, replacedBy) => + replacedBy + .sort( + (replacement1, replacement2) => + +!!replacement2.whiteListedNames - +!!replacement1.whiteListedNames + ) + .filter( + ({ whiteListedNames }) => + !whiteListedNames || + whiteListedNames.some(name => contextRuleName.startsWith(name)) + ) + .filter( + ({ blackListedNames }) => + !blackListedNames || + blackListedNames.every(name => !contextRuleName.startsWith(name)) + ) + .filter(({ referenceNode }) => contextRuleName !== referenceNode.dottedName) + +/** + * Filter-out and apply all possible replacements at runtime. + */ const getApplicableReplacements = ( filter, contextRuleName, @@ -21,23 +47,10 @@ const getApplicableReplacements = ( if (contextRuleName.startsWith('[evaluation]')) { return [[], []] } - const applicableReplacements = rule.replacedBy - .sort( - (replacement1, replacement2) => - +!!replacement2.whiteListedNames - +!!replacement1.whiteListedNames - ) - // Remove remplacement not in whitelist - .filter( - ({ whiteListedNames }) => - !whiteListedNames || - whiteListedNames.some(name => contextRuleName.startsWith(name)) - ) - .filter( - ({ blackListedNames }) => - !blackListedNames || - blackListedNames.every(name => !contextRuleName.startsWith(name)) - ) - .filter(({ referenceNode }) => contextRuleName !== referenceNode.dottedName) + const applicableReplacements = getApplicableReplacedBy( + contextRuleName, + rule.replacedBy + ) // Remove remplacement defined in a not applicable node .filter(({ referenceNode }) => { const referenceRule = rules[referenceNode.dottedName] diff --git a/publicodes/source/types/index.ts b/publicodes/source/types/index.ts index 48b8cfb47..645b8e968 100644 --- a/publicodes/source/types/index.ts +++ b/publicodes/source/types/index.ts @@ -39,7 +39,7 @@ export type ParsedRule = Rule & { formule?: any evaluate?: () => EvaluatedRule explanation?: any - isDisabledBy?: Array + isDisabledBy: Array replacedBy: Array<{ whiteListedNames: Array blackListedNames: Array diff --git a/publicodes/test/mécanismes/remplace.yaml b/publicodes/test/mécanismes/remplace.yaml index 16a405534..b50c3d0eb 100644 --- a/publicodes/test/mécanismes/remplace.yaml +++ b/publicodes/test/mécanismes/remplace.yaml @@ -181,3 +181,53 @@ remplacement non applicable car branche desactivée: formule: z exemples: - valeur attendue: 1 + +# Remplacement non effectué dans la formule du remplacement +espace . valeur: + formule: 20 +espace . remplacement: + remplace: valeur + formule: valeur + 10 +test remplacement non effectué dans la formule du remplacement: + formule: espace . valeur + exemples: + - valeur attendue: 30 + + +frais de repas: + formule: 5 €/repas + +convention hôtels cafés restaurants: + formule: oui + +convention hôtels cafés restaurants . frais de repas: + remplace: frais de repas + formule: 6 €/repas + +frais de repas non remplacé: + formule: frais de repas + exemples: + - valeur attendue: 5 + +# Note: this would produce an infinite loop +# frais de repas remplacé: +# formule: convention hôtels cafés restaurants . frais de repas +# exemples: +# - nom: par défaut +# valeur attendue: 5 + + +frais de repas2: + formule: 5 €/repas + +convention hôtels cafés restaurants2: + formule: oui + +convention hôtels cafés restaurants2 . remplaçeur: + remplace: frais de repas2 + formule: 6 €/repas + +frais de repas2 remplacé: + formule: frais de repas2 + exemples: + - valeur attendue: 6