diff --git a/site/source/components/ChiffreAffairesActivitéMixte.tsx b/site/source/components/ChiffreAffairesActivitéMixte.tsx index f66ada017..120028407 100644 --- a/site/source/components/ChiffreAffairesActivitéMixte.tsx +++ b/site/source/components/ChiffreAffairesActivitéMixte.tsx @@ -8,7 +8,7 @@ import { styled } from 'styled-components' import { Switch } from '@/design-system/switch' import { batchUpdateSituation } from '@/store/actions/actions' import { situationSelector } from '@/store/selectors/simulationSelectors' -import { catchDivideByZeroError } from '@/utils' +import { catchDivideByZeroError } from '@/utils/publicodes' import { ExplicableRule } from './conversation/Explicable' import { Condition } from './EngineValue/Condition' diff --git a/site/source/components/FicheDePaie/CotisationLine.tsx b/site/source/components/FicheDePaie/CotisationLine.tsx index 722eea6e9..3cbf9d61b 100644 --- a/site/source/components/FicheDePaie/CotisationLine.tsx +++ b/site/source/components/FicheDePaie/CotisationLine.tsx @@ -1,10 +1,11 @@ import { DottedName } from 'modele-social' -import { ASTNode, formatValue, reduceAST } from 'publicodes' +import { formatValue } from 'publicodes' import { useContext } from 'react' import { useTranslation } from 'react-i18next' import RuleLink from '@/components/RuleLink' import { EngineContext } from '@/components/utils/EngineContext' +import { findReferenceInNode } from '@/utils/publicodes' export default function CotisationLine({ dottedName, @@ -53,24 +54,3 @@ export default function CotisationLine({ function isExoneration(dottedName: DottedName): boolean { return dottedName === 'salarié . cotisations . exonérations' } - -function findReferenceInNode( - dottedName: DottedName, - node: ASTNode -): string | undefined { - return reduceAST( - (acc, node) => { - if ( - node.nodeKind === 'reference' && - node.dottedName?.startsWith(dottedName) && - !node.dottedName.endsWith('$SITUATION') - ) { - return node.dottedName - } else if (node.nodeKind === 'reference') { - return acc - } - }, - undefined, - node - ) -} diff --git a/site/source/components/conversation/AnswerList.tsx b/site/source/components/conversation/AnswerList.tsx index f82ee3291..79df67034 100644 --- a/site/source/components/conversation/AnswerList.tsx +++ b/site/source/components/conversation/AnswerList.tsx @@ -25,7 +25,7 @@ import { companySituationSelector, situationSelector, } from '@/store/selectors/simulationSelectors' -import { evaluateQuestion } from '@/utils' +import { evaluateQuestion } from '@/utils/publicodes' import Value from '../EngineValue/Value' import { JeDonneMonAvis } from '../JeDonneMonAvis' diff --git a/site/source/components/conversation/QuestionEnCours.tsx b/site/source/components/conversation/QuestionEnCours.tsx index c0b2494e2..908ff22c9 100644 --- a/site/source/components/conversation/QuestionEnCours.tsx +++ b/site/source/components/conversation/QuestionEnCours.tsx @@ -23,7 +23,7 @@ import { } from '@/store/actions/actions' import { estSurLaPremièreQuestionRépondueSelector } from '@/store/selectors/estSurLaPremièreQuestionRépondue.selector' import { situationSelector } from '@/store/selectors/simulationSelectors' -import { evaluateQuestion } from '@/utils' +import { evaluateQuestion } from '@/utils/publicodes' interface Props { previousAnswers: DottedName[] diff --git a/site/source/components/conversation/RuleInput.tsx b/site/source/components/conversation/RuleInput.tsx index cf860566b..666d9f813 100644 --- a/site/source/components/conversation/RuleInput.tsx +++ b/site/source/components/conversation/RuleInput.tsx @@ -14,7 +14,7 @@ import SelectCommune from '@/components/conversation/select/SelectCommune' import { EngineContext } from '@/components/utils/EngineContext' import { DateFieldProps } from '@/design-system/field/DateField' import { Spacing } from '@/design-system/layout' -import { getMeta } from '@/utils' +import { getMeta } from '@/utils/publicodes' import { Choice, MultipleAnswerInput, OuiNonInput } from './ChoicesInput' import DateInput from './DateInput' diff --git a/site/source/pages/assistants/components/Fields.tsx b/site/source/pages/assistants/components/Fields.tsx index 8dee35d3f..bd31aef61 100644 --- a/site/source/pages/assistants/components/Fields.tsx +++ b/site/source/pages/assistants/components/Fields.tsx @@ -19,7 +19,7 @@ import { situationSelector, targetUnitSelector, } from '@/store/selectors/simulationSelectors' -import { evaluateQuestion, getMeta } from '@/utils' +import { evaluateQuestion, getMeta } from '@/utils/publicodes' type SubSectionProp = { dottedName: DottedName diff --git a/site/source/pages/assistants/demande-mobilité/index.tsx b/site/source/pages/assistants/demande-mobilité/index.tsx index b377f5c39..2bd6bbb2e 100644 --- a/site/source/pages/assistants/demande-mobilité/index.tsx +++ b/site/source/pages/assistants/demande-mobilité/index.tsx @@ -19,13 +19,12 @@ import PopoverConfirm from '@/design-system/popover/PopoverConfirm' import { headings } from '@/design-system/typography' import { Intro, SmallBody } from '@/design-system/typography/paragraphs' import useSimulationConfig from '@/hooks/useSimulationConfig' +import { hash, omit } from '@/utils' import { buildSituationFromObject, evaluateQuestion, getMeta, - hash, - omit, -} from '@/utils' +} from '@/utils/publicodes' import formulaire from './demande-mobilité.yaml' diff --git a/site/source/pages/assistants/pour-mon-entreprise/index.tsx b/site/source/pages/assistants/pour-mon-entreprise/index.tsx index d3010412f..cf8839c47 100644 --- a/site/source/pages/assistants/pour-mon-entreprise/index.tsx +++ b/site/source/pages/assistants/pour-mon-entreprise/index.tsx @@ -42,7 +42,7 @@ import { useSitePaths } from '@/sitePaths' import { resetCompany } from '@/store/actions/companyActions' import { SimulationConfig } from '@/store/reducers/rootReducer' import { companySituationSelector } from '@/store/selectors/simulationSelectors' -import { evaluateQuestion } from '@/utils' +import { evaluateQuestion } from '@/utils/publicodes' import forms from './forms.svg' import growth from './growth.svg' diff --git a/site/source/pages/simulateurs/chômage-partiel/ChômagePartiel.tsx b/site/source/pages/simulateurs/chômage-partiel/ChômagePartiel.tsx index 1e3117850..494fb6525 100644 --- a/site/source/pages/simulateurs/chômage-partiel/ChômagePartiel.tsx +++ b/site/source/pages/simulateurs/chômage-partiel/ChômagePartiel.tsx @@ -20,7 +20,7 @@ import { H2 } from '@/design-system/typography/heading' import { Link } from '@/design-system/typography/link' import { Li, Ul } from '@/design-system/typography/list' import { Body } from '@/design-system/typography/paragraphs' -import { catchDivideByZeroError } from '@/utils' +import { catchDivideByZeroError } from '@/utils/publicodes' declare global { interface Window { diff --git a/site/source/store/actions/actions.ts b/site/source/store/actions/actions.ts index 4fa4371ab..db2c27963 100644 --- a/site/source/store/actions/actions.ts +++ b/site/source/store/actions/actions.ts @@ -4,7 +4,7 @@ import Engine, { PublicodesExpression } from 'publicodes' import { SimpleRuleEvaluation } from '@/domaine/engine/SimpleRuleEvaluation' import { SimulationConfig } from '@/store/reducers/rootReducer' import { QuestionRépondue } from '@/store/reducers/simulation.reducer' -import { buildSituationFromObject } from '@/utils' +import { buildSituationFromObject } from '@/utils/publicodes' import { CompanyActions } from './companyActions' import { HiringChecklistAction } from './hiringChecklistAction' diff --git a/site/source/store/reducers/companySituationReducer.ts b/site/source/store/reducers/companySituationReducer.ts index 37587853f..cee54bb56 100644 --- a/site/source/store/reducers/companySituationReducer.ts +++ b/site/source/store/reducers/companySituationReducer.ts @@ -4,7 +4,8 @@ import { CodeCatégorieJuridique } from '@/domaine/CodeCatégorieJuridique' import { toPublicodeDate } from '@/domaine/Date' import { Entreprise } from '@/domaine/Entreprise' import { Action } from '@/store/actions/actions' -import { buildSituationFromObject, omit } from '@/utils' +import { omit } from '@/utils' +import { buildSituationFromObject } from '@/utils/publicodes' import { Situation } from './rootReducer' diff --git a/site/source/utils/index.ts b/site/source/utils/index.ts index 145f57a0c..5b89e3bd1 100644 --- a/site/source/utils/index.ts +++ b/site/source/utils/index.ts @@ -1,13 +1,4 @@ -import { DottedName } from 'modele-social' -import Engine, { - formatValue, - isPublicodesError, - PublicodesExpression, - Rule, - RuleNode, -} from 'publicodes' - -import { Situation } from '@/store/reducers/rootReducer' +import { formatValue } from 'publicodes' /** The `capitalise0` function is a utility function that capitalizes the first letter of a string. The function takes an optional `name` parameter, which is a string that needs to be capitalized. */ @@ -180,17 +171,6 @@ export const getValueFrom = < ): Extract[K] | undefined => key in obj ? obj[key] : undefined -const isMeta = (rule: Rule): rule is Rule & { meta?: T } => 'meta' in rule - -/** - * Return typed meta property from a rule - * @param rule - * @param defaultValue - * @returns - */ -export const getMeta = (rule: Rule, defaultValue: T) => - (isMeta(rule) ? getValueFrom(rule, 'meta') : null) ?? defaultValue - /** * Wraps each event function specified in eventsToWrap (default onPress) with an * asynchronous function that waits x ms before executing the original function @@ -245,50 +225,6 @@ export async function getIframeOffset(): Promise { }) } -export function evaluateQuestion( - engine: Engine, - rule: RuleNode -): string | undefined { - const question = rule.rawNode.question as Exclude< - number, - PublicodesExpression - > - if (question && typeof question === 'object') { - return engine.evaluate(question as PublicodesExpression).nodeValue as string - } - - return question -} - -export function buildSituationFromObject( - contextDottedName: Names, - situationObject: Record -): Situation { - return Object.fromEntries( - Object.entries(situationObject).map( - ([key, value]: [string, PublicodesExpression]) => [ - `${contextDottedName} . ${key}` as Names, - typeof value === 'string' ? `'${value}'` : value, - ] - ) - ) -} - -export const catchDivideByZeroError = (func: () => T) => { - try { - return func() - } catch (err) { - if ( - isPublicodesError(err, 'EvaluationError') && - err.message === 'Division by zero' - ) { - // eslint-disable-next-line no-console - console.error(err) - } - throw err - } -} - export const generateUuid = () => { return Math.floor(Math.random() * Date.now()).toString(16) } diff --git a/site/source/utils/publicodes.ts b/site/source/utils/publicodes.ts new file mode 100644 index 000000000..383e94374 --- /dev/null +++ b/site/source/utils/publicodes.ts @@ -0,0 +1,89 @@ +import { DottedName } from 'modele-social' +import Engine, { + ASTNode, + isPublicodesError, + PublicodesExpression, + reduceAST, + Rule, + RuleNode, +} from 'publicodes' + +import { Situation } from '@/store/reducers/rootReducer' + +import { getValueFrom } from '.' + +const isMeta = (rule: Rule): rule is Rule & { meta?: T } => 'meta' in rule + +/** + * Return typed meta property from a rule + * @param rule + * @param defaultValue + * @returns + */ +export const getMeta = (rule: Rule, defaultValue: T) => + (isMeta(rule) ? getValueFrom(rule, 'meta') : null) ?? defaultValue + +export function evaluateQuestion( + engine: Engine, + rule: RuleNode +): string | undefined { + const question = rule.rawNode.question as Exclude< + number, + PublicodesExpression + > + if (question && typeof question === 'object') { + return engine.evaluate(question as PublicodesExpression).nodeValue as string + } + + return question +} + +export function buildSituationFromObject( + contextDottedName: Names, + situationObject: Record +): Situation { + return Object.fromEntries( + Object.entries(situationObject).map( + ([key, value]: [string, PublicodesExpression]) => [ + `${contextDottedName} . ${key}` as Names, + typeof value === 'string' ? `'${value}'` : value, + ] + ) + ) +} + +export const catchDivideByZeroError = (func: () => T) => { + try { + return func() + } catch (err) { + if ( + isPublicodesError(err, 'EvaluationError') && + err.message === 'Division by zero' + ) { + // eslint-disable-next-line no-console + console.error(err) + } + throw err + } +} + +export function findReferenceInNode( + dottedName: DottedName, + node: ASTNode +): string | undefined { + return reduceAST( + (acc, node) => { + if ( + node.nodeKind === 'reference' && + node.dottedName?.startsWith(dottedName) && + !node.dottedName.endsWith('$SITUATION') + ) { + return node.dottedName + } else if (node.nodeKind === 'reference') { + return acc + } + }, + undefined, + node + ) +}