refactor: groupe la manipulation d'objets de Publicodes dans un fichier utils dédié
parent
3c2d9a3999
commit
4c4ff2cbdf
|
@ -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'
|
||||
|
|
|
@ -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<string | undefined>(
|
||||
(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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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[]
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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<T, { [k in K]?: unknown }>[K] | undefined =>
|
||||
key in obj ? obj[key] : undefined
|
||||
|
||||
const isMeta = <T>(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 = <T>(rule: Rule, defaultValue: T) =>
|
||||
(isMeta<T>(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<number> {
|
|||
})
|
||||
}
|
||||
|
||||
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<Names extends string = DottedName>(
|
||||
contextDottedName: Names,
|
||||
situationObject: Record<string, PublicodesExpression>
|
||||
): Situation {
|
||||
return Object.fromEntries(
|
||||
Object.entries(situationObject).map(
|
||||
([key, value]: [string, PublicodesExpression]) => [
|
||||
`${contextDottedName} . ${key}` as Names,
|
||||
typeof value === 'string' ? `'${value}'` : value,
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const catchDivideByZeroError = <T>(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)
|
||||
}
|
||||
|
|
|
@ -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 = <T>(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 = <T>(rule: Rule, defaultValue: T) =>
|
||||
(isMeta<T>(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<Names extends string = DottedName>(
|
||||
contextDottedName: Names,
|
||||
situationObject: Record<string, PublicodesExpression>
|
||||
): Situation {
|
||||
return Object.fromEntries(
|
||||
Object.entries(situationObject).map(
|
||||
([key, value]: [string, PublicodesExpression]) => [
|
||||
`${contextDottedName} . ${key}` as Names,
|
||||
typeof value === 'string' ? `'${value}'` : value,
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const catchDivideByZeroError = <T>(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<string | undefined>(
|
||||
(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
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue