Fix infinite loop

engine-in-web-worker
Jérémy Rialland 2023-09-07 17:12:20 +02:00
parent db49a62fe5
commit 00f26f11f2
8 changed files with 54 additions and 67 deletions

View File

@ -196,7 +196,9 @@ function ActivitéMixte() {
Activité mixte
</Switch>
</Trans>
{rule && <ExplicableRule dottedName={rule.dottedName} light />}
{rule && (
<ExplicableRule dottedName={rule.dottedName as DottedName} light />
)}
</StyledActivitéMixteContainer>
</div>
)

View File

@ -1,5 +1,4 @@
import { DottedName } from 'modele-social'
import Engine from 'publicodes'
import { WorkerEngine } from '@publicodes/worker-react'
import { Trans } from 'react-i18next'
import { styled } from 'styled-components'
@ -27,10 +26,10 @@ const Notice = styled(Body)`
export function Questions({
customEndMessages,
engines,
workerEngines,
}: {
customEndMessages?: ConversationProps['customEndMessages']
engines?: Array<Engine<DottedName>>
workerEngines?: WorkerEngine[]
}) {
const { numberCurrentStep, numberSteps } = useSimulationProgress()
@ -47,7 +46,10 @@ export function Questions({
</Notice>
)}
</div>
<Conversation customEndMessages={customEndMessages} engines={engines} />
<Conversation
customEndMessages={customEndMessages}
workerEngines={workerEngines}
/>
</QuestionsContainer>
</>
)

View File

@ -1,5 +1,4 @@
import { DottedName } from 'modele-social'
import Engine from 'publicodes'
import { WorkerEngine } from '@publicodes/worker-react'
import React from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
@ -29,7 +28,7 @@ export { SimulationGoals } from './SimulationGoals'
type SimulationProps = {
explanations?: React.ReactNode
engines?: Array<Engine<DottedName>>
workerEngines?: WorkerEngine[]
results?: React.ReactNode
children?: React.ReactNode
afterQuestionsSlot?: React.ReactNode
@ -57,7 +56,7 @@ export default function Simulation({
afterQuestionsSlot,
customEndMessages,
showQuestionsFromBeginning,
engines,
workerEngines,
hideDetails = false,
fullWidth,
id,
@ -83,7 +82,7 @@ export default function Simulation({
<FromTop>{results}</FromTop>
</div>
<Questions
engines={engines}
workerEngines={workerEngines}
customEndMessages={customEndMessages}
/>
</>

View File

@ -1,4 +1,4 @@
import { useWorkerEngine } from '@publicodes/worker-react'
import { usePromise, useWorkerEngine } from '@publicodes/worker-react'
import { DottedName } from 'modele-social'
import { PublicodesExpression, RuleNode, utils } from 'publicodes'
import { useCallback, useMemo } from 'react'
@ -17,7 +17,6 @@ import { Link } from '@/design-system/typography/link'
import { Body, Intro } from '@/design-system/typography/paragraphs'
import { useCurrentSimulatorData } from '@/hooks/useCurrentSimulatorData'
import { useNextQuestions } from '@/hooks/useNextQuestion'
import { usePromise } from '@/hooks/usePromise'
import { answerQuestion, resetSimulation } from '@/store/actions/actions'
import { resetCompany } from '@/store/actions/companyActions'
import { isCompanyDottedName } from '@/store/reducers/companySituationReducer'
@ -79,30 +78,21 @@ export default function AnswerList({ onClose, children }: AnswerListProps) {
const situationQuestions = useMemo(
() =>
answeredAndPassedQuestions.filter(
({ dottedName }) => !isCompanyDottedName(dottedName)
({ dottedName }) => !isCompanyDottedName(dottedName as DottedName)
),
[answeredAndPassedQuestions]
)
const companyQuestions = usePromise(
() =>
Promise.all(
Array.from(
new Set(
(
[
...answeredAndPassedQuestions.map(
({ dottedName }) => dottedName
),
...Object.keys(situation),
...Object.keys(companySituation),
] as Array<DottedName>
).filter(isCompanyDottedName)
)
).map((dottedName) => workerEngine.getRule(dottedName))
),
[answeredAndPassedQuestions, companySituation, situation, workerEngine],
[] as RuleNode<DottedName>[]
)
const companyQuestions = Array.from(
new Set(
(
[
...answeredAndPassedQuestions.map(({ dottedName }) => dottedName),
...Object.keys(situation),
...Object.keys(companySituation),
] as Array<DottedName>
).filter(isCompanyDottedName)
)
).map((dottedName) => workerEngine.getRule(dottedName))
const siret = usePromise(
async () =>

View File

@ -1,4 +1,8 @@
import { useWorkerEngine, WorkerEngine } from '@publicodes/worker-react'
import {
usePromise,
useWorkerEngine,
WorkerEngine,
} from '@publicodes/worker-react'
import { DottedName } from 'modele-social'
import { PublicodesExpression, RuleNode } from 'publicodes'
import { Fragment } from 'react'
@ -6,14 +10,13 @@ import { useTranslation } from 'react-i18next'
import { Checkbox } from '@/design-system'
import { Emoji } from '@/design-system/emoji'
import { usePromise } from '@/hooks/usePromise'
import { ExplicableRule } from './Explicable'
import { InputProps, RuleWithMultiplePossibilities } from './RuleInput'
export function MultipleChoicesInput<Names extends string = DottedName>(
props: Omit<InputProps<DottedName>, 'onChange'> & {
engineId: number
// engineId: number
onChange: (value: PublicodesExpression, name: DottedName) => void
}
) {
@ -21,7 +24,7 @@ export function MultipleChoicesInput<Names extends string = DottedName>(
const workerEngine = useWorkerEngine()
const choices = getMultiplePossibilitiesOptions(
workerEngine,
engineId,
// engineId,
dottedName
)
@ -47,7 +50,7 @@ export function MultipleChoicesInput<Names extends string = DottedName>(
onChange={(isSelected) =>
void handleChange(isSelected, node.dottedName)
}
engineId={engineId}
// engineId={engineId}
/>
</Fragment>
))}
@ -57,10 +60,14 @@ export function MultipleChoicesInput<Names extends string = DottedName>(
type CheckBoxRuleProps = {
node: RuleNode
engineId: number
// engineId: number
onChange: (isSelected: boolean) => void
}
function CheckBoxRule({ node, engineId, onChange }: CheckBoxRuleProps) {
function CheckBoxRule({
node,
// engineId,
onChange,
}: CheckBoxRuleProps) {
const workerEngine = useWorkerEngine()
const evaluation = usePromise(
@ -95,7 +102,7 @@ function CheckBoxRule({ node, engineId, onChange }: CheckBoxRuleProps) {
function getMultiplePossibilitiesOptions(
workerEngine: WorkerEngine,
engineId: number,
// engineId: number,
// engine: Engine<Name>,
dottedName: DottedName
): RuleNode<DottedName>[] {

View File

@ -63,7 +63,7 @@ export type InputProps<Name extends string = string> = Omit<
value: EvaluatedNode['nodeValue']
onChange: (value: PublicodesExpression | undefined) => void
// engine: Engine<Name>
engineId: number
// engineId: number
}
export const binaryQuestion = [
@ -84,7 +84,7 @@ export default function RuleInput({
missing,
inputType,
modifiers,
engineId = 0,
// engineId = 0, // TODO engine id is in worker engine so we need to accept workerEngine from props
...props
}: Props<DottedName>) {
// const defaultEngine = useContext(EngineContext)
@ -109,7 +109,7 @@ export default function RuleInput({
const value = evaluation?.nodeValue
const isMultipleChoices =
rule && isMultiplePossibilities(workerEngine, engineId, dottedName)
rule && isMultiplePossibilities(workerEngine, dottedName)
const choice = usePromise(
() => getOnePossibilityOptions(workerEngine, dottedName),
@ -132,7 +132,7 @@ export default function RuleInput({
question: rule.rawNode.question,
suggestions: showSuggestions ? rule.suggestions : {},
// engine: engineValue,
engineId,
// engineId,
...props,
// Les espaces ne sont pas autorisés dans un id, les points sont assimilés à une déclaration de class CSS par Cypress
id: props?.id?.replace(/\s|\.]/g, '_') ?? dottedName.replace(/\s|\./g, '_'),
@ -143,7 +143,7 @@ export default function RuleInput({
return (
<MultipleChoicesInput
{...commonProps}
engineId={engineId}
// engineId={engineId}
onChange={onChange}
/>
)
@ -245,11 +245,6 @@ const getOnePossibilityOptions = async (
): Promise<Choice> => {
const node = workerEngine.getRule(path)
// if (path === 'entreprise . activité . nature') debugger
if (!node) {
throw new Error(`La règle ${path} est introuvable`)
}
const variant = isOnePossibility(node)
const canGiveUp =
variant &&
@ -265,8 +260,6 @@ const getOnePossibilityOptions = async (
(
variant.explanation as (ASTNode & { nodeKind: 'reference' })[]
).map(async (explanation) => {
console.log('=>>>>', explanation)
const evaluate = await workerEngine.asyncEvaluate(explanation)
return evaluate.nodeValue !== null
@ -293,13 +286,8 @@ export type RuleWithMultiplePossibilities = RuleNode & {
function isMultiplePossibilities(
workerEngine: WorkerEngine,
engineId: number,
// Engine<Name>,
dottedName: DottedName
): boolean {
// return !!(engine.getRule(dottedName) as RuleWithMultiplePossibilities)
// .rawNode['plusieurs possibilités']
return !!(workerEngine.getRule(dottedName) as RuleWithMultiplePossibilities)
.rawNode['plusieurs possibilités']
}

View File

@ -1,4 +1,5 @@
import { WorkerEngine } from '@publicodes/worker-react'
import { DottedName } from 'modele-social'
import { useCallback, useEffect, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
@ -48,7 +49,8 @@ export function useNavigateQuestions(workerEngines?: WorkerEngine[]) {
}, [currentQuestion, dispatch, nextQuestions])
return {
currentQuestion: currentQuestion ?? nextQuestions[0],
currentQuestion:
currentQuestion ?? (nextQuestions[0] as DottedName | undefined),
currentQuestionIsAnswered,
goToPrevious,
goToNext,

View File

@ -74,7 +74,7 @@ export const useNextQuestions = function (
const workerEngine = useWorkerEngine()
const missingVariables = useMissingVariables(workerEngines)
return useMemo(() => {
const nextQuestions = useMemo(() => {
const next = getNextQuestions(
missingVariables,
config.questions ?? {},
@ -83,13 +83,10 @@ export const useNextQuestions = function (
const rules = next.map((question) => workerEngine.getRule(question))
const nextQuestions = next.filter(
(_, i) => rules[i].rawNode.question !== undefined
)
console.log('nextQuestions', nextQuestions)
return next.filter((_, i) => rules[i].rawNode.question !== undefined)
}, [missingVariables, config.questions, answeredQuestions, workerEngine])
return nextQuestions
}, [answeredQuestions, config, missingVariables])
return nextQuestions
}
export function useSimulationProgress(): {