MAJ publicodes (#1645)

* Squashed 'publicodes/' changes from 10a30d32..71b68707

71b68707 📦 Publicodes v1.0.0-beta.16
bdc92216 Merge the tests and publish workflows
1c032ebc  Add test for a value with a percentage in its unit
d2865e8c Disable sum optimization inside comparisons
f4faa35d Ajout d'un test qui casse l'implé actuelle des missing parentes
f6105283 🖋 Document packages publication on NPM
a79eeb86 Better Github workflows
d0db4d09 Import publish action
c268cff5 Type checking in CI
a35403d7 Correction formattage
3022fd78 Add a separate cache for applicability
35095da9 Optimize the evaluation of applicability
7525446e Add a github action to run tests on push
39a12a13 Ajout d'un prettierrc / reformattage de quelques fichiers récents
c296a25e Ajout d'un deuxièmes test non fonctionnel sur le sujet #33
9f5afb4e Désactivation d'un nouveau test pas encore résolu
76d00085 Récupération de la complexité initiale du test missing variations
93210235 🐛 Meilleures missingVariables des variations
369abeae Simplification du test missingVariables qui ne marche pas
64217d3d Nouveau test missing variables éval paresseuse variations
d9c3e1f6 Conversion d'un gros test JS object en YAML
615ae5e5 Ajout d'un test râté pour #33
d290b46d Passage à mochapack pour webpack 5
5d7a5b31 Paquets NPM et conf babel manquants
1df9a8d4 Ajout d'un .gitignore et yarn.lock
6c2d0203 Uniformise l'unité des arrondis
2cbffe8a ⬆ MAJ Typescript vers 4.3
678403e4 Corrige le calcul des cotisations forfaitaires de début d'activité
8cdaac05 Simpler condition component (#1578)
b7459617 🔥 Supprime les variables temporelles
db62b57d 🔥 Supprime l'utilisation des temporals dans les mécanismes

git-subtree-dir: publicodes
git-subtree-split: 71b687077ec30ea3959209657c2ac7fd7a0277e1

* 🔥 Supprime l'action de déploiement de publicodes

Migrée sur betagouv/publicodes

* 🖋  MAJ documentation de contribution

*  Désactive prettier pour publicodes

Je préférerais ne pas avoir à désactiver Prettier pour le répertoire
publicodes mais pour une raison qui m'échappe (peut-être liée aux
versions des differentes dépendances prettier/babel/typescript ?) entre
betagouv/publicodes et betagouv/mon-entreprise, l'une des lignes est
formatée différemment ce qui provoque une erreur dans la CI.

On va considérer que la “bonne configuration” est celle de
betagouv/publicodes et ignorer celle de betagouv/mon-entreprise. Mais ça
serait quand même mieux d'avoir la même des deux côtés.

* 🔨 Sort une question d'un espace parfois non applicable
pull/1662/head
Maxime Quandalle 2021-07-06 15:47:44 +02:00 committed by GitHub
parent 21801ea73a
commit 3e4463d5d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 4160 additions and 208 deletions

View File

@ -1,45 +0,0 @@
name: Publication du paquet publicodes
on:
push:
paths:
- publicodes/**
- .github/workflows/publish-publicodes.yaml
jobs:
test:
if: contains(join(github.event.commits.*.message, ' | '), '📦 Publicodes v1.0.0-beta.')
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-v2
- run: yarn install --frozen-lockfile
- working-directory: ./publicodes/example/publicodes-react
run: |
yarn install
yarn test
publish:
needs: test
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-v2
- run: yarn install --frozen-lockfile
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_PUBLISH_SECRET }}
dry-run: ${{ github.ref != 'refs/heads/master' }}
package: ./publicodes/core/package.json
tag: next
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_PUBLISH_SECRET }}
dry-run: ${{ github.ref != 'refs/heads/master' }}
package: ./publicodes/ui-react/package.json
tag: next

View File

@ -1,2 +1,3 @@
.eslintrc.js
dist
publicodes

View File

@ -66,28 +66,22 @@ REDUX_TRACE=true yarn start
A mettre sans retenue dans les messages de commit :
https://github.com/atom/atom/blob/master/CONTRIBUTING.md#git-commit-messages
- 🎨 `:art:` when working on the app's visual style
- 🐎 `:racehorse:` when improving performance
- 📝 `:memo:` when writing docs
- 🐛 `:bug:` when fixing a bug
- 🔥 `:fire:` when removing code or files
- 💚 `:green_heart:` when fixing the CI build
- ✅ `:white_check_mark:` when adding tests
- ⬆️ `:arrow_up:` when upgrading dependencies
- :sparkles: `:sparkles:` when formatting, renaming, reorganizing files
Et ceux spécifiques au projet :
- :gear: `:gear:` pour une contribution au moteur qui traite les YAML
- :hammer: `:hammer:` pour une contribution à la base de règles
- :calendar: `:calendar:` pour un changement de règle du à une évolution temporelle (en attendant mieux)
- :chart_with_upwards_trend: `:chart_with_upwards_trend:` pour une amélioration du tracking
- :alien: `:alien:` pour ajouter des traductions
- :wheelchair: `:wheelchair:` pour corriger les problèmes liés à l'accessibilité
- :fountain_pen: `:fountain_pen:` pour séparer les commits liés à la modification du contenu
- :mag: `:mag:` pour les modifications liées au référencement naturel
- 🎨 `:art:` pour une modification de l'UI
- 🐎 `:racehorse:` pour une amélioration de performance
- 🐛 `:bug:` pour une correction de bug
- 🔥 `:fire:` pour une suppression de code ou de fichier
- 💚 `:green_heart:` pour une correction de CI
- ✅ `:white_check_mark:` pour un ajout de test
- ⬆️ `:arrow_up:` pour une mise à jour de dépendances
- ✨ `:sparkles:` pour une ré-organisation du code
- ⚙ `:gear:` pour une contribution sur le moteur publicodes
- 🔨 `:hammer:` pour une contribution à la base de règles
- 📆 `:calendar:` pour un changement de règle du à une évolution temporelle (en attendant mieux)
- 📈 `:chart_with_upwards_trend:` pour une amélioration du tracking
- 👽 `:alien:` pour ajouter des traductions
- ♿ `:wheelchair:` pour corriger les problèmes liés à l'accessibilité
- 🖋 `:fountain_pen:` pour séparer les commits liés à la modification du contenu
- 🔍 `:mag:` pour les modifications liées au référencement naturel
### Tests
@ -167,6 +161,44 @@ La commande `yarn run build:analyse-bundle` gènere une visualisation interactiv
contenu packagé, cf.
[webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer)
### Tests
Pour tester les règles, il est recommandé de:
- faire tourner un simulateur et vérifier à la main l'adéquation des règles avec les normes
traduites ;
- créer des cas de tests de non-régression sous la forme de nouveaux snapshots (cf.
`mon-entreprise/test/regressions`).
## Publicodes
### Documentation
Un tutoriel sur publicodes est disponible sur https://publi.codes.
Un wiki contenant des informations intéressantes sur publicodes et le
raisonnement ayant abouti à ce langage sont dispos sur le repository
[betagouv/publicodes](https://github.com/betagouv/publicodes/wiki), qui est par
ailleurs inutilisé.
Pour se familiariser avec les règles, vous pouvez jeter un œil aux fichiers
contenant les règles elles-mêmes (dans le dossier `modele-social`) mais cela
peut s'avérer assez abrupt.
Essayez plutôt de jeter un oeil [aux tests](./publicodes/test/mécanismes/expressions.yaml)
dans un premier temps, puis au [mécanismes en
place](./publicodes/source/mecanisms).
### Traduction des normes (lois) en règles Publicodes
Checklist:
- [ ] Lire les articles de vulgarisation (sur le site de l'URSSAF, des impôts, etc.).
- [ ] Utiliser un moteur de recherche spécialisé, comme [RFPaye](https://rfpaye.grouperf.com/).
- [ ] [Lire les normes][wiki normes] et noter leurs référence dans les règles Publicodes.
[wiki normes]: https://github.com/betagouv/mon-entreprise/wiki/Comment-lire-les-normes-(la-loi)-efficacement-pour-r%C3%A9diger-des-r%C3%A8gles-Publicodes%3F
### Modifier publicodes
Publicodes dispose désormais de son propre dépôt GitHub https://github.com/betagouv/publicodes
@ -198,57 +230,4 @@ Dans l'autre sens il est possible de rapatrier les changements avec la commande
$ git subtree pull --prefix=publicodes publicodes master --squash
```
## Développement de modèles Publicodes
### Traduction des normes (lois) en règles Publicodes
Checklist:
- [ ] Lire les articles de vulgarisation (sur le site de l'URSSAF, des impôts, etc.).
- [ ] Utiliser un moteur de recherche spécialisé, comme [RFPaye](https://rfpaye.grouperf.com/).
- [ ] [Lire les normes][wiki normes] et noter leurs référence dans les règles Publicodes.
[wiki normes]: https://github.com/betagouv/mon-entreprise/wiki/Comment-lire-les-normes-(la-loi)-efficacement-pour-r%C3%A9diger-des-r%C3%A8gles-Publicodes%3F
### Tests
Pour tester les règles, il est recommandé de:
- faire tourner un simulateur et vérifier à la main l'adéquation des règles avec les normes
traduites ;
- créer des cas de tests de non-régression sous la forme de nouveaux snapshots (cf.
`mon-entreprise/test/regressions`).
## Documentation
### Publicodes
Un tutoriel sur publicodes est disponible sur https://publi.codes.
Un wiki contenant des informations intéressantes sur publicodes et le
raisonnement ayant abouti à ce langage sont dispos sur le repository
[betagouv/publicodes](https://github.com/betagouv/publicodes/wiki), qui est par
ailleurs inutilisé.
Pour se familiariser avec les règles, vous pouvez jeter un œil aux fichiers
contenant les règles elles-mêmes (dans le dossier `rules`) mais cela peut
s'avérer assez abrupt.
Essayez plutôt de jeter un oeil [aux tests](./publicodes/test/mécanismes/expressions.yaml)
dans un premier temps, puis au [mécanismes en
place](./publicodes/source/mecanisms).
## Publier une nouvelle version des paquets publicodes
<!-- TODO: action à déplacer dans le dépot betagouv/publicodes -->
Voici la marche à suivre pour publier une nouvelle version :
1. Renseigner les modifications dans publicodes/CHANGELOG.md
2. Remplacer les références à la précédente version par la nouvelle version dans les packages.json
3. Ajouter tous les changement dans un commit avec le message suivant :
```
📦 Publicodes v1.0.0-beta.<n>
```
> **Important** Le message doit être exactement celui-ci (emoji compris), car le script de déploiement automatique sur le CI se base sur ce dernier.
4. Laisser faire le CI, une fois le commit mergé sur master, le paquet sera déployé effectivement
Les dépendances peuvent avoir changé côté publicodes, mieux vaut donc enchaîner avec un `yarn install` pour être à jour.

View File

@ -2106,6 +2106,10 @@ contrat salarié . aides employeur . aide exceptionnelle à l'embauche d'apprent
références:
Plan \#1jeune1solution: https://travail-emploi.gouv.fr/formation-professionnelle/entreprise-et-alternance/aide-exceptionnelle-apprentissage
contrat salarié . jeune de moins de 26 ans:
question: Le salarié a-t-il moins de 26 ans ?
par défaut: non
contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes:
non applicable si: aides employeur . emploi franc
description: >-
@ -2126,9 +2130,7 @@ contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeune
- toutes ces conditions:
- CDD
- CDD . durée contrat >= 3 mois
- nom: jeune de moins de 26 ans
question: Le salarié a-t-il moins de 26 ans ?
par défaut: non
- jeune de moins de 26 ans
rend non applicable:
# Dispositifs moins généreux et non cumulables
- aide à l'embauche des travailleurs handicapés
@ -2173,7 +2175,7 @@ contrat salarié . aides employeur . emploi franc:
toutes ces conditions:
- ancienneté . date d'embauche >= 15/10/2020
- ancienneté . date d'embauche <= 31/05/2021
- contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes . jeune de moins de 26 ans
- jeune de moins de 26 ans
alors:
nom: emploi franc plus
variations:

View File

@ -3703,6 +3703,11 @@ contrat salarié . intermittents du spectacle . technicien:
contrat salarié . intermittents du spectacle . technicien . non cadre:
titre.en: not "cadre"
titre.fr: non cadre
contrat salarié . jeune de moins de 26 ans:
question.en: '[automatic] Is the employee under 26 years of age?'
question.fr: Le salarié a-t-il moins de 26 ans ?
titre.en: '[automatic] young person under 26 years old'
titre.fr: jeune de moins de 26 ans
contrat salarié . lodeom:
description.en: >
A rather complex set of contribution reductions is available for overseas

View File

@ -113,7 +113,7 @@ aides:
- contrat salarié . rémunération . brut de base: 2000 €/mois
contrat salarié . aides employeur . emploi franc . éligible: oui
contrat salarié . ancienneté . date d'embauche: 01/11/2020
contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes . jeune de moins de 26 ans: oui
contrat salarié . jeune de moins de 26 ans: oui
# travailleur handicapé
- contrat salarié . rémunération . brut de base: 2000 €/mois
contrat salarié . ancienneté . date d'embauche: 01/03/2021
@ -122,15 +122,15 @@ aides:
aides embauche covid:
- contrat salarié . ancienneté . date d'embauche: 01/08/2020
contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes . jeune de moins de 26 ans: oui
contrat salarié . jeune de moins de 26 ans: oui
contrat salarié . rémunération . brut de base: 1500 €/mois
- contrat salarié . ancienneté . date d'embauche: 01/08/2020
contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes . jeune de moins de 26 ans: oui
contrat salarié . jeune de moins de 26 ans: oui
contrat salarié . rémunération . brut de base: 5000 €/mois
- contrat salarié . ancienneté . date d'embauche: 01/08/2020
contrat salarié: "'CDD'"
contrat salarié . CDD . durée contrat: 3 mois
contrat salarié . aides employeur . aide exceptionnelle à l'embauche des jeunes . jeune de moins de 26 ans: oui
contrat salarié . jeune de moins de 26 ans: oui
contrat salarié . rémunération . brut de base: 1500 €/mois
- contrat salarié . ancienneté . date d'embauche: 01/08/2020
contrat salarié: "'apprentissage'"

View File

@ -0,0 +1,65 @@
name: Test and Publish
on: [push]
jobs:
test:
name: Unit tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 14
- run: yarn install
- run: yarn test
test-type:
name: Type checking
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 14
- run: yarn install
- run: yarn test:type
test-example-app:
name: Test example app
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- run: yarn install --frozen-lockfile
- working-directory: ./example/publicodes-react
run: |
yarn install
yarn test
# This job could be in a separate workflow triggered when all the tests passes
# using the `workflow_run` event, but it makes it difficult to retrieve the
# commit message.
publish:
if: contains(join(github.event.commits.*.message, ' | '), '📦 Publicodes v1.0.0-beta.')
needs: [test, test-type, test-example-app]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-v2
- run: yarn install --frozen-lockfile
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_PUBLISH_SECRET }}
dry-run: ${{ github.ref != 'refs/heads/master' }}
package: ./core/package.json
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_PUBLISH_SECRET }}
dry-run: ${{ github.ref != 'refs/heads/master' }}
package: ./ui-react/package.json

12
publicodes/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
.tags*
.tmp
/tmp
.DS_Store
yarn-error.log
package-lock.json
node_modules/
.env
dist/
# Local Netlify folder
.netlify

View File

@ -0,0 +1,4 @@
bracketSpacing: true
semi: false
singleQuote: true
useTabs: true

View File

@ -26,8 +26,11 @@
- Fix bug sur le mécanisme minimum, une valeur non applicable n'est plus considérée comme valant "0" (#1493)
## 1.0.0-beta.16 (release candidate)
## 1.0.0-beta.16
**core**
- Répare un bug dans le mécanisme résoudre le cycle
- Suppression des variables temporelles
- Optimisation de la désactivation de branches
- Meilleures performances

View File

@ -7,3 +7,16 @@ Voici quelques informations pour démarrer :
## Rapport de bug, nouvelles fonctionnalités
Nous utilisons GitHub pour suivre tous les bugs et discussions sur les nouvelles fonctionnalités. Pour rapporter un bug ou proposer une évolution vous pouvez [ouvrir une nouvelle discussion](https://github.com/betagouv/publicodes/discussions). N'hésitez pas à utiliser la recherche pour vérifier si le sujet n'est pas déjà traité dans une discussion ouverte.
## Publier une nouvelle version sur NPM
Voici la marche à suivre pour publier une nouvelle version :
1. Renseigner les modifications dans `CHANGELOG.md`
2. Remplacer les références à la précédente version par la nouvelle version dans les packages.json
3. Ajouter tous les changements dans un commit avec le message suivant :
```
📦 Publicodes v1.0.0-beta.<n>
```
> **Important** Le message doit être exactement celui-ci (emoji compris), car le script de déploiement automatique sur le CI se base sur ce dernier.
4. Laisser faire le CI, une fois le commit mergé sur master, le paquet sera déployé effectivement

View File

@ -0,0 +1,20 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-syntax-dynamic-import"
]
}

View File

@ -1,6 +1,6 @@
{
"name": "publicodes",
"version": "1.0.0-beta.15",
"version": "1.0.0-beta.16",
"description": "A declarative language for encoding public algorithm",
"main": "dist/index.js",
"types": "dist/types/index.d.ts",
@ -25,14 +25,27 @@
],
"private": false,
"devDependencies": {
"@babel/preset-typescript": "^7.14.5",
"babel-loader": "^8.2.2",
"chai": "^4.2.0",
"dedent-js": "1.0.1",
"intl": "^1.2.5",
"json-loader": "^0.5.7",
"mocha": "^9.0.1",
"mochapack": "^2.1.2",
"nearley-loader": "^2.0.0",
"rimraf": "^3.0.2",
"typescript": "^4.3.2",
"dedent-js": "1.0.1"
"webpack-cli": "^4.7.2",
"yaml-loader": "^0.6.0"
},
"dependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.5",
"@types/webpack-env": "^1.16.0",
"moo": "^0.5.1",
"nearley": "^2.19.2",
"webpack": "^5.39.1",
"yaml": "^1.9.2"
},
"scripts": {
@ -41,7 +54,7 @@
"prepare": "yarn run rimraf dist && yarn run build",
"build": "yarn run webpack --config webpack.config.js && yarn run tsc",
"build:watch": "concurrently \"yarn run webpack --watch --config webpack.config.js\" \"yarn run tsc -w\"",
"test:file": "yarn mocha-webpack --include test/setupIntl.js --webpack-config ./webpack.test.js ",
"test:file": "yarn mochapack --include test/setupIntl.js --webpack-config ./webpack.test.js ",
"test": "yarn test:file \"./{,!(node_modules)/**/}!(webpack).test.js\""
},
"engines": {

View File

@ -16,14 +16,17 @@ const emptyCache = (): Cache => ({
_meta: {
parentRuleStack: [],
evaluationRuleStack: [],
disableApplicabilityContextCounter: 0,
},
nodes: new Map(),
nodesApplicability: new Map(),
})
type Cache = {
_meta: {
parentRuleStack: Array<string>
evaluationRuleStack: Array<string>
disableApplicabilityContextCounter: number
inversionFail?:
| {
given: string
@ -34,6 +37,7 @@ type Cache = {
filter?: string
}
nodes: Map<PublicodesExpression | ASTNode, EvaluatedNode>
nodesApplicability: Map<PublicodesExpression | ASTNode, EvaluatedNode>
}
export type EvaluationOptions = Partial<{
@ -157,8 +161,17 @@ export default class Engine<Name extends string = string> {
evaluate(value: PublicodesExpression): EvaluatedNode
evaluate(value: PublicodesExpression | ASTNode): EvaluatedNode {
const cachedNode = this.cache.nodes.get(value)
// The evaluation of parent applicabilty is slightly different from
// regular rules since we cut some of the paths (sums) for optimization.
// That's why we need to have a separate cache for this evaluation.
if (cachedNode !== undefined) {
return cachedNode
} else if (this.inApplicabilityEvaluationContext) {
const cachedNodeApplicability = this.cache.nodesApplicability.get(value)
if (cachedNodeApplicability) {
return cachedNodeApplicability
}
}
let parsedNode: ASTNode
@ -180,7 +193,16 @@ export default class Engine<Name extends string = string> {
this,
parsedNode
)
this.cache.nodes.set(value, evaluatedNode)
// TODO: In most cases the two evaluation provide the same result, this
// could be optimized. The idea would be to use the “nodesApplicability”
// cache iff the rule uses a sum mechanism (ie, some paths are cut from
// the full evaluaiton).
if (!this.inApplicabilityEvaluationContext) {
this.cache.nodes.set(value, evaluatedNode)
} else {
this.cache.nodesApplicability.set(value, evaluatedNode)
}
return evaluatedNode
}
@ -196,6 +218,13 @@ export default class Engine<Name extends string = string> {
newEngine.cache = this.cache
return newEngine
}
get inApplicabilityEvaluationContext(): boolean {
return (
this.cache._meta.parentRuleStack.length > 0 &&
this.cache._meta.disableApplicabilityContextCounter === 0
)
}
}
/**

View File

@ -41,10 +41,24 @@ const parseOperation = (k, symbol) => (v, context) => {
}
const evaluate: EvaluationFunction<'operation'> = function (node) {
// When we only need to evaluate the applicability of a rule, we don't enter
// inside “sum terms” since we know that the sum will always be applicable.
// However, if somewhere in the evaluation stack we do a comparison, we need
// to disable this optimization since in this case we'll need the exact value
// of sums in the evaluation subtree.
const disableApplicabilityContext = ['≠', '=', '<', '>', '≤', '≥'].includes(
node.operator
)
if (disableApplicabilityContext && this.inApplicabilityEvaluationContext) {
this.cache._meta.disableApplicabilityContextCounter += 1
}
const explanation = node.explanation.map((node) => this.evaluate(node)) as [
EvaluatedNode,
EvaluatedNode
]
if (disableApplicabilityContext && this.inApplicabilityEvaluationContext) {
this.cache._meta.disableApplicabilityContextCounter -= 1
}
let [node1, node2] = explanation
const missingVariables = mergeAllMissing([node1, node2])

View File

@ -18,4 +18,17 @@ export const mecanismSum = (v, context) => {
} as SommeNode
}
registerEvaluationFunction('somme', evaluate)
registerEvaluationFunction('somme', function (node) {
if (this.inApplicabilityEvaluationContext) {
return {
// With a clearer distinction between `getApplicability` and
// `getValue` we could avoid faking a `nodeValue: true` and instead
// simply return `isApplicable: true, nodeValue: undefined`
nodeValue: true,
nodeKind: 'somme',
missingVariables: {},
explanation: [],
}
}
return evaluate.call(this, node)
})

View File

@ -131,10 +131,10 @@ const evaluate: EvaluationFunction<'variations'> = function (node) {
const missingVariables = mergeAllMissing(
explanation.reduce<ASTNode[]>(
(values, { condition, consequence }) => [
(values, { condition, satisfied, consequence }) => [
...values,
condition,
consequence,
...(satisfied ? [consequence] : []),
],
[]
)

View File

@ -21,6 +21,12 @@ describe('format engine values', () => {
expect(formatValue(10, { displayedUnit: '%' })).to.equal('10 %')
expect(formatValue(100, { displayedUnit: '%' })).to.equal('100 %')
expect(formatValue(10.2, { displayedUnit: '%' })).to.equal('10,2 %')
expect(
formatValue({
nodeValue: 441,
unit: parseUnit('%.kgCO2e'),
})
).to.equal('4,41 kgCO2e')
})
it('format values', () => {

View File

@ -1,22 +1,25 @@
import { expect } from 'chai'
import Engine from '../source/index'
import { parse } from 'yaml'
describe('Missing variables', function () {
it('should identify missing variables', function () {
const rawRules = {
ko: 'oui',
sum: 'oui',
'sum . startHere': {
formule: 2,
'non applicable si': 'sum . evt . ko',
},
'sum . evt': {
formule: { 'une possibilité': ['ko'] },
titre: 'Truc',
question: '?',
},
'sum . evt . ko': {},
}
// Rules in tests can be expressed in YAML like to for more clarity than JS objects
const rawRules = parse(`
ko: oui
sum: oui
sum . startHere:
formule: 2
non applicable si: sum . evt . ko
sum . evt:
formule:
une possibilité:
- ko
titre: Truc
question: '?'
sum . evt . ko:
`)
const result = Object.keys(
new Engine(rawRules).evaluate('sum . startHere').missingVariables
)
@ -129,60 +132,74 @@ describe('Missing variables', function () {
expect(result).to.be.empty
})
// TODO : réparer ce test
it.skip('should report missing variables in variations', function () {
const rawRules = {
top: 'oui',
'top . startHere': {
formule: { somme: ['variations'] },
},
'top . variations': {
formule: {
variations: [
{
si: 'dix',
alors: {
barème: {
assiette: 2008,
multiplicateur: 'deux',
tranches: [
{ plafond: 1, taux: 0.1 },
{ plafond: 2, taux: 'trois' },
{ taux: 10 },
],
},
},
},
{
si: '3 > 4',
alors: {
barème: {
assiette: 2008,
multiplicateur: 'quatre',
tranches: [
{ plafond: 1, taux: 0.1 },
{ plafond: 2, taux: 1.8 },
{ 'au-dessus de': 2, taux: 10 },
],
},
},
},
],
},
},
'top . dix': {},
'top . deux': {},
'top . trois': {},
'top . quatre': {},
}
it('should report missing variables in simple variations', function () {
const rawRules = parse(`
somme: a + b
a: 10
b:
formule:
variations:
- si: a > 100
alors: c
- sinon: 0
c:
question: Alors ?`)
const result = Object.keys(
new Engine(rawRules).evaluate('top . startHere').missingVariables
new Engine(rawRules).evaluate('somme').missingVariables
)
expect(result).to.include('top . dix')
expect(result).to.include('top . deux')
expect(result).to.include('top . trois')
expect(result).not.to.include('top . quatre')
expect(result).to.have.lengthOf(0)
})
// TODO : réparer ce test
it('should report missing variables in variations', function () {
const rawRules = parse(`
startHere:
formule:
somme:
- variations
variations:
formule:
variations:
- si: dix
alors:
barème:
assiette: 2008
multiplicateur: deux
tranches:
- plafond: 1
taux: 0.1
- plafond: 2
taux: trois
- taux: 10
- si: 3 > 4
alors:
barème:
assiette: 2008
multiplicateur: quatre
tranches:
- plafond: 1
taux: 0.1
- plafond: 2
taux: 1.8
- au-dessus de: 2
taux: 10
dix: {}
deux: {}
trois: {}
quatre: {}
`)
const result = Object.keys(
new Engine(rawRules).evaluate('startHere').missingVariables
)
expect(result).to.include('dix')
expect(result).to.include('deux')
expect(result).to.include('trois')
expect(result).not.to.include('quatre')
})
})
@ -249,4 +266,98 @@ describe('nextSteps', function () {
expect(result).to.eql(['top . sum . evt'])
})
it("Parent's other descendands in sums should not be included as missing variables", function () {
// See https://github.com/betagouv/publicodes/issues/33
const rawRules = parse(`
transport:
somme:
- voiture
- avion
transport . voiture:
formule: empreinte * km
transport . voiture . empreinte: 0.12
transport . voiture . km:
question: COMBIENKM
par défaut: 1000
transport . avion:
applicable si: usager
formule: empreinte * km
transport . avion . km:
question: COMBIENKM
par défaut: 10000
transport . avion . empreinte: 0.300
transport . avion . usager:
question: Prenez-vous l'avion ?
par défaut: oui
`)
const result = Object.keys(
new Engine(rawRules).evaluate('transport . avion').missingVariables
)
expect(result).deep.to.equal([
'transport . avion . km',
'transport . avion . usager',
])
expect(result).to.have.lengthOf(2)
})
it("Parent's other descendands in sums should not be included as missing variables - 2", function () {
// See https://github.com/betagouv/publicodes/issues/33
const rawRules = parse(`
avion:
question: prenez-vous l'avion ?
par défaut: oui
avion . impact:
formule:
somme:
- au sol
- en vol
avion . impact . en vol:
question: Combien de temps passé en vol ?
par défaut: 10
avion . impact . au sol: 5
`)
const result = Object.keys(
new Engine(rawRules).evaluate('avion . impact . au sol').missingVariables
)
expect(result).deep.to.equal(['avion'])
expect(result).to.have.lengthOf(1)
})
it("Parent's other descendands in sums in applicability should be included as missing variables", function () {
// See https://github.com/betagouv/publicodes/issues/33
const rawRules = parse(`
a:
applicable si: d > 3
valeur: oui
d:
formule:
somme:
- e
- 8
e:
question: Vous venez à combien à la soirée ?
par défaut: 3
a . b: 20 + 9
`)
const result = Object.keys(
new Engine(rawRules).evaluate('a . b').missingVariables
)
expect(result).deep.to.equal(['e'])
expect(result).to.have.lengthOf(1)
})
})

View File

@ -6,8 +6,8 @@
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"publicodes": "../../core/publicodes-1.0.0-beta.15.tgz",
"publicodes-react": "../../ui-react/publicodes-react-1.0.0-beta.15.tgz",
"publicodes": "../../core/publicodes-1.0.0-beta.16.tgz",
"publicodes-react": "../../ui-react/publicodes-react-1.0.0-beta.16.tgz",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router": "^5.2.0",

12
publicodes/package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "publicodes-monorepo",
"private": true,
"workspaces": [
"core",
"ui-react"
],
"scripts": {
"test": "yarn workspaces run test",
"test:type": "yarn workspaces run tsc"
}
}

View File

@ -11,7 +11,8 @@
"clean": "rimraf node_modules"
},
"devDependencies": {
"core-js": "^3.8.1"
"core-js": "^3.8.1",
"typescript": "^4.3.2"
},
"dependencies": {
"color-convert": "^2.0.1",

View File

@ -1,6 +1,6 @@
{
"name": "publicodes-react",
"version": "1.0.0-beta.15",
"version": "1.0.0-beta.16",
"description": "UI to explore publicodes computations",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@ -22,17 +22,22 @@
"react-easy-emoji": "^1.4.0",
"react-helmet": "^6.1.0",
"react-markdown": "^4.3.1",
"react-router-hash-link": "^2.4.3",
"styled-components": "^5.1.0",
"yaml": "^1.9.2"
},
"peerDependencies": {
"publicodes": "1.0.0-beta.15",
"publicodes": "1.0.0-beta.16",
"react": "^17.0.2",
"react-router-dom": "^5.1.1",
"react-router-hash-link": "^1.2.2"
},
"devDependencies": {
"js-yaml": "^4.0.0",
"@types/react": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@types/react-router-hash-link": "^2.4.0",
"@types/styled-components": "^5.1.10",
"js-yaml": "^4.1.0",
"typescript": "^4.3.2"
}
}

3689
publicodes/yarn.lock Normal file

File diff suppressed because it is too large Load Diff