From b069c40cbf2d44bd72494216c363859215c11d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Rialland?= Date: Wed, 14 Sep 2022 12:55:16 +0200 Subject: [PATCH] Fix safe situation catch errors --- .../source/components/utils/EngineContext.tsx | 49 ++++++++++++------- .../utils/useSearchParamsSimulationSharing.ts | 19 ++++--- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/site/source/components/utils/EngineContext.tsx b/site/source/components/utils/EngineContext.tsx index d3765c08c..56ebf3b92 100644 --- a/site/source/components/utils/EngineContext.tsx +++ b/site/source/components/utils/EngineContext.tsx @@ -4,14 +4,22 @@ import { configSituationSelector, situationSelector, } from '@/selectors/simulationSelectors' +import { omit } from '@/utils' import { DottedName } from 'modele-social' import Engine, { EvaluatedNode, + isPublicodesError, PublicodesExpression, Rule, RuleNode, } from 'publicodes' -import { createContext, useContext, useMemo } from 'react' +import { + createContext, + useContext, + useEffect, + useLayoutEffect, + useMemo, +} from 'react' import { useDispatch, useSelector } from 'react-redux' import i18n from '../../locales/i18n' @@ -60,36 +68,39 @@ export const useRawSituation = () => { export const useSetupSafeSituation = (engine: Engine) => { const dispatch = useDispatch() - const situation = useRawSituation() + const rawSituation = useRawSituation() - let loop = true - while (loop) { + // Try to set situation and delete all rules with syntax error + let situationError = false + let maxLoopCount = 1000 + let situation = { ...rawSituation } as typeof rawSituation + do { try { engine.setSituation(situation) - loop = false + situationError = false } catch (error) { - const errorStr = (error as Error).toString() - const faultyDottedName = ((/Erreur syntaxique/.test(errorStr) && - errorStr.match(/"[^"[]*\[([^"\]]*)\][^"\]]*"/)) || - null)?.[1] + situationError = true + maxLoopCount-- + + if (isPublicodesError(error, 'SyntaxError')) { + const faultyDottedName = error.info.dottedName as DottedName - if (faultyDottedName == null) { - loop = false - // eslint-disable-next-line no-console - console.error(error) - } else { // eslint-disable-next-line no-console console.error( - 'Key omit from situation:', - `"${faultyDottedName}"\n\n`, + `Key omit from situation: "${faultyDottedName}"\n\n`, error ) - // Delete faultyDottedName from redux store - dispatch(deleteFromSituation(faultyDottedName as DottedName)) + // Hack: Omit faultyDottedName from situation for next loop + situation = omit(situation, faultyDottedName) + + dispatch(deleteFromSituation(faultyDottedName)) + } else { + // eslint-disable-next-line no-console + console.error('safeSituationCatch', error) } } - } + } while (situationError && maxLoopCount > 0) } export function useInversionFail() { diff --git a/site/source/components/utils/useSearchParamsSimulationSharing.ts b/site/source/components/utils/useSearchParamsSimulationSharing.ts index 1121d5f8e..ed051cd9a 100644 --- a/site/source/components/utils/useSearchParamsSimulationSharing.ts +++ b/site/source/components/utils/useSearchParamsSimulationSharing.ts @@ -113,7 +113,7 @@ export const cleanSearchParams = ( setSearchParams(searchParams.toString(), { replace: true }) } -export const getRulesParamNames = ( +const getRulesParamNames = ( parsedRules: ParsedRules ): [DottedName, ParamName][] => ( @@ -126,7 +126,7 @@ export const getRulesParamNames = ( ruleNode.rawNode['identifiant court'] || dottedName, ]) -export function getSearchParamsFromSituation( +function getSearchParamsFromSituation( engine: Engine, situation: Situation, dottedNameParamName: [DottedName, ParamName][] @@ -136,12 +136,17 @@ export function getSearchParamsFromSituation( Object.entries(situation).forEach(([dottedName, value]) => { const paramName = dottedNameParamNameMapping[dottedName] - const serializedValue = serializeEvaluation(engine.evaluate(value)) + try { + const serializedValue = serializeEvaluation(engine.evaluate(value)) - if (typeof serializedValue !== 'undefined') { - searchParams.set(paramName, serializedValue) - } else if (typeof value === 'object') { - searchParams.set(paramName, JSON.stringify(value)) + if (typeof serializedValue !== 'undefined') { + searchParams.set(paramName, serializedValue) + } else if (typeof value === 'object') { + searchParams.set(paramName, JSON.stringify(value)) + } + } catch (error) { + // eslint-disable-next-line no-console + console.error(error) } }) searchParams.sort()