1
0
Fork 0
mirror of https://github.com/betagouv/mon-entreprise synced 2025-02-10 15:05:01 +00:00
mon-entreprise/source/engine/parse.js
Maxime Quandalle 3c77fa8261 🔨 Implémente la Déduction Forfaitaire Spécifique
- DFS pour journalistes, ouvriers du bâtiment, artistes, pilotes
- Plafonnement réduction générale dans le cas d'un cumul avec DFS
  (nouveauté 2020)
- Taux réduit de cotisations pour les journalistes
- Abattement fiscal journalistes

🐛 Corrige la désactivation des plafond si la règle référencée dans le
"plafond" est non applicable.
2020-03-04 15:22:29 +01:00

198 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This should be the new way to implement mecanisms
// In a specific file
// TODO import them automatically
// TODO convert the legacy functions to new files
import Value from 'Components/Value'
import mecanismRound from 'Engine/mecanisms/arrondi'
import barème from 'Engine/mecanisms/barème'
import durée from 'Engine/mecanisms/durée'
import encadrement from 'Engine/mecanisms/encadrement'
import grille from 'Engine/mecanisms/grille'
import operation from 'Engine/mecanisms/operation'
import tauxProgressif from 'Engine/mecanisms/tauxProgressif'
import variations from 'Engine/mecanisms/variations'
import { Grammar, Parser } from 'nearley'
import {
add,
divide,
equals,
fromPairs,
gt,
gte,
lt,
lte,
multiply,
subtract
} from 'ramda'
import React from 'react'
import { syntaxError } from './error.ts'
import grammar from './grammar.ne'
import {
mecanismAllOf,
mecanismInversion,
mecanismMax,
mecanismMin,
mecanismOneOf,
mecanismOnePossibility,
mecanismProduct,
mecanismRecalcul,
mecanismReduction,
mecanismSum,
mecanismSynchronisation
} from './mecanisms'
import { parseReferenceTransforms } from './parseReference'
export const parse = (rules, rule, parsedRules) => rawNode => {
if (rawNode == null) {
syntaxError(
rule.dottedName,
`
Une des valeurs de la formule est vide.
Vérifiez que tous les champs à droite des deux points sont remplis`
)
}
if (typeof rawNode === 'boolean') {
syntaxError(
rule.dottedName,
`
Les valeure booléenes true / false ne sont acceptée.
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
}
const compiledGrammar = Grammar.fromCompiled(grammar)
const parseExpression = (rule, rawNode) => {
/* Strings correspond to infix expressions.
* Indeed, a subset of expressions like simple arithmetic operations `3 + (quantity * 2)` or like `salary [month]` are more explicit that their prefixed counterparts.
* This function makes them prefixed operations. */
try {
let [parseResult] = new Parser(compiledGrammar).feed(rawNode).results
return parseResult
} catch (e) {
syntaxError(
rule.dottedName,
`\`${rawNode}\` n'est pas une expression valide`,
e
)
}
}
const parseMecanism = (rules, rule, parsedRules) => rawNode => {
if (Object.keys(rawNode).length > 1) {
syntaxError(
rule.dottedName,
`
Les mécanismes suivants se situent au même niveau : ${Object.keys(rawNode)
.map(x => `'${x}'`)
.join(', ')}
Cela vient probablement d'une erreur dans l'indentation
`
)
}
const mecanismName = Object.keys(rawNode)[0]
const values = rawNode[mecanismName]
const parseFunctions = {
...statelessParseFunction,
'une possibilité': mecanismOnePossibility(rule.dottedName),
'inversion numérique': mecanismInversion(rule.dottedName),
recalcul: mecanismRecalcul(rule.dottedName),
filter: () =>
parseReferenceTransforms(
rules,
rule,
parsedRules
)({
filter: values.filter,
variable: values.explanation
}),
variable: () =>
parseReferenceTransforms(rules, rule, parsedRules)({ variable: values }),
unitConversion: () =>
parseReferenceTransforms(
rules,
rule,
parsedRules
)({
variable: values.explanation,
unit: values.unit
})
}
const parseFn = parseFunctions[mecanismName]
if (!parseFn) {
syntaxError(
rule.dottedName,
`
Le mécanisme ${mecanismName} est inconnu.
Vérifiez qu'il n'y ait pas d'erreur dans l'orthographe du nom.`
)
}
return parseFn(parse(rules, rule, parsedRules), mecanismName, values)
}
const knownOperations = {
'*': [multiply, '×'],
'/': [divide, ''],
'+': [add],
'-': [subtract, ''],
'<': [lt],
'<=': [lte, '≤'],
'>': [gt],
'>=': [gte, '≥'],
'=': [equals],
'!=': [(a, b) => !equals(a, b), '≠']
}
const operationDispatch = fromPairs(
Object.entries(knownOperations).map(([k, [f, symbol]]) => [
k,
operation(k, f, symbol)
])
)
const statelessParseFunction = {
...operationDispatch,
'une de ces conditions': mecanismOneOf,
'toutes ces conditions': mecanismAllOf,
somme: mecanismSum,
multiplication: mecanismProduct,
arrondi: mecanismRound,
barème,
grille,
'taux progressif': tauxProgressif,
encadrement,
durée,
'le maximum de': mecanismMax,
'le minimum de': mecanismMin,
allègement: mecanismReduction,
variations,
synchronisation: mecanismSynchronisation,
constant: (_, __, v) => ({
type: v.type,
nodeValue: v.nodeValue,
unit: v.unit,
// eslint-disable-next-line
jsx: (nodeValue, _, __, unit) => (
<span className={v.type}>
<Value
{...{
unit,
nodeValue,
// We want to display constants with full precision,
// espacilly for percentages like APEC 0,036 %
maximumFractionDigits: 5
}}
/>
</span>
)
})
}