iobroker.statechart 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/chart-runtime.ts"],
4
+ "sourcesContent": ["import crypto from \"node:crypto\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport vm from \"node:vm\";\nimport SunCalc from \"suncalc\";\nimport type { SunTimes } from \"suncalc\";\nimport { createActor, createMachine } from \"xstate\";\nimport type { AnyActor, AnyStateMachine } from \"xstate\";\nimport { isTimeBetween } from \"./chart-helpers\";\nimport { MAX_SUPER_STEPS, parseTransitionLabel } from \"./chart-model\";\nimport type { Chart, ChartState, ChartSymbol, ChartTransition } from \"./chart-model\";\nimport { ChartStructure } from \"./chart-structure\";\nimport { getDeclarations, quoteChangeArguments, validateChart } from \"./chart-validation\";\nimport type { CodeKind } from \"./chart-validation\";\n\n/** Maximum run time of a single condition or action */\nconst SCRIPT_TIMEOUT_MS = 1000;\n\n/** Longer delays are not supported by setTimeout() */\nconst MAX_TIMEOUT_MS = 2 ** 31 - 1;\n\n/** Version of the persisted data, increase on incompatible changes */\nconst PERSISTED_VERSION = 1;\n\n/**\n * The persisted state of a running chart, restored when the adapter starts again\n */\nexport interface PersistedChart {\n /** See PERSISTED_VERSION */\n version: number;\n /** Of the chart logic, the data is only restored for an unchanged chart */\n hash: string;\n /** Persisted XState snapshot (active states) */\n machine: any;\n /** Time each active state was entered (ms since 1970) */\n entered: Record<string, number>;\n /** Values of the local variables */\n locals: Record<string, any>;\n}\n\n/**\n * A hash over everything which influences the execution, but not e.g. the positions in the editor\n *\n * @param chart The chart\n */\nexport function getChartHash(chart: Chart): string {\n const logic = {\n initial: chart.initial,\n symbols: chart.symbols,\n // comments and notes are only documentation\n states: chart.states.map(({ x: _x, y: _y, width: _w, height: _h, comment: _c, ...state }) => state),\n transitions: chart.transitions.map(\n ({\n sourceHandle: _s,\n targetHandle: _t,\n sourceAnchor: _sa,\n targetAnchor: _ta,\n comment: _c,\n ...transition\n }) => transition,\n ),\n functions: (chart.functions || []).map(fn => fn.code),\n };\n return crypto.createHash(\"sha1\").update(JSON.stringify(logic)).digest(\"hex\");\n}\n\nexport interface Location {\n latitude: number;\n longitude: number;\n}\n\n/**\n * What woke up the chart: a change of an input, a timer of after(...), or the start of the chart\n */\nexport type WakeupCause = \"input\" | \"timer\" | \"start\";\n\n/**\n * An event of a running chart, shown in the history of the editor\n */\nexport interface HistoryEntry {\n /** Time of the event (ms since 1970) */\n ts: number;\n /** \"start\": the chart was started, \"transition\": a transition was taken */\n kind: \"start\" | \"transition\";\n /** Start only: the chart continued with the state from before the restart of the adapter */\n restored?: boolean;\n /** Transition only: ID of the transition */\n transition?: string;\n /** Transition only: name of the source state */\n from?: string;\n /** Transition only: name of the target state */\n to?: string;\n /** Transition only: name of the input which woke up the chart, null for the other causes */\n trigger?: string | null;\n /** Transition only: what woke up the chart (missing in entries of older versions: input if trigger is set) */\n cause?: WakeupCause;\n /** Name paths of the active states after the event, e.g. \"Auto.Heat\" */\n active: string;\n}\n\n/**\n * The connection of a chart to the outside world, provided by the adapter\n */\nexport interface RuntimeHost {\n /** Reads the current value of a state */\n readState: (stateId: string) => Promise<any>;\n /** Writes the value of a state */\n writeState: (stateId: string, val: any, ack?: boolean) => Promise<void>;\n /** Sends a message to an adapter */\n sendTo?: (instance: string, command: string, message: any) => void;\n /** Of the ioBroker system settings */\n getLocation?: () => Location | null;\n /** Called when the active states change */\n onActiveChange: (active: { names: string; ids: string[] }) => void;\n /** Stores the state of the chart, called when it changes */\n persist?: (data: PersistedChart) => void;\n /** Loads the stored state of the chart */\n loadPersisted?: () => Promise<PersistedChart | null>;\n /** Called with the values of all variables when one of them changed, after the chart processed a wakeup */\n onValues?: (values: Record<string, any>) => void;\n /** Called with the events of a start or a wakeup, in the order they happened */\n onHistory?: (entries: HistoryEntry[]) => void;\n log: Pick<ioBroker.Logger, LogLevel>;\n}\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * A transition which is checked on wakeups\n */\ninterface CheckedTransition {\n id: string;\n /** ID of the source state */\n source: string;\n /** Used in error messages */\n where: string;\n /** Name of the source state */\n from: string;\n /** Name of the target state */\n to: string;\n /** Name of the input which must have caused the wakeup */\n event?: string;\n /** Temporal transition: only valid this long after entering the source state */\n afterMs?: number;\n condition: vm.Script | null;\n}\n\n/**\n * Executes a single chart with XState.\n *\n * Wakeup semantics like Stateflow: every change of an input wakes up the chart once, as well as every\n * expiring after(...) of an active state. Transitions with event are only checked when that input changed,\n * all others on every wakeup. A temporal transition after(n, unit) is valid from n units after entering its\n * source state on, so its condition is checked again on every following wakeup.\n *\n * Starting with the active top level state, each active state is processed like this:\n * 1. its outer transitions, 2. its \"during\" action, 3. its inner transitions (to its own children),\n * 4. its active child. Processing stops as soon as a transition is taken.\n *\n * The runtime selects the transition itself and sends an event for exactly this transition to XState,\n * which executes the exit, transition and entry actions in the right order.\n */\nexport class ChartRuntime {\n readonly structure: ChartStructure;\n readonly statesById: Map<string, ChartState>;\n /** timers of setStateDelayed() */\n readonly delayedWrites = new Set<NodeJS.Timeout>();\n /** values of all symbols, this is also the global scope of conditions and actions */\n readonly sandbox: vm.Context;\n /** last value written to (or read from) each output */\n readonly outputValues = new Map<string, any>();\n /** transitions which leave the source state, by source, sorted */\n readonly outerTransitions = new Map<string, CheckedTransition[]>();\n /** transitions to children of the source state, by source, sorted */\n readonly innerTransitions = new Map<string, CheckedTransition[]>();\n /** temporal transitions by source */\n readonly temporalTransitions = new Map<string, CheckedTransition[]>();\n /** all active states, parents before children */\n activeIds: string[] = [];\n /** time each active state was entered */\n readonly enteredAt = new Map<string, number>();\n /** timers of the temporal transitions by state */\n readonly timers = new Map<string, { handle?: NodeJS.Timeout }[]>();\n /** temporal transitions whose time has come */\n readonly expired = new Set<string>();\n /** timers of inputs with debounce, by variable name */\n readonly debounceTimers = new Map<string, NodeJS.Timeout>();\n /** JSON of the last persisted data, to persist only changes */\n lastPersisted = \"\";\n /** name paths of the active leaf states, like the \"activeState\" state */\n activeNames = \"\";\n /** events which are not yet passed to host.onHistory() */\n pendingHistory: HistoryEntry[] = [];\n /** JSON of the last values passed to host.onValues(), to pass only changes */\n lastValues = \"\";\n /** what caused the current wakeup, for the history */\n wakeupCause: WakeupCause = \"input\";\n /** name of the input which caused the current wakeup, for the history */\n wakeupInput: string | null = null;\n /** the code of conditions, actions and function blocks prepared for the change detection, by kind and code */\n readonly preparedCode = new Map<string, string>();\n /** the variables used by hasChanged() etc. */\n readonly changeVariables = new Set<string>();\n /** their values at the start of the previous wakeup, null before the second wakeup */\n previousValues: Map<string, any> | null = null;\n /** their values at the start of the current wakeup, null before the first one */\n currentValues: Map<string, any> | null = null;\n readonly hash: string;\n actor: AnyActor | null = null;\n /** the current time, can be replaced in tests */\n now = (): number => Date.now();\n\n constructor(\n readonly chartId: string,\n readonly chart: Chart,\n readonly host: RuntimeHost,\n ) {\n this.structure = new ChartStructure(chart);\n this.statesById = this.structure.statesById;\n this.sandbox = vm.createContext(this.createHelpers());\n this.hash = getChartHash(chart);\n this.prepareAllCode();\n }\n\n /**\n * Prepares all code of the chart for the change detection, so its variables are known from the first wakeup on\n */\n prepareAllCode(): void {\n for (const state of this.chart.states) {\n for (const code of [state.entry, state.during, state.exit]) {\n this.prepareCode(code, \"statements\");\n }\n }\n for (const transition of this.chart.transitions) {\n try {\n const label = parseTransitionLabel(transition.label);\n this.prepareCode(label.condition, \"expression\");\n this.prepareCode(label.action, \"statements\");\n } catch {\n // the transition is ignored, see buildTransition()\n }\n }\n for (const fn of this.chart.functions || []) {\n this.prepareCode(fn.code, \"statements\");\n }\n }\n\n /**\n * @param code A condition, action or function block\n * @param kind Expression or statements\n * @returns the code with the names of the variables in hasChanged() etc., see quoteChangeArguments()\n */\n prepareCode(code: string | undefined, kind: CodeKind): string {\n if (!code) {\n return \"\";\n }\n const key = `${kind}:${code}`;\n let prepared = this.preparedCode.get(key);\n if (prepared === undefined) {\n const quoted = quoteChangeArguments(code, kind);\n prepared = quoted.code;\n for (const name of quoted.names) {\n this.changeVariables.add(name);\n }\n this.preparedCode.set(key, prepared);\n }\n return prepared;\n }\n\n /**\n * IDs of all states this chart reads\n */\n get inputStateIds(): string[] {\n return this.chart.symbols.filter(s => s.scope === \"input\" && s.stateId).map(s => s.stateId as string);\n }\n\n /**\n * @param options Start options\n * @param options.restore Continue with the persisted state, if the chart was not changed since\n */\n async start(options: { restore?: boolean } = {}): Promise<void> {\n this.logProblems();\n for (const symbol of this.chart.symbols) {\n if (symbol.scope === \"local\") {\n // a copy, so actions changing an object or array do not change the chart model\n this.sandbox[symbol.name] = structuredClone(symbol.initial);\n } else if (symbol.stateId) {\n const val = await this.host.readState(symbol.stateId);\n this.sandbox[symbol.name] = val;\n if (symbol.scope === \"output\") {\n this.outputValues.set(symbol.name, val);\n }\n }\n }\n\n // defines the functions, without block around the code so they become globals of the sandbox\n for (const fn of this.chart.functions || []) {\n const where = `function block ${getDeclarations(fn.code)\n .map(d => d.name)\n .join(\", \")}`;\n this.run(this.compile(this.prepareCode(fn.code, \"statements\"), where), where);\n }\n this.writeChangedOutputs();\n\n const machine = createMachine(this.buildMachineConfig());\n const persisted = options.restore && this.chart.restoreState !== false ? await this.loadPersisted() : null;\n let restored = false;\n if (persisted) {\n try {\n this.restore(machine, persisted);\n restored = true;\n this.host.log.info(`[${this.chart.name}] Restored the state from before the restart`);\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] Cannot restore the state, starting anew: ${err.message}`);\n this.stop();\n this.startActor(machine);\n }\n } else {\n this.startActor(machine);\n }\n this.pendingHistory.push({ ts: this.now(), kind: \"start\", restored, active: this.activeNames });\n // like the first time step in Stateflow: transitions without event, whose condition is already true,\n // are taken right away instead of on the next change of an input\n this.wakeup(null, \"start\");\n }\n\n /**\n * Starts the chart in its initial state, the entry actions are executed\n *\n * @param machine The XState machine of the chart\n */\n startActor(machine: AnyStateMachine): void {\n this.activeIds = [];\n this.enteredAt.clear();\n this.actor = createActor(machine);\n this.subscribe();\n this.actor.start();\n }\n\n /**\n * Continues with a persisted state: the entry actions are not executed again,\n * the timers of the temporal transitions continue with their remaining time\n *\n * @param machine The XState machine of the chart\n * @param persisted The stored state\n */\n restore(machine: AnyStateMachine, persisted: PersistedChart): void {\n for (const symbol of this.chart.symbols) {\n if (symbol.scope === \"local\" && symbol.name in persisted.locals) {\n this.sandbox[symbol.name] = persisted.locals[symbol.name];\n }\n }\n this.actor = createActor(machine, { snapshot: persisted.machine });\n this.subscribe();\n this.actor.start();\n this.publishActiveStates(this.actor.getSnapshot().value);\n for (const id of this.activeIds) {\n this.enteredAt.set(id, persisted.entered[id] ?? this.now());\n this.startTimers(id);\n }\n }\n\n subscribe(): void {\n this.actor?.subscribe({\n next: snapshot => this.publishActiveStates(snapshot.value),\n error: err => this.host.log.error(`[${this.chart.name}] ${String(err)}`),\n });\n }\n\n /**\n * @returns the persisted data, if it fits to this chart\n */\n async loadPersisted(): Promise<PersistedChart | null> {\n let persisted;\n try {\n persisted = await this.host.loadPersisted?.();\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] Cannot load the stored state: ${err.message}`);\n return null;\n }\n if (!persisted?.machine || persisted.version !== PERSISTED_VERSION) {\n return null;\n }\n if (persisted.hash !== this.hash) {\n this.host.log.info(`[${this.chart.name}] The chart was changed, starting in the initial state`);\n return null;\n }\n return { ...persisted, entered: persisted.entered || {}, locals: persisted.locals || {} };\n }\n\n /**\n * Stores the current state of the chart, if it changed since the last time\n */\n persist(): void {\n if (!this.actor || !this.host.persist) {\n return;\n }\n const data: PersistedChart = {\n version: PERSISTED_VERSION,\n hash: this.hash,\n machine: this.actor.getPersistedSnapshot(),\n entered: Object.fromEntries(this.enteredAt),\n locals: Object.fromEntries(\n this.chart.symbols.filter(s => s.scope === \"local\").map(s => [s.name, this.sandbox[s.name]]),\n ),\n };\n let json;\n try {\n json = JSON.stringify(data);\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] Cannot store the state: ${err.message}`);\n return;\n }\n if (json !== this.lastPersisted) {\n this.lastPersisted = json;\n this.host.persist(data);\n }\n }\n\n /**\n * Called by XState before the entry action of a state\n *\n * @param id ID of the state\n */\n onEnter(id: string): void {\n this.enteredAt.set(id, this.now());\n this.startTimers(id);\n }\n\n /**\n * Called by XState after the exit action of a state\n *\n * @param id ID of the state\n */\n onExit(id: string): void {\n this.enteredAt.delete(id);\n for (const timer of this.timers.get(id) || []) {\n clearTimeout(timer.handle);\n }\n this.timers.delete(id);\n for (const transition of this.temporalTransitions.get(id) || []) {\n this.expired.delete(transition.id);\n }\n }\n\n /**\n * Starts a timer for every temporal transition of a state, which wakes up the chart when its time has come\n *\n * @param id ID of the state\n */\n startTimers(id: string): void {\n const entered = this.enteredAt.get(id) ?? this.now();\n const timers: { handle?: NodeJS.Timeout }[] = [];\n for (const transition of this.temporalTransitions.get(id) || []) {\n const timer: { handle?: NodeJS.Timeout } = {};\n const due = entered + (transition.afterMs as number);\n const wait = (): void => {\n const remaining = due - this.now();\n timer.handle = setTimeout(\n () => {\n if (due - this.now() > 0 && remaining > MAX_TIMEOUT_MS) {\n wait();\n return;\n }\n this.expired.add(transition.id);\n this.wakeup(null);\n },\n Math.min(Math.max(remaining, 0), MAX_TIMEOUT_MS),\n );\n };\n wait();\n timers.push(timer);\n }\n this.timers.set(id, timers);\n }\n\n /**\n * Logs the problems found by the validation, the chart is started anyway\n */\n logProblems(): void {\n for (const { kind, id, field, diagnostic } of validateChart(this.chart)) {\n let where;\n if (kind === \"state\") {\n where = `${this.statesById.get(id)?.name ?? id}/${field}`;\n } else if (kind === \"function\") {\n const fn = this.chart.functions?.find(f => f.id === id);\n where = `Function block ${getDeclarations(fn?.code)\n .map(d => d.name)\n .join(\", \")}`;\n } else {\n const transition = this.chart.transitions.find(t => t.id === id);\n const source = this.statesById.get(transition?.source ?? \"\")?.name;\n const target = this.statesById.get(transition?.target ?? \"\")?.name;\n where = `Transition ${source} -> ${target}`;\n }\n const log = diagnostic.severity === \"error\" ? this.host.log.error : this.host.log.warn;\n log(`[${this.chart.name}] ${where}: ${diagnostic.message}`);\n }\n }\n\n stop(): void {\n this.actor?.stop();\n this.actor = null;\n for (const timers of this.timers.values()) {\n for (const timer of timers) {\n clearTimeout(timer.handle);\n }\n }\n this.timers.clear();\n this.expired.clear();\n for (const timer of this.debounceTimers.values()) {\n clearTimeout(timer);\n }\n this.debounceTimers.clear();\n for (const timer of this.delayedWrites) {\n clearTimeout(timer);\n }\n this.delayedWrites.clear();\n }\n\n /**\n * The helper functions which can be used in conditions and actions, see chart-helpers.ts\n */\n createHelpers(): Record<string, (...args: any[]) => any> {\n const prefix = `[${this.chart.name}]`;\n const write = (id: string, value: any, ack: boolean): Promise<void> =>\n this.host\n .writeState(String(id), value, !!ack)\n .catch(err => this.host.log.warn(`${prefix} Cannot write ${id}: ${err}`));\n return {\n log: (message: string, level = \"info\") => {\n const method: LogLevel = [\"debug\", \"info\", \"warn\", \"error\"].includes(level)\n ? (level as LogLevel)\n : \"info\";\n this.host.log[method](`${prefix} ${message}`);\n },\n setState: (id: string, value: any, ack = false) => {\n void write(id, value, ack);\n },\n setStateDelayed: (id: string, value: any, delayMs: number, ack = false) => {\n const timer = setTimeout(\n () => {\n this.delayedWrites.delete(timer);\n void write(id, value, ack);\n },\n Math.min(Math.max(Number(delayMs) || 0, 0), MAX_TIMEOUT_MS),\n );\n this.delayedWrites.add(timer);\n },\n sendTo: (instance: string, command: string, message: any) => {\n if (!this.host.sendTo) {\n throw new Error(\"sendTo() is not available\");\n }\n this.host.sendTo(String(instance), String(command), message);\n },\n isTimeBetween: (start: string, end: string) => isTimeBetween(start, end, new Date(this.now())),\n isDaytime: () => {\n const now = new Date(this.now());\n const { sunrise, sunset, alwaysUp } = this.getSunTimes(now);\n // in polar regions there may be no sunrise or sunset: the sun is up or down all day\n if (!sunrise || !sunset) {\n return !!alwaysUp;\n }\n return now >= sunrise && now < sunset;\n },\n astroTime: (name: string, offsetMinutes = 0) => {\n const times = this.getSunTimes(new Date(this.now()));\n const time = times[name];\n if (!(time instanceof Date)) {\n // the events are null if they do not happen on that day, the flags are no events\n const known = name in times && name !== \"alwaysUp\" && name !== \"alwaysDown\";\n throw new Error(\n known\n ? `There is no \"${name}\" today at the location of the system settings`\n : `Unknown astro event \"${name}\"`,\n );\n }\n return new Date(time.getTime() + (Number(offsetMinutes) || 0) * 60_000);\n },\n hasChanged: (name: string) => this.getChange(name, \"hasChanged\").changed,\n hasChangedFrom: (name: string, value: any) => {\n const { changed, previous } = this.getChange(name, \"hasChangedFrom\");\n return changed && isDeepStrictEqual(previous, value);\n },\n hasChangedTo: (name: string, value: any) => {\n const { changed, current } = this.getChange(name, \"hasChangedTo\");\n return changed && isDeepStrictEqual(current, value);\n },\n };\n }\n\n /**\n * @param date The day\n * @returns the astro events of the day, null for events which do not happen on that day (polar regions)\n * @throws {Error} if no location is configured\n */\n getSunTimes(date: Date): SunTimes {\n const location = this.host.getLocation?.();\n if (!location) {\n throw new Error(\"No location (latitude/longitude) configured in the ioBroker system settings\");\n }\n return SunCalc.getTimes(date, location.latitude, location.longitude);\n }\n\n /**\n * Must be called when an input state is updated\n *\n * @param stateId ID of the updated state\n * @param val The new value\n * @param options The ack flag of the update\n * @param options.ack The ack flag of the update\n */\n handleInput(stateId: string, val: any, options: { ack?: boolean } = {}): void {\n if (!this.actor) {\n return;\n }\n for (const symbol of this.chart.symbols) {\n if (symbol.scope !== \"input\" || symbol.stateId !== stateId) {\n continue;\n }\n // an update which is filtered out does not change the variable either\n if ((symbol.ack === \"ack\" && options.ack !== true) || (symbol.ack === \"command\" && options.ack !== false)) {\n continue;\n }\n const debounceMs = symbol.debounceMs || 0;\n if (debounceMs > 0) {\n // wake up only after the input was quiet for the debounce time, with its last value\n clearTimeout(this.debounceTimers.get(symbol.name));\n this.debounceTimers.set(\n symbol.name,\n setTimeout(() => {\n this.debounceTimers.delete(symbol.name);\n this.applyInput(symbol, val);\n }, debounceMs),\n );\n } else {\n this.applyInput(symbol, val);\n }\n }\n }\n\n /**\n * Sets the variable of an input and wakes up the chart\n *\n * @param symbol The input\n * @param val The new value\n */\n applyInput(symbol: ChartSymbol, val: any): void {\n if (symbol.trigger === \"change\" && val === this.sandbox[symbol.name]) {\n return;\n }\n this.sandbox[symbol.name] = val;\n this.wakeup(symbol.name);\n }\n\n /**\n * @param input Name of the input which caused the wakeup, null for timers and the start\n * @param cause What caused the wakeup\n */\n wakeup(input: string | null, cause: WakeupCause = input === null ? \"timer\" : \"input\"): void {\n if (!this.actor) {\n return;\n }\n this.wakeupCause = cause;\n this.wakeupInput = input;\n this.rememberValues();\n if (!this.chart.superStep) {\n this.step(input);\n } else {\n // super step: take transitions until none is valid anymore. Like in Stateflow, the event of the input\n // is only present in the first step, the following steps check the transitions without event.\n let steps = 0;\n let stepInput = input;\n while (steps < MAX_SUPER_STEPS && this.step(stepInput)) {\n steps++;\n stepInput = null;\n }\n if (steps >= MAX_SUPER_STEPS) {\n this.host.log.warn(\n `[${this.chart.name}] Stopped after ${MAX_SUPER_STEPS} transitions in one wakeup, the transitions probably form a loop. The chart continues on the next wakeup.`,\n );\n }\n }\n // functions called in conditions may have changed outputs as well\n this.writeChangedOutputs();\n this.persist();\n this.publishLive();\n }\n\n /**\n * Stores the values of the variables used by the change detection at the start of a wakeup\n */\n rememberValues(): void {\n if (!this.changeVariables.size) {\n return;\n }\n this.previousValues = this.currentValues;\n this.currentValues = new Map();\n for (const name of this.changeVariables) {\n const value = this.sandbox[name];\n let copy;\n try {\n // a copy, so a change of an object or array by an action is detected as well\n copy = structuredClone(value);\n } catch {\n copy = value;\n }\n this.currentValues.set(name, copy);\n }\n }\n\n /**\n * @param name Name of the variable\n * @param helper Name of the helper, for the error message\n * @returns whether the variable has changed between the start of the previous and of the current wakeup\n * @throws {Error} if the variable is unknown\n */\n getChange(name: string, helper: string): { changed: boolean; previous?: any; current?: any } {\n if (!this.changeVariables.has(name) || !this.chart.symbols.some(s => s.name === name)) {\n throw new Error(`${helper}() needs a variable of the chart as first argument`);\n }\n // nothing has changed before the second wakeup, as in Stateflow\n if (!this.previousValues || !this.currentValues) {\n return { changed: false };\n }\n const previous = this.previousValues.get(name);\n const current = this.currentValues.get(name);\n return { changed: !isDeepStrictEqual(previous, current), previous, current };\n }\n\n /**\n * Processes the active states once, see the class description\n *\n * @param input Name of the input which caused the wakeup, null if the step has no event\n * @returns true if a transition was taken\n */\n step(input: string | null): boolean {\n for (const id of this.getActiveChildren(null)) {\n if (this.processState(id, input)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Passes the events since the last call and the changed values of the variables to the host\n */\n publishLive(): void {\n if (this.pendingHistory.length) {\n const entries = this.pendingHistory;\n this.pendingHistory = [];\n this.host.onHistory?.(entries);\n }\n if (!this.host.onValues) {\n return;\n }\n const values = Object.fromEntries(this.chart.symbols.map(s => [s.name, this.sandbox[s.name]]));\n let json;\n try {\n json = JSON.stringify(values);\n } catch {\n // e.g. a circular object in a local: the values are shown as text then\n for (const [name, value] of Object.entries(values)) {\n try {\n JSON.stringify(value);\n } catch {\n values[name] = String(value);\n }\n }\n json = JSON.stringify(values);\n }\n if (json !== this.lastValues) {\n this.lastValues = json;\n this.host.onValues(values);\n }\n }\n\n /**\n * Processes an active state and its active children, see the class description\n *\n * @param id ID of the state\n * @param input Name of the input which caused the wakeup, null for timers\n * @returns true if a transition was taken\n */\n processState(id: string, input: string | null): boolean {\n if (this.takeFirstValid(this.outerTransitions.get(id), input)) {\n return true;\n }\n const state = this.statesById.get(id);\n if (state?.during) {\n this.runAction(state.during, `${state.name}/during`);\n }\n if (this.takeFirstValid(this.innerTransitions.get(id), input)) {\n return true;\n }\n for (const child of this.getActiveChildren(id)) {\n if (this.processState(child, input)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @param parent null for the top level\n */\n getActiveChildren(parent: string | null): string[] {\n const children = new Set(this.structure.getChildren(parent).map(s => s.id));\n return this.activeIds.filter(id => children.has(id));\n }\n\n /**\n * Takes the first transition whose event and condition match\n *\n * @param transitions The transitions to check, sorted\n * @param input Name of the input which caused the wakeup, null for timers\n * @returns true if a transition was taken\n */\n takeFirstValid(transitions: CheckedTransition[] | undefined, input: string | null): boolean {\n for (const transition of transitions || []) {\n if (transition.event && transition.event !== input) {\n continue;\n }\n if (transition.afterMs !== undefined && !this.isExpired(transition)) {\n continue;\n }\n if (transition.condition && !this.run(transition.condition, `${transition.where}/condition`)) {\n continue;\n }\n this.actor?.send({ type: `T.${transition.id}` });\n // XState has executed the transition synchronously, so the active states are the new ones\n this.pendingHistory.push({\n ts: this.now(),\n kind: \"transition\",\n transition: transition.id,\n from: transition.from,\n to: transition.to,\n // in a super step, all transitions of the wakeup were caused by its input\n trigger: this.wakeupInput,\n cause: this.wakeupCause,\n active: this.activeNames,\n });\n return true;\n }\n return false;\n }\n\n /**\n * @param transition A temporal transition\n * @returns true if its source state is active for at least its delay\n */\n isExpired(transition: CheckedTransition): boolean {\n if (this.expired.has(transition.id)) {\n return true;\n }\n const entered = this.enteredAt.get(transition.source);\n return entered !== undefined && this.now() - entered >= (transition.afterMs as number);\n }\n\n buildMachineConfig(): any {\n const structure = this.structure;\n\n const buildState = (state: ChartState): any => {\n const node: any = {\n id: state.id,\n entry: [\n () => this.onEnter(state.id),\n ...(state.entry ? [() => this.runAction(state.entry, `${state.name}/entry`)] : []),\n ],\n exit: [\n ...(state.exit ? [() => this.runAction(state.exit, `${state.name}/exit`)] : []),\n () => this.onExit(state.id),\n ],\n on: {},\n };\n\n const outer: CheckedTransition[] = [];\n const inner: CheckedTransition[] = [];\n for (const transition of structure.getTransitions(state.id)) {\n const built = this.buildTransition(transition, state);\n if (!built) {\n continue;\n }\n // all transitions are selected by processState(), XState only executes them\n node.on[`T.${transition.id}`] = built.config;\n (built.inner ? inner : outer).push(built.checked);\n }\n this.outerTransitions.set(state.id, outer);\n this.innerTransitions.set(state.id, inner);\n this.temporalTransitions.set(\n state.id,\n [...outer, ...inner].filter(t => t.afterMs !== undefined),\n );\n\n const subStates = structure.getChildren(state.id);\n if (subStates.length) {\n node.initial = structure.getInitialChild(state.id);\n node.states = Object.fromEntries(subStates.map(s => [s.id, buildState(s)]));\n }\n return node;\n };\n\n const topLevel = structure.getChildren(null);\n if (!topLevel.length) {\n throw new Error(\"The chart has no states\");\n }\n return {\n id: `chart_${this.chartId}`,\n initial: structure.getInitialChild(null),\n states: Object.fromEntries(topLevel.map(s => [s.id, buildState(s)])),\n };\n }\n\n /**\n * @param transition The transition\n * @param source Its source state\n */\n buildTransition(\n transition: ChartTransition,\n source: ChartState,\n ): { inner: boolean; config: any; checked: CheckedTransition } | null {\n const target = this.statesById.get(transition.target);\n const where = `${source.name} -> ${target?.name ?? transition.target}`;\n if (!target) {\n this.host.log.warn(`[${this.chart.name}] Transition ${where}: unknown target, ignored`);\n return null;\n }\n\n let label;\n try {\n label = parseTransitionLabel(transition.label);\n } catch (err) {\n this.host.log.error(`[${this.chart.name}] Transition ${where}: ${err.message}, ignored`);\n return null;\n }\n\n const condition = label.condition\n ? this.compile(`(${this.prepareCode(label.condition, \"expression\")})`, `${where}/condition`)\n : null;\n const { inner, reenter } = this.structure.getTransitionKind(transition);\n const config = {\n target: `#${target.id}`,\n reenter,\n actions: label.action ? [() => this.runAction(label.action, `${where}/action`)] : [],\n };\n return {\n inner,\n config,\n checked: {\n id: transition.id,\n source: source.id,\n where,\n from: source.name,\n to: target.name,\n event: label.event,\n afterMs: label.afterMs,\n condition,\n },\n };\n }\n\n /**\n * @param code The code\n * @param where Used in error messages\n */\n compile(code: string, where: string): vm.Script | null {\n try {\n return new vm.Script(code, { filename: `${this.chart.name}/${where}` });\n } catch (err) {\n this.host.log.error(`[${this.chart.name}] ${where}: ${err.message}`);\n return null;\n }\n }\n\n /**\n * @param script The compiled code\n * @param where Used in error messages\n */\n run(script: vm.Script | null, where: string): any {\n if (!script) {\n return undefined;\n }\n try {\n return script.runInContext(this.sandbox, { timeout: SCRIPT_TIMEOUT_MS });\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] ${where}: ${err.message}`);\n return undefined;\n }\n }\n\n /**\n * Executes an action and writes all changed outputs\n *\n * @param code The action\n * @param where Used in error messages\n */\n runAction(code: string | undefined, where: string): void {\n // the block keeps \"let\" and \"const\" declarations local to this action\n this.run(this.compile(`{\\n${this.prepareCode(code, \"statements\")}\\n}`, where), where);\n this.writeChangedOutputs();\n }\n\n writeChangedOutputs(): void {\n for (const symbol of this.chart.symbols) {\n if (symbol.scope !== \"output\" || !symbol.stateId) {\n continue;\n }\n const val = this.sandbox[symbol.name];\n if (val !== this.outputValues.get(symbol.name)) {\n this.outputValues.set(symbol.name, val);\n this.host\n .writeState(symbol.stateId, val)\n .catch(err => this.host.log.warn(`[${this.chart.name}] Cannot write ${symbol.stateId}: ${err}`));\n }\n }\n }\n\n /**\n * @param value XState state value\n */\n publishActiveStates(value: any): void {\n /** all active states, parents before children */\n const ids: string[] = [];\n /** name paths of the active leaf states */\n const names: string[] = [];\n\n const walk = (val: any, path: string[]): void => {\n const keys = typeof val === \"string\" ? [val] : Object.keys(val || {});\n for (const key of keys) {\n const name = [...path, this.statesById.get(key)?.name ?? key];\n ids.push(key);\n if (typeof val === \"string\" || !val[key] || !Object.keys(val[key]).length) {\n names.push(name.join(\".\"));\n } else {\n walk(val[key], name);\n }\n }\n };\n walk(value, []);\n\n if (ids.join() !== this.activeIds.join()) {\n this.activeIds = ids;\n this.activeNames = names.join(\", \");\n this.host.onActiveChange({ names: this.activeNames, ids });\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAmB;AACnB,uBAAkC;AAClC,qBAAe;AACf,qBAAoB;AAEpB,oBAA2C;AAE3C,2BAA8B;AAC9B,yBAAsD;AAEtD,6BAA+B;AAC/B,8BAAqE;AAIrE,MAAM,oBAAoB;AAG1B,MAAM,iBAAiB,KAAK,KAAK;AAGjC,MAAM,oBAAoB;AAuBnB,SAAS,aAAa,OAAsB;AAC/C,QAAM,QAAQ;AAAA,IACV,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA;AAAA,IAEf,QAAQ,MAAM,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,OAAO,IAAI,QAAQ,IAAI,SAAS,IAAI,GAAG,MAAM,MAAM,KAAK;AAAA,IAClG,aAAa,MAAM,YAAY;AAAA,MAC3B,CAAC;AAAA,QACG,cAAc;AAAA,QACd,cAAc;AAAA,QACd,cAAc;AAAA,QACd,cAAc;AAAA,QACd,SAAS;AAAA,QACT,GAAG;AAAA,MACP,MAAM;AAAA,IACV;AAAA,IACA,YAAY,MAAM,aAAa,CAAC,GAAG,IAAI,QAAM,GAAG,IAAI;AAAA,EACxD;AACA,SAAO,mBAAAA,QAAO,WAAW,MAAM,EAAE,OAAO,KAAK,UAAU,KAAK,CAAC,EAAE,OAAO,KAAK;AAC/E;AAkGO,MAAM,aAAa;AAAA,EAkDtB,YACa,SACA,OACA,MACX;AAHW;AACA;AACA;AAET,SAAK,YAAY,IAAI,sCAAe,KAAK;AACzC,SAAK,aAAa,KAAK,UAAU;AACjC,SAAK,UAAU,eAAAC,QAAG,cAAc,KAAK,cAAc,CAAC;AACpD,SAAK,OAAO,aAAa,KAAK;AAC9B,SAAK,eAAe;AAAA,EACxB;AAAA,EA3DS;AAAA,EACA;AAAA;AAAA,EAEA,gBAAgB,oBAAI,IAAoB;AAAA;AAAA,EAExC;AAAA;AAAA,EAEA,eAAe,oBAAI,IAAiB;AAAA;AAAA,EAEpC,mBAAmB,oBAAI,IAAiC;AAAA;AAAA,EAExD,mBAAmB,oBAAI,IAAiC;AAAA;AAAA,EAExD,sBAAsB,oBAAI,IAAiC;AAAA;AAAA,EAEpE,YAAsB,CAAC;AAAA;AAAA,EAEd,YAAY,oBAAI,IAAoB;AAAA;AAAA,EAEpC,SAAS,oBAAI,IAA2C;AAAA;AAAA,EAExD,UAAU,oBAAI,IAAY;AAAA;AAAA,EAE1B,iBAAiB,oBAAI,IAA4B;AAAA;AAAA,EAE1D,gBAAgB;AAAA;AAAA,EAEhB,cAAc;AAAA;AAAA,EAEd,iBAAiC,CAAC;AAAA;AAAA,EAElC,aAAa;AAAA;AAAA,EAEb,cAA2B;AAAA;AAAA,EAE3B,cAA6B;AAAA;AAAA,EAEpB,eAAe,oBAAI,IAAoB;AAAA;AAAA,EAEvC,kBAAkB,oBAAI,IAAY;AAAA;AAAA,EAE3C,iBAA0C;AAAA;AAAA,EAE1C,gBAAyC;AAAA,EAChC;AAAA,EACT,QAAyB;AAAA;AAAA,EAEzB,MAAM,MAAc,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA,EAiB7B,iBAAuB;AACnB,eAAW,SAAS,KAAK,MAAM,QAAQ;AACnC,iBAAW,QAAQ,CAAC,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,GAAG;AACxD,aAAK,YAAY,MAAM,YAAY;AAAA,MACvC;AAAA,IACJ;AACA,eAAW,cAAc,KAAK,MAAM,aAAa;AAC7C,UAAI;AACA,cAAM,YAAQ,yCAAqB,WAAW,KAAK;AACnD,aAAK,YAAY,MAAM,WAAW,YAAY;AAC9C,aAAK,YAAY,MAAM,QAAQ,YAAY;AAAA,MAC/C,QAAQ;AAAA,MAER;AAAA,IACJ;AACA,eAAW,MAAM,KAAK,MAAM,aAAa,CAAC,GAAG;AACzC,WAAK,YAAY,GAAG,MAAM,YAAY;AAAA,IAC1C;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,MAA0B,MAAwB;AAC1D,QAAI,CAAC,MAAM;AACP,aAAO;AAAA,IACX;AACA,UAAM,MAAM,GAAG,IAAI,IAAI,IAAI;AAC3B,QAAI,WAAW,KAAK,aAAa,IAAI,GAAG;AACxC,QAAI,aAAa,QAAW;AACxB,YAAM,aAAS,8CAAqB,MAAM,IAAI;AAC9C,iBAAW,OAAO;AAClB,iBAAW,QAAQ,OAAO,OAAO;AAC7B,aAAK,gBAAgB,IAAI,IAAI;AAAA,MACjC;AACA,WAAK,aAAa,IAAI,KAAK,QAAQ;AAAA,IACvC;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAA0B;AAC1B,WAAO,KAAK,MAAM,QAAQ,OAAO,OAAK,EAAE,UAAU,WAAW,EAAE,OAAO,EAAE,IAAI,OAAK,EAAE,OAAiB;AAAA,EACxG;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,MAAM,UAAiC,CAAC,GAAkB;AAC5D,SAAK,YAAY;AACjB,eAAW,UAAU,KAAK,MAAM,SAAS;AACrC,UAAI,OAAO,UAAU,SAAS;AAE1B,aAAK,QAAQ,OAAO,IAAI,IAAI,gBAAgB,OAAO,OAAO;AAAA,MAC9D,WAAW,OAAO,SAAS;AACvB,cAAM,MAAM,MAAM,KAAK,KAAK,UAAU,OAAO,OAAO;AACpD,aAAK,QAAQ,OAAO,IAAI,IAAI;AAC5B,YAAI,OAAO,UAAU,UAAU;AAC3B,eAAK,aAAa,IAAI,OAAO,MAAM,GAAG;AAAA,QAC1C;AAAA,MACJ;AAAA,IACJ;AAGA,eAAW,MAAM,KAAK,MAAM,aAAa,CAAC,GAAG;AACzC,YAAM,QAAQ,sBAAkB,yCAAgB,GAAG,IAAI,EAClD,IAAI,OAAK,EAAE,IAAI,EACf,KAAK,IAAI,CAAC;AACf,WAAK,IAAI,KAAK,QAAQ,KAAK,YAAY,GAAG,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK;AAAA,IAChF;AACA,SAAK,oBAAoB;AAEzB,UAAM,cAAU,6BAAc,KAAK,mBAAmB,CAAC;AACvD,UAAM,YAAY,QAAQ,WAAW,KAAK,MAAM,iBAAiB,QAAQ,MAAM,KAAK,cAAc,IAAI;AACtG,QAAI,WAAW;AACf,QAAI,WAAW;AACX,UAAI;AACA,aAAK,QAAQ,SAAS,SAAS;AAC/B,mBAAW;AACX,aAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,8CAA8C;AAAA,MACxF,SAAS,KAAK;AACV,aAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,8CAA8C,IAAI,OAAO,EAAE;AACjG,aAAK,KAAK;AACV,aAAK,WAAW,OAAO;AAAA,MAC3B;AAAA,IACJ,OAAO;AACH,WAAK,WAAW,OAAO;AAAA,IAC3B;AACA,SAAK,eAAe,KAAK,EAAE,IAAI,KAAK,IAAI,GAAG,MAAM,SAAS,UAAU,QAAQ,KAAK,YAAY,CAAC;AAG9F,SAAK,OAAO,MAAM,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,SAAgC;AACvC,SAAK,YAAY,CAAC;AAClB,SAAK,UAAU,MAAM;AACrB,SAAK,YAAQ,2BAAY,OAAO;AAChC,SAAK,UAAU;AACf,SAAK,MAAM,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAQ,SAA0B,WAAiC;AAC/D,eAAW,UAAU,KAAK,MAAM,SAAS;AACrC,UAAI,OAAO,UAAU,WAAW,OAAO,QAAQ,UAAU,QAAQ;AAC7D,aAAK,QAAQ,OAAO,IAAI,IAAI,UAAU,OAAO,OAAO,IAAI;AAAA,MAC5D;AAAA,IACJ;AACA,SAAK,YAAQ,2BAAY,SAAS,EAAE,UAAU,UAAU,QAAQ,CAAC;AACjE,SAAK,UAAU;AACf,SAAK,MAAM,MAAM;AACjB,SAAK,oBAAoB,KAAK,MAAM,YAAY,EAAE,KAAK;AACvD,eAAW,MAAM,KAAK,WAAW;AAC7B,WAAK,UAAU,IAAI,IAAI,UAAU,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC;AAC1D,WAAK,YAAY,EAAE;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,YAAkB;AACd,SAAK,OAAO,UAAU;AAAA,MAClB,MAAM,cAAY,KAAK,oBAAoB,SAAS,KAAK;AAAA,MACzD,OAAO,SAAO,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAC3E,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgD;AAClD,QAAI;AACJ,QAAI;AACA,kBAAY,MAAM,KAAK,KAAK,gBAAgB;AAAA,IAChD,SAAS,KAAK;AACV,WAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,mCAAmC,IAAI,OAAO,EAAE;AACtF,aAAO;AAAA,IACX;AACA,QAAI,CAAC,WAAW,WAAW,UAAU,YAAY,mBAAmB;AAChE,aAAO;AAAA,IACX;AACA,QAAI,UAAU,SAAS,KAAK,MAAM;AAC9B,WAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,wDAAwD;AAC9F,aAAO;AAAA,IACX;AACA,WAAO,EAAE,GAAG,WAAW,SAAS,UAAU,WAAW,CAAC,GAAG,QAAQ,UAAU,UAAU,CAAC,EAAE;AAAA,EAC5F;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACZ,QAAI,CAAC,KAAK,SAAS,CAAC,KAAK,KAAK,SAAS;AACnC;AAAA,IACJ;AACA,UAAM,OAAuB;AAAA,MACzB,SAAS;AAAA,MACT,MAAM,KAAK;AAAA,MACX,SAAS,KAAK,MAAM,qBAAqB;AAAA,MACzC,SAAS,OAAO,YAAY,KAAK,SAAS;AAAA,MAC1C,QAAQ,OAAO;AAAA,QACX,KAAK,MAAM,QAAQ,OAAO,OAAK,EAAE,UAAU,OAAO,EAAE,IAAI,OAAK,CAAC,EAAE,MAAM,KAAK,QAAQ,EAAE,IAAI,CAAC,CAAC;AAAA,MAC/F;AAAA,IACJ;AACA,QAAI;AACJ,QAAI;AACA,aAAO,KAAK,UAAU,IAAI;AAAA,IAC9B,SAAS,KAAK;AACV,WAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,6BAA6B,IAAI,OAAO,EAAE;AAChF;AAAA,IACJ;AACA,QAAI,SAAS,KAAK,eAAe;AAC7B,WAAK,gBAAgB;AACrB,WAAK,KAAK,QAAQ,IAAI;AAAA,IAC1B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ,IAAkB;AACtB,SAAK,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC;AACjC,SAAK,YAAY,EAAE;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,IAAkB;AACrB,SAAK,UAAU,OAAO,EAAE;AACxB,eAAW,SAAS,KAAK,OAAO,IAAI,EAAE,KAAK,CAAC,GAAG;AAC3C,mBAAa,MAAM,MAAM;AAAA,IAC7B;AACA,SAAK,OAAO,OAAO,EAAE;AACrB,eAAW,cAAc,KAAK,oBAAoB,IAAI,EAAE,KAAK,CAAC,GAAG;AAC7D,WAAK,QAAQ,OAAO,WAAW,EAAE;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,IAAkB;AAC1B,UAAM,UAAU,KAAK,UAAU,IAAI,EAAE,KAAK,KAAK,IAAI;AACnD,UAAM,SAAwC,CAAC;AAC/C,eAAW,cAAc,KAAK,oBAAoB,IAAI,EAAE,KAAK,CAAC,GAAG;AAC7D,YAAM,QAAqC,CAAC;AAC5C,YAAM,MAAM,UAAW,WAAW;AAClC,YAAM,OAAO,MAAY;AACrB,cAAM,YAAY,MAAM,KAAK,IAAI;AACjC,cAAM,SAAS;AAAA,UACX,MAAM;AACF,gBAAI,MAAM,KAAK,IAAI,IAAI,KAAK,YAAY,gBAAgB;AACpD,mBAAK;AACL;AAAA,YACJ;AACA,iBAAK,QAAQ,IAAI,WAAW,EAAE;AAC9B,iBAAK,OAAO,IAAI;AAAA,UACpB;AAAA,UACA,KAAK,IAAI,KAAK,IAAI,WAAW,CAAC,GAAG,cAAc;AAAA,QACnD;AAAA,MACJ;AACA,WAAK;AACL,aAAO,KAAK,KAAK;AAAA,IACrB;AACA,SAAK,OAAO,IAAI,IAAI,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAChB,eAAW,EAAE,MAAM,IAAI,OAAO,WAAW,SAAK,uCAAc,KAAK,KAAK,GAAG;AACrE,UAAI;AACJ,UAAI,SAAS,SAAS;AAClB,gBAAQ,GAAG,KAAK,WAAW,IAAI,EAAE,GAAG,QAAQ,EAAE,IAAI,KAAK;AAAA,MAC3D,WAAW,SAAS,YAAY;AAC5B,cAAM,KAAK,KAAK,MAAM,WAAW,KAAK,OAAK,EAAE,OAAO,EAAE;AACtD,gBAAQ,sBAAkB,yCAAgB,IAAI,IAAI,EAC7C,IAAI,OAAK,EAAE,IAAI,EACf,KAAK,IAAI,CAAC;AAAA,MACnB,OAAO;AACH,cAAM,aAAa,KAAK,MAAM,YAAY,KAAK,OAAK,EAAE,OAAO,EAAE;AAC/D,cAAM,SAAS,KAAK,WAAW,IAAI,YAAY,UAAU,EAAE,GAAG;AAC9D,cAAM,SAAS,KAAK,WAAW,IAAI,YAAY,UAAU,EAAE,GAAG;AAC9D,gBAAQ,cAAc,MAAM,OAAO,MAAM;AAAA,MAC7C;AACA,YAAM,MAAM,WAAW,aAAa,UAAU,KAAK,KAAK,IAAI,QAAQ,KAAK,KAAK,IAAI;AAClF,UAAI,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,WAAW,OAAO,EAAE;AAAA,IAC9D;AAAA,EACJ;AAAA,EAEA,OAAa;AACT,SAAK,OAAO,KAAK;AACjB,SAAK,QAAQ;AACb,eAAW,UAAU,KAAK,OAAO,OAAO,GAAG;AACvC,iBAAW,SAAS,QAAQ;AACxB,qBAAa,MAAM,MAAM;AAAA,MAC7B;AAAA,IACJ;AACA,SAAK,OAAO,MAAM;AAClB,SAAK,QAAQ,MAAM;AACnB,eAAW,SAAS,KAAK,eAAe,OAAO,GAAG;AAC9C,mBAAa,KAAK;AAAA,IACtB;AACA,SAAK,eAAe,MAAM;AAC1B,eAAW,SAAS,KAAK,eAAe;AACpC,mBAAa,KAAK;AAAA,IACtB;AACA,SAAK,cAAc,MAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAyD;AACrD,UAAM,SAAS,IAAI,KAAK,MAAM,IAAI;AAClC,UAAM,QAAQ,CAAC,IAAY,OAAY,QACnC,KAAK,KACA,WAAW,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,EACnC,MAAM,SAAO,KAAK,KAAK,IAAI,KAAK,GAAG,MAAM,iBAAiB,EAAE,KAAK,GAAG,EAAE,CAAC;AAChF,WAAO;AAAA,MACH,KAAK,CAAC,SAAiB,QAAQ,WAAW;AACtC,cAAM,SAAmB,CAAC,SAAS,QAAQ,QAAQ,OAAO,EAAE,SAAS,KAAK,IACnE,QACD;AACN,aAAK,KAAK,IAAI,MAAM,EAAE,GAAG,MAAM,IAAI,OAAO,EAAE;AAAA,MAChD;AAAA,MACA,UAAU,CAAC,IAAY,OAAY,MAAM,UAAU;AAC/C,aAAK,MAAM,IAAI,OAAO,GAAG;AAAA,MAC7B;AAAA,MACA,iBAAiB,CAAC,IAAY,OAAY,SAAiB,MAAM,UAAU;AACvE,cAAM,QAAQ;AAAA,UACV,MAAM;AACF,iBAAK,cAAc,OAAO,KAAK;AAC/B,iBAAK,MAAM,IAAI,OAAO,GAAG;AAAA,UAC7B;AAAA,UACA,KAAK,IAAI,KAAK,IAAI,OAAO,OAAO,KAAK,GAAG,CAAC,GAAG,cAAc;AAAA,QAC9D;AACA,aAAK,cAAc,IAAI,KAAK;AAAA,MAChC;AAAA,MACA,QAAQ,CAAC,UAAkB,SAAiB,YAAiB;AACzD,YAAI,CAAC,KAAK,KAAK,QAAQ;AACnB,gBAAM,IAAI,MAAM,2BAA2B;AAAA,QAC/C;AACA,aAAK,KAAK,OAAO,OAAO,QAAQ,GAAG,OAAO,OAAO,GAAG,OAAO;AAAA,MAC/D;AAAA,MACA,eAAe,CAAC,OAAe,YAAgB,oCAAc,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,MAC7F,WAAW,MAAM;AACb,cAAM,MAAM,IAAI,KAAK,KAAK,IAAI,CAAC;AAC/B,cAAM,EAAE,SAAS,QAAQ,SAAS,IAAI,KAAK,YAAY,GAAG;AAE1D,YAAI,CAAC,WAAW,CAAC,QAAQ;AACrB,iBAAO,CAAC,CAAC;AAAA,QACb;AACA,eAAO,OAAO,WAAW,MAAM;AAAA,MACnC;AAAA,MACA,WAAW,CAAC,MAAc,gBAAgB,MAAM;AAC5C,cAAM,QAAQ,KAAK,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;AACnD,cAAM,OAAO,MAAM,IAAI;AACvB,YAAI,EAAE,gBAAgB,OAAO;AAEzB,gBAAM,QAAQ,QAAQ,SAAS,SAAS,cAAc,SAAS;AAC/D,gBAAM,IAAI;AAAA,YACN,QACM,gBAAgB,IAAI,mDACpB,wBAAwB,IAAI;AAAA,UACtC;AAAA,QACJ;AACA,eAAO,IAAI,KAAK,KAAK,QAAQ,KAAK,OAAO,aAAa,KAAK,KAAK,GAAM;AAAA,MAC1E;AAAA,MACA,YAAY,CAAC,SAAiB,KAAK,UAAU,MAAM,YAAY,EAAE;AAAA,MACjE,gBAAgB,CAAC,MAAc,UAAe;AAC1C,cAAM,EAAE,SAAS,SAAS,IAAI,KAAK,UAAU,MAAM,gBAAgB;AACnE,eAAO,eAAW,oCAAkB,UAAU,KAAK;AAAA,MACvD;AAAA,MACA,cAAc,CAAC,MAAc,UAAe;AACxC,cAAM,EAAE,SAAS,QAAQ,IAAI,KAAK,UAAU,MAAM,cAAc;AAChE,eAAO,eAAW,oCAAkB,SAAS,KAAK;AAAA,MACtD;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,MAAsB;AAC9B,UAAM,WAAW,KAAK,KAAK,cAAc;AACzC,QAAI,CAAC,UAAU;AACX,YAAM,IAAI,MAAM,6EAA6E;AAAA,IACjG;AACA,WAAO,eAAAC,QAAQ,SAAS,MAAM,SAAS,UAAU,SAAS,SAAS;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAY,SAAiB,KAAU,UAA6B,CAAC,GAAS;AAC1E,QAAI,CAAC,KAAK,OAAO;AACb;AAAA,IACJ;AACA,eAAW,UAAU,KAAK,MAAM,SAAS;AACrC,UAAI,OAAO,UAAU,WAAW,OAAO,YAAY,SAAS;AACxD;AAAA,MACJ;AAEA,UAAK,OAAO,QAAQ,SAAS,QAAQ,QAAQ,QAAU,OAAO,QAAQ,aAAa,QAAQ,QAAQ,OAAQ;AACvG;AAAA,MACJ;AACA,YAAM,aAAa,OAAO,cAAc;AACxC,UAAI,aAAa,GAAG;AAEhB,qBAAa,KAAK,eAAe,IAAI,OAAO,IAAI,CAAC;AACjD,aAAK,eAAe;AAAA,UAChB,OAAO;AAAA,UACP,WAAW,MAAM;AACb,iBAAK,eAAe,OAAO,OAAO,IAAI;AACtC,iBAAK,WAAW,QAAQ,GAAG;AAAA,UAC/B,GAAG,UAAU;AAAA,QACjB;AAAA,MACJ,OAAO;AACH,aAAK,WAAW,QAAQ,GAAG;AAAA,MAC/B;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,QAAqB,KAAgB;AAC5C,QAAI,OAAO,YAAY,YAAY,QAAQ,KAAK,QAAQ,OAAO,IAAI,GAAG;AAClE;AAAA,IACJ;AACA,SAAK,QAAQ,OAAO,IAAI,IAAI;AAC5B,SAAK,OAAO,OAAO,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,OAAsB,QAAqB,UAAU,OAAO,UAAU,SAAe;AACxF,QAAI,CAAC,KAAK,OAAO;AACb;AAAA,IACJ;AACA,SAAK,cAAc;AACnB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,QAAI,CAAC,KAAK,MAAM,WAAW;AACvB,WAAK,KAAK,KAAK;AAAA,IACnB,OAAO;AAGH,UAAI,QAAQ;AACZ,UAAI,YAAY;AAChB,aAAO,QAAQ,sCAAmB,KAAK,KAAK,SAAS,GAAG;AACpD;AACA,oBAAY;AAAA,MAChB;AACA,UAAI,SAAS,oCAAiB;AAC1B,aAAK,KAAK,IAAI;AAAA,UACV,IAAI,KAAK,MAAM,IAAI,mBAAmB,kCAAe;AAAA,QACzD;AAAA,MACJ;AAAA,IACJ;AAEA,SAAK,oBAAoB;AACzB,SAAK,QAAQ;AACb,SAAK,YAAY;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAuB;AACnB,QAAI,CAAC,KAAK,gBAAgB,MAAM;AAC5B;AAAA,IACJ;AACA,SAAK,iBAAiB,KAAK;AAC3B,SAAK,gBAAgB,oBAAI,IAAI;AAC7B,eAAW,QAAQ,KAAK,iBAAiB;AACrC,YAAM,QAAQ,KAAK,QAAQ,IAAI;AAC/B,UAAI;AACJ,UAAI;AAEA,eAAO,gBAAgB,KAAK;AAAA,MAChC,QAAQ;AACJ,eAAO;AAAA,MACX;AACA,WAAK,cAAc,IAAI,MAAM,IAAI;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,MAAc,QAAqE;AACzF,QAAI,CAAC,KAAK,gBAAgB,IAAI,IAAI,KAAK,CAAC,KAAK,MAAM,QAAQ,KAAK,OAAK,EAAE,SAAS,IAAI,GAAG;AACnF,YAAM,IAAI,MAAM,GAAG,MAAM,oDAAoD;AAAA,IACjF;AAEA,QAAI,CAAC,KAAK,kBAAkB,CAAC,KAAK,eAAe;AAC7C,aAAO,EAAE,SAAS,MAAM;AAAA,IAC5B;AACA,UAAM,WAAW,KAAK,eAAe,IAAI,IAAI;AAC7C,UAAM,UAAU,KAAK,cAAc,IAAI,IAAI;AAC3C,WAAO,EAAE,SAAS,KAAC,oCAAkB,UAAU,OAAO,GAAG,UAAU,QAAQ;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,OAA+B;AAChC,eAAW,MAAM,KAAK,kBAAkB,IAAI,GAAG;AAC3C,UAAI,KAAK,aAAa,IAAI,KAAK,GAAG;AAC9B,eAAO;AAAA,MACX;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAChB,QAAI,KAAK,eAAe,QAAQ;AAC5B,YAAM,UAAU,KAAK;AACrB,WAAK,iBAAiB,CAAC;AACvB,WAAK,KAAK,YAAY,OAAO;AAAA,IACjC;AACA,QAAI,CAAC,KAAK,KAAK,UAAU;AACrB;AAAA,IACJ;AACA,UAAM,SAAS,OAAO,YAAY,KAAK,MAAM,QAAQ,IAAI,OAAK,CAAC,EAAE,MAAM,KAAK,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7F,QAAI;AACJ,QAAI;AACA,aAAO,KAAK,UAAU,MAAM;AAAA,IAChC,QAAQ;AAEJ,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAChD,YAAI;AACA,eAAK,UAAU,KAAK;AAAA,QACxB,QAAQ;AACJ,iBAAO,IAAI,IAAI,OAAO,KAAK;AAAA,QAC/B;AAAA,MACJ;AACA,aAAO,KAAK,UAAU,MAAM;AAAA,IAChC;AACA,QAAI,SAAS,KAAK,YAAY;AAC1B,WAAK,aAAa;AAClB,WAAK,KAAK,SAAS,MAAM;AAAA,IAC7B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,IAAY,OAA+B;AACpD,QAAI,KAAK,eAAe,KAAK,iBAAiB,IAAI,EAAE,GAAG,KAAK,GAAG;AAC3D,aAAO;AAAA,IACX;AACA,UAAM,QAAQ,KAAK,WAAW,IAAI,EAAE;AACpC,QAAI,OAAO,QAAQ;AACf,WAAK,UAAU,MAAM,QAAQ,GAAG,MAAM,IAAI,SAAS;AAAA,IACvD;AACA,QAAI,KAAK,eAAe,KAAK,iBAAiB,IAAI,EAAE,GAAG,KAAK,GAAG;AAC3D,aAAO;AAAA,IACX;AACA,eAAW,SAAS,KAAK,kBAAkB,EAAE,GAAG;AAC5C,UAAI,KAAK,aAAa,OAAO,KAAK,GAAG;AACjC,eAAO;AAAA,MACX;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,QAAiC;AAC/C,UAAM,WAAW,IAAI,IAAI,KAAK,UAAU,YAAY,MAAM,EAAE,IAAI,OAAK,EAAE,EAAE,CAAC;AAC1E,WAAO,KAAK,UAAU,OAAO,QAAM,SAAS,IAAI,EAAE,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,aAA8C,OAA+B;AACxF,eAAW,cAAc,eAAe,CAAC,GAAG;AACxC,UAAI,WAAW,SAAS,WAAW,UAAU,OAAO;AAChD;AAAA,MACJ;AACA,UAAI,WAAW,YAAY,UAAa,CAAC,KAAK,UAAU,UAAU,GAAG;AACjE;AAAA,MACJ;AACA,UAAI,WAAW,aAAa,CAAC,KAAK,IAAI,WAAW,WAAW,GAAG,WAAW,KAAK,YAAY,GAAG;AAC1F;AAAA,MACJ;AACA,WAAK,OAAO,KAAK,EAAE,MAAM,KAAK,WAAW,EAAE,GAAG,CAAC;AAE/C,WAAK,eAAe,KAAK;AAAA,QACrB,IAAI,KAAK,IAAI;AAAA,QACb,MAAM;AAAA,QACN,YAAY,WAAW;AAAA,QACvB,MAAM,WAAW;AAAA,QACjB,IAAI,WAAW;AAAA;AAAA,QAEf,SAAS,KAAK;AAAA,QACd,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,MACjB,CAAC;AACD,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,YAAwC;AAC9C,QAAI,KAAK,QAAQ,IAAI,WAAW,EAAE,GAAG;AACjC,aAAO;AAAA,IACX;AACA,UAAM,UAAU,KAAK,UAAU,IAAI,WAAW,MAAM;AACpD,WAAO,YAAY,UAAa,KAAK,IAAI,IAAI,WAAY,WAAW;AAAA,EACxE;AAAA,EAEA,qBAA0B;AACtB,UAAM,YAAY,KAAK;AAEvB,UAAM,aAAa,CAAC,UAA2B;AAC3C,YAAM,OAAY;AAAA,QACd,IAAI,MAAM;AAAA,QACV,OAAO;AAAA,UACH,MAAM,KAAK,QAAQ,MAAM,EAAE;AAAA,UAC3B,GAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,UAAU,MAAM,OAAO,GAAG,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC;AAAA,QACpF;AAAA,QACA,MAAM;AAAA,UACF,GAAI,MAAM,OAAO,CAAC,MAAM,KAAK,UAAU,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;AAAA,UAC7E,MAAM,KAAK,OAAO,MAAM,EAAE;AAAA,QAC9B;AAAA,QACA,IAAI,CAAC;AAAA,MACT;AAEA,YAAM,QAA6B,CAAC;AACpC,YAAM,QAA6B,CAAC;AACpC,iBAAW,cAAc,UAAU,eAAe,MAAM,EAAE,GAAG;AACzD,cAAM,QAAQ,KAAK,gBAAgB,YAAY,KAAK;AACpD,YAAI,CAAC,OAAO;AACR;AAAA,QACJ;AAEA,aAAK,GAAG,KAAK,WAAW,EAAE,EAAE,IAAI,MAAM;AACtC,SAAC,MAAM,QAAQ,QAAQ,OAAO,KAAK,MAAM,OAAO;AAAA,MACpD;AACA,WAAK,iBAAiB,IAAI,MAAM,IAAI,KAAK;AACzC,WAAK,iBAAiB,IAAI,MAAM,IAAI,KAAK;AACzC,WAAK,oBAAoB;AAAA,QACrB,MAAM;AAAA,QACN,CAAC,GAAG,OAAO,GAAG,KAAK,EAAE,OAAO,OAAK,EAAE,YAAY,MAAS;AAAA,MAC5D;AAEA,YAAM,YAAY,UAAU,YAAY,MAAM,EAAE;AAChD,UAAI,UAAU,QAAQ;AAClB,aAAK,UAAU,UAAU,gBAAgB,MAAM,EAAE;AACjD,aAAK,SAAS,OAAO,YAAY,UAAU,IAAI,OAAK,CAAC,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AAAA,MAC9E;AACA,aAAO;AAAA,IACX;AAEA,UAAM,WAAW,UAAU,YAAY,IAAI;AAC3C,QAAI,CAAC,SAAS,QAAQ;AAClB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC7C;AACA,WAAO;AAAA,MACH,IAAI,SAAS,KAAK,OAAO;AAAA,MACzB,SAAS,UAAU,gBAAgB,IAAI;AAAA,MACvC,QAAQ,OAAO,YAAY,SAAS,IAAI,OAAK,CAAC,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AAAA,IACvE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBACI,YACA,QACkE;AAClE,UAAM,SAAS,KAAK,WAAW,IAAI,WAAW,MAAM;AACpD,UAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,QAAQ,QAAQ,WAAW,MAAM;AACpE,QAAI,CAAC,QAAQ;AACT,WAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,gBAAgB,KAAK,2BAA2B;AACtF,aAAO;AAAA,IACX;AAEA,QAAI;AACJ,QAAI;AACA,kBAAQ,yCAAqB,WAAW,KAAK;AAAA,IACjD,SAAS,KAAK;AACV,WAAK,KAAK,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,gBAAgB,KAAK,KAAK,IAAI,OAAO,WAAW;AACvF,aAAO;AAAA,IACX;AAEA,UAAM,YAAY,MAAM,YAClB,KAAK,QAAQ,IAAI,KAAK,YAAY,MAAM,WAAW,YAAY,CAAC,KAAK,GAAG,KAAK,YAAY,IACzF;AACN,UAAM,EAAE,OAAO,QAAQ,IAAI,KAAK,UAAU,kBAAkB,UAAU;AACtE,UAAM,SAAS;AAAA,MACX,QAAQ,IAAI,OAAO,EAAE;AAAA,MACrB;AAAA,MACA,SAAS,MAAM,SAAS,CAAC,MAAM,KAAK,UAAU,MAAM,QAAQ,GAAG,KAAK,SAAS,CAAC,IAAI,CAAC;AAAA,IACvF;AACA,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA,SAAS;AAAA,QACL,IAAI,WAAW;AAAA,QACf,QAAQ,OAAO;AAAA,QACf;AAAA,QACA,MAAM,OAAO;AAAA,QACb,IAAI,OAAO;AAAA,QACX,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,QACf;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,MAAc,OAAiC;AACnD,QAAI;AACA,aAAO,IAAI,eAAAD,QAAG,OAAO,MAAM,EAAE,UAAU,GAAG,KAAK,MAAM,IAAI,IAAI,KAAK,GAAG,CAAC;AAAA,IAC1E,SAAS,KAAK;AACV,WAAK,KAAK,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,OAAO,EAAE;AACnE,aAAO;AAAA,IACX;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,QAA0B,OAAoB;AAC9C,QAAI,CAAC,QAAQ;AACT,aAAO;AAAA,IACX;AACA,QAAI;AACA,aAAO,OAAO,aAAa,KAAK,SAAS,EAAE,SAAS,kBAAkB,CAAC;AAAA,IAC3E,SAAS,KAAK;AACV,WAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,OAAO,EAAE;AAClE,aAAO;AAAA,IACX;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,MAA0B,OAAqB;AAErD,SAAK,IAAI,KAAK,QAAQ;AAAA,EAAM,KAAK,YAAY,MAAM,YAAY,CAAC;AAAA,IAAO,KAAK,GAAG,KAAK;AACpF,SAAK,oBAAoB;AAAA,EAC7B;AAAA,EAEA,sBAA4B;AACxB,eAAW,UAAU,KAAK,MAAM,SAAS;AACrC,UAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS;AAC9C;AAAA,MACJ;AACA,YAAM,MAAM,KAAK,QAAQ,OAAO,IAAI;AACpC,UAAI,QAAQ,KAAK,aAAa,IAAI,OAAO,IAAI,GAAG;AAC5C,aAAK,aAAa,IAAI,OAAO,MAAM,GAAG;AACtC,aAAK,KACA,WAAW,OAAO,SAAS,GAAG,EAC9B,MAAM,SAAO,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,kBAAkB,OAAO,OAAO,KAAK,GAAG,EAAE,CAAC;AAAA,MACvG;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,OAAkB;AAElC,UAAM,MAAgB,CAAC;AAEvB,UAAM,QAAkB,CAAC;AAEzB,UAAM,OAAO,CAAC,KAAU,SAAyB;AAC7C,YAAM,OAAO,OAAO,QAAQ,WAAW,CAAC,GAAG,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC;AACpE,iBAAW,OAAO,MAAM;AACpB,cAAM,OAAO,CAAC,GAAG,MAAM,KAAK,WAAW,IAAI,GAAG,GAAG,QAAQ,GAAG;AAC5D,YAAI,KAAK,GAAG;AACZ,YAAI,OAAO,QAAQ,YAAY,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,KAAK,IAAI,GAAG,CAAC,EAAE,QAAQ;AACvE,gBAAM,KAAK,KAAK,KAAK,GAAG,CAAC;AAAA,QAC7B,OAAO;AACH,eAAK,IAAI,GAAG,GAAG,IAAI;AAAA,QACvB;AAAA,MACJ;AAAA,IACJ;AACA,SAAK,OAAO,CAAC,CAAC;AAEd,QAAI,IAAI,KAAK,MAAM,KAAK,UAAU,KAAK,GAAG;AACtC,WAAK,YAAY;AACjB,WAAK,cAAc,MAAM,KAAK,IAAI;AAClC,WAAK,KAAK,eAAe,EAAE,OAAO,KAAK,aAAa,IAAI,CAAC;AAAA,IAC7D;AAAA,EACJ;AACJ;",
6
+ "names": ["crypto", "vm", "SunCalc"]
7
+ }
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var chart_structure_exports = {};
20
+ __export(chart_structure_exports, {
21
+ ChartStructure: () => ChartStructure
22
+ });
23
+ module.exports = __toCommonJS(chart_structure_exports);
24
+ class ChartStructure {
25
+ constructor(chart) {
26
+ this.chart = chart;
27
+ this.statesById = new Map(chart.states.map((s) => [s.id, s]));
28
+ for (const state of chart.states) {
29
+ const parent = state.parent && this.statesById.has(state.parent) ? state.parent : "";
30
+ this.childrenByParent.set(parent, [...this.childrenByParent.get(parent) || [], state]);
31
+ }
32
+ for (const transition of chart.transitions) {
33
+ const list = this.transitionsBySource.get(transition.source) || [];
34
+ this.transitionsBySource.set(transition.source, [...list, transition]);
35
+ }
36
+ for (const list of this.transitionsBySource.values()) {
37
+ list.sort((a, b) => (a.priority ?? Number.MAX_SAFE_INTEGER) - (b.priority ?? Number.MAX_SAFE_INTEGER));
38
+ }
39
+ }
40
+ statesById;
41
+ /** children by parent ID, "" for the top level */
42
+ childrenByParent = /* @__PURE__ */ new Map();
43
+ /** transitions by source, sorted by priority */
44
+ transitionsBySource = /* @__PURE__ */ new Map();
45
+ /**
46
+ * @param parentId null for the top level
47
+ */
48
+ getChildren(parentId) {
49
+ return this.childrenByParent.get(parentId || "") || [];
50
+ }
51
+ /**
52
+ * The initial state of a level: the configured one if it is a child of this level, otherwise the first child
53
+ *
54
+ * @param parentId null for the top level
55
+ * @returns undefined if the level has no states
56
+ */
57
+ getInitialChild(parentId) {
58
+ const children = this.getChildren(parentId);
59
+ const configured = parentId ? this.statesById.get(parentId)?.initial : this.chart.initial;
60
+ return children.some((s) => s.id === configured) ? configured : children[0]?.id;
61
+ }
62
+ /**
63
+ * @param stateId ID of the source state
64
+ * @returns the transitions starting at the state, sorted by priority
65
+ */
66
+ getTransitions(stateId) {
67
+ return this.transitionsBySource.get(stateId) || [];
68
+ }
69
+ /**
70
+ * @param ancestorId ID of the possible ancestor
71
+ * @param id ID of the possible descendant
72
+ * @returns true if the state "id" is a (direct or indirect) child of "ancestorId"
73
+ */
74
+ isDescendant(ancestorId, id) {
75
+ let parent = this.statesById.get(id)?.parent;
76
+ for (let i = 0; parent && i < this.statesById.size; i++) {
77
+ if (parent === ancestorId) {
78
+ return true;
79
+ }
80
+ parent = this.statesById.get(parent)?.parent;
81
+ }
82
+ return false;
83
+ }
84
+ /**
85
+ * How a transition is executed
86
+ *
87
+ * @param transition The transition
88
+ */
89
+ getTransitionKind(transition) {
90
+ const { source, target } = transition;
91
+ const toChild = this.isDescendant(source, target);
92
+ const inner = toChild && !transition.reenterParent;
93
+ const reenter = source === target || toChild && !inner || this.isDescendant(target, source);
94
+ return { inner, reenter };
95
+ }
96
+ }
97
+ // Annotate the CommonJS export names for ESM import in node:
98
+ 0 && (module.exports = {
99
+ ChartStructure
100
+ });
101
+ //# sourceMappingURL=chart-structure.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/chart-structure.ts"],
4
+ "sourcesContent": ["/*\n * The structure of a chart (hierarchy, transition order, kind of transitions) as the runtime executes it.\n * Shared by the runtime and the code generator, so the generated code always shows what is executed.\n */\n\nimport type { Chart, ChartState, ChartTransition } from \"./chart-model\";\n\nexport interface TransitionKind {\n /** checked after the during action of the source, the source stays active */\n inner: boolean;\n /** the source state is left and entered again (XState \"reenter\") */\n reenter: boolean;\n}\n\nexport class ChartStructure {\n readonly statesById: Map<string, ChartState>;\n /** children by parent ID, \"\" for the top level */\n readonly childrenByParent = new Map<string, ChartState[]>();\n /** transitions by source, sorted by priority */\n readonly transitionsBySource = new Map<string, ChartTransition[]>();\n\n constructor(readonly chart: Chart) {\n this.statesById = new Map(chart.states.map(s => [s.id, s]));\n for (const state of chart.states) {\n // states with an unknown parent are treated like top level states\n const parent = state.parent && this.statesById.has(state.parent) ? state.parent : \"\";\n this.childrenByParent.set(parent, [...(this.childrenByParent.get(parent) || []), state]);\n }\n for (const transition of chart.transitions) {\n const list = this.transitionsBySource.get(transition.source) || [];\n this.transitionsBySource.set(transition.source, [...list, transition]);\n }\n for (const list of this.transitionsBySource.values()) {\n // the sort is stable: transitions without priority keep their order, after the others\n list.sort((a, b) => (a.priority ?? Number.MAX_SAFE_INTEGER) - (b.priority ?? Number.MAX_SAFE_INTEGER));\n }\n }\n\n /**\n * @param parentId null for the top level\n */\n getChildren(parentId: string | null): ChartState[] {\n return this.childrenByParent.get(parentId || \"\") || [];\n }\n\n /**\n * The initial state of a level: the configured one if it is a child of this level, otherwise the first child\n *\n * @param parentId null for the top level\n * @returns undefined if the level has no states\n */\n getInitialChild(parentId: string | null): string | undefined {\n const children = this.getChildren(parentId);\n const configured = parentId ? this.statesById.get(parentId)?.initial : this.chart.initial;\n return children.some(s => s.id === configured) ? configured : children[0]?.id;\n }\n\n /**\n * @param stateId ID of the source state\n * @returns the transitions starting at the state, sorted by priority\n */\n getTransitions(stateId: string): ChartTransition[] {\n return this.transitionsBySource.get(stateId) || [];\n }\n\n /**\n * @param ancestorId ID of the possible ancestor\n * @param id ID of the possible descendant\n * @returns true if the state \"id\" is a (direct or indirect) child of \"ancestorId\"\n */\n isDescendant(ancestorId: string, id: string): boolean {\n let parent = this.statesById.get(id)?.parent;\n // the counter protects against cycles in invalid charts\n for (let i = 0; parent && i < this.statesById.size; i++) {\n if (parent === ancestorId) {\n return true;\n }\n parent = this.statesById.get(parent)?.parent;\n }\n return false;\n }\n\n /**\n * How a transition is executed\n *\n * @param transition The transition\n */\n getTransitionKind(transition: ChartTransition): TransitionKind {\n const { source, target } = transition;\n const toChild = this.isDescendant(source, target);\n // an inner transition stays in the source state, only its active child is left\n const inner = toChild && !transition.reenterParent;\n // Like Stateflow, the source state is left and entered again by self transitions, by transitions\n // to an own child which should re-enter the parent, and by transitions from a child to its parent.\n // Without \"reenter\", XState does not leave the source state if the target is a child of it.\n const reenter = source === target || (toChild && !inner) || this.isDescendant(target, source);\n return { inner, reenter };\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAcO,MAAM,eAAe;AAAA,EAOxB,YAAqB,OAAc;AAAd;AACjB,SAAK,aAAa,IAAI,IAAI,MAAM,OAAO,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAC1D,eAAW,SAAS,MAAM,QAAQ;AAE9B,YAAM,SAAS,MAAM,UAAU,KAAK,WAAW,IAAI,MAAM,MAAM,IAAI,MAAM,SAAS;AAClF,WAAK,iBAAiB,IAAI,QAAQ,CAAC,GAAI,KAAK,iBAAiB,IAAI,MAAM,KAAK,CAAC,GAAI,KAAK,CAAC;AAAA,IAC3F;AACA,eAAW,cAAc,MAAM,aAAa;AACxC,YAAM,OAAO,KAAK,oBAAoB,IAAI,WAAW,MAAM,KAAK,CAAC;AACjE,WAAK,oBAAoB,IAAI,WAAW,QAAQ,CAAC,GAAG,MAAM,UAAU,CAAC;AAAA,IACzE;AACA,eAAW,QAAQ,KAAK,oBAAoB,OAAO,GAAG;AAElD,WAAK,KAAK,CAAC,GAAG,OAAO,EAAE,YAAY,OAAO,qBAAqB,EAAE,YAAY,OAAO,iBAAiB;AAAA,IACzG;AAAA,EACJ;AAAA,EArBS;AAAA;AAAA,EAEA,mBAAmB,oBAAI,IAA0B;AAAA;AAAA,EAEjD,sBAAsB,oBAAI,IAA+B;AAAA;AAAA;AAAA;AAAA,EAsBlE,YAAY,UAAuC;AAC/C,WAAO,KAAK,iBAAiB,IAAI,YAAY,EAAE,KAAK,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,UAA6C;AACzD,UAAM,WAAW,KAAK,YAAY,QAAQ;AAC1C,UAAM,aAAa,WAAW,KAAK,WAAW,IAAI,QAAQ,GAAG,UAAU,KAAK,MAAM;AAClF,WAAO,SAAS,KAAK,OAAK,EAAE,OAAO,UAAU,IAAI,aAAa,SAAS,CAAC,GAAG;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,SAAoC;AAC/C,WAAO,KAAK,oBAAoB,IAAI,OAAO,KAAK,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,YAAoB,IAAqB;AAClD,QAAI,SAAS,KAAK,WAAW,IAAI,EAAE,GAAG;AAEtC,aAAS,IAAI,GAAG,UAAU,IAAI,KAAK,WAAW,MAAM,KAAK;AACrD,UAAI,WAAW,YAAY;AACvB,eAAO;AAAA,MACX;AACA,eAAS,KAAK,WAAW,IAAI,MAAM,GAAG;AAAA,IAC1C;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAkB,YAA6C;AAC3D,UAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,UAAM,UAAU,KAAK,aAAa,QAAQ,MAAM;AAEhD,UAAM,QAAQ,WAAW,CAAC,WAAW;AAIrC,UAAM,UAAU,WAAW,UAAW,WAAW,CAAC,SAAU,KAAK,aAAa,QAAQ,MAAM;AAC5F,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC5B;AACJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var chart_validation_exports = {};
30
+ __export(chart_validation_exports, {
31
+ GLOBALS: () => GLOBALS,
32
+ getDeclarations: () => getDeclarations,
33
+ getFunctionNames: () => getFunctionNames,
34
+ quoteChangeArguments: () => quoteChangeArguments,
35
+ validateChart: () => validateChart,
36
+ validateCode: () => validateCode,
37
+ validateTransitionLabel: () => validateTransitionLabel
38
+ });
39
+ module.exports = __toCommonJS(chart_validation_exports);
40
+ var acorn = __toESM(require("acorn"));
41
+ var walk = __toESM(require("acorn-walk"));
42
+ var import_chart_helpers = require("./chart-helpers");
43
+ var import_chart_model = require("./chart-model");
44
+ const GLOBALS = /* @__PURE__ */ new Set([
45
+ // the helper functions, e.g. log() and setState()
46
+ ...Object.keys(import_chart_helpers.HELPERS),
47
+ "undefined",
48
+ "NaN",
49
+ "Infinity",
50
+ "Math",
51
+ "Date",
52
+ "JSON",
53
+ "Number",
54
+ "String",
55
+ "Boolean",
56
+ "Array",
57
+ "Object",
58
+ "RegExp",
59
+ "Map",
60
+ "Set",
61
+ "Error",
62
+ "parseInt",
63
+ "parseFloat",
64
+ "isNaN",
65
+ "isFinite",
66
+ "encodeURIComponent",
67
+ "decodeURIComponent"
68
+ ]);
69
+ const STATE_ACTIONS = ["entry", "during", "exit"];
70
+ function createDiagnostic(from, to, severity, key, args = []) {
71
+ return { from, to, severity, key, args, message: (0, import_chart_model.formatMessage)(key, args) };
72
+ }
73
+ function parseCode(code, kind) {
74
+ try {
75
+ if (kind === "statements") {
76
+ return { ast: acorn.parse(code, { ecmaVersion: "latest", sourceType: "script" }) };
77
+ }
78
+ const ast = acorn.parseExpressionAt(code, 0, { ecmaVersion: "latest" });
79
+ const rest = code.substring(ast.end);
80
+ if (rest.trim()) {
81
+ const from = ast.end + rest.length - rest.trimStart().length;
82
+ return { diagnostic: createDiagnostic(from, code.length, "error", 'Unexpected "%s"', [rest.trim()]) };
83
+ }
84
+ return { ast };
85
+ } catch (err) {
86
+ const pos = typeof err.pos === "number" ? Math.min(err.pos, code.length) : 0;
87
+ const message = String(err.message).replace(/\s*\(\d+:\d+\)$/, "");
88
+ const from = pos < code.length ? pos : Math.max(0, code.length - 1);
89
+ const token = /^(\w+|\S)/.exec(code.substring(from));
90
+ const to = Math.min(code.length, from + (token ? token[0].length : 1));
91
+ return { diagnostic: createDiagnostic(from, to, "error", "Syntax error: %s", [message]) };
92
+ }
93
+ }
94
+ function validateCode(code, kind, symbols, offset = 0, functionNames = []) {
95
+ if (!code?.trim()) {
96
+ return [];
97
+ }
98
+ const parsed = parseCode(code, kind);
99
+ if ("diagnostic" in parsed) {
100
+ const d = parsed.diagnostic;
101
+ return [{ ...d, from: d.from + offset, to: d.to + offset }];
102
+ }
103
+ const declared = /* @__PURE__ */ new Set();
104
+ const references = [];
105
+ walk.fullAncestor(parsed.ast, (node, _state, ancestors, type) => {
106
+ if (node.type !== "Identifier") {
107
+ return;
108
+ }
109
+ const parent = ancestors[ancestors.length - 2];
110
+ if (type === "VariablePattern") {
111
+ if (parent?.type === "AssignmentExpression" && parent.left === node) {
112
+ references.push({ node, write: true });
113
+ } else {
114
+ declared.add(node.name);
115
+ }
116
+ } else {
117
+ references.push({ node, write: parent?.type === "UpdateExpression" });
118
+ }
119
+ });
120
+ const inputs = new Set(symbols.filter((s) => s.scope === "input").map((s) => s.name));
121
+ const symbolNames = new Set(symbols.map((s) => s.name));
122
+ const known = /* @__PURE__ */ new Set([...symbolNames, ...functionNames]);
123
+ const diagnostics = [];
124
+ walk.simple(parsed.ast, {
125
+ CallExpression(node) {
126
+ if (node.callee.type !== "Identifier" || !import_chart_helpers.CHANGE_HELPERS.has(node.callee.name)) {
127
+ return;
128
+ }
129
+ const arg = node.arguments[0];
130
+ let valid;
131
+ if (arg?.type === "Identifier") {
132
+ valid = symbolNames.has(arg.name) || !(known.has(arg.name) || declared.has(arg.name) || GLOBALS.has(arg.name));
133
+ } else {
134
+ valid = arg?.type === "Literal" && typeof arg.value === "string" && symbolNames.has(arg.value);
135
+ }
136
+ if (!valid) {
137
+ const { start, end } = arg ?? node;
138
+ diagnostics.push(
139
+ createDiagnostic(
140
+ start + offset,
141
+ end + offset,
142
+ "error",
143
+ "%s() needs a variable of the chart as first argument",
144
+ [node.callee.name]
145
+ )
146
+ );
147
+ }
148
+ }
149
+ });
150
+ for (const { node, write } of references) {
151
+ const from = node.start + offset;
152
+ const to = node.end + offset;
153
+ if (!known.has(node.name) && !declared.has(node.name) && !GLOBALS.has(node.name)) {
154
+ diagnostics.push(createDiagnostic(from, to, "error", 'Unknown variable "%s"', [node.name]));
155
+ } else if (write && inputs.has(node.name) && !declared.has(node.name)) {
156
+ diagnostics.push(
157
+ createDiagnostic(from, to, "warning", 'Input "%s" is overwritten on its next change', [node.name])
158
+ );
159
+ }
160
+ }
161
+ return diagnostics;
162
+ }
163
+ function validateTransitionLabel(label, symbols, functionNames = []) {
164
+ let parsed;
165
+ try {
166
+ parsed = (0, import_chart_model.parseTransitionLabelWithRanges)(label);
167
+ } catch (err) {
168
+ if (err instanceof import_chart_model.LabelSyntaxError) {
169
+ return [createDiagnostic(err.from, err.to, "error", err.key, err.args)];
170
+ }
171
+ throw err;
172
+ }
173
+ const { label: parts, ranges } = parsed;
174
+ const diagnostics = [];
175
+ if (parts.event && ranges.event && !symbols.some((s) => s.scope === "input" && s.name === parts.event)) {
176
+ diagnostics.push(
177
+ createDiagnostic(
178
+ ranges.event.from,
179
+ ranges.event.to,
180
+ "error",
181
+ 'Unknown event "%s", use the name of an input',
182
+ [parts.event]
183
+ )
184
+ );
185
+ }
186
+ if (parts.condition && ranges.condition) {
187
+ diagnostics.push(...validateCode(parts.condition, "expression", symbols, ranges.condition.from, functionNames));
188
+ }
189
+ if (parts.action && ranges.action) {
190
+ diagnostics.push(...validateCode(parts.action, "statements", symbols, ranges.action.from, functionNames));
191
+ }
192
+ return diagnostics;
193
+ }
194
+ function getDeclarations(code) {
195
+ if (!code?.trim()) {
196
+ return [];
197
+ }
198
+ const parsed = parseCode(code, "statements");
199
+ if ("diagnostic" in parsed) {
200
+ return [];
201
+ }
202
+ const signature = (fn, name) => `${name}(${fn.params.map((p) => code.substring(p.start, p.end)).join(", ")})`;
203
+ const declarations = [];
204
+ for (const node of parsed.ast.body) {
205
+ if (node.type === "FunctionDeclaration" && node.id) {
206
+ const { name, start, end } = node.id;
207
+ declarations.push({ name, signature: signature(node, name), from: start, to: end });
208
+ } else if (node.type === "VariableDeclaration") {
209
+ for (const declarator of node.declarations) {
210
+ if (declarator.id.type !== "Identifier") {
211
+ continue;
212
+ }
213
+ const { name, start, end } = declarator.id;
214
+ const init = declarator.init;
215
+ const isFunction = init?.type === "ArrowFunctionExpression" || init?.type === "FunctionExpression";
216
+ declarations.push({ name, signature: isFunction ? signature(init, name) : null, from: start, to: end });
217
+ }
218
+ }
219
+ }
220
+ return declarations;
221
+ }
222
+ function getFunctionNames(chart) {
223
+ return (chart.functions || []).flatMap((fn) => getDeclarations(fn.code).map((d) => d.name));
224
+ }
225
+ function quoteChangeArguments(code, kind) {
226
+ const parsed = code.trim() ? parseCode(code, kind) : null;
227
+ if (!parsed || "diagnostic" in parsed) {
228
+ return { code, names: [] };
229
+ }
230
+ const names = /* @__PURE__ */ new Set();
231
+ const replacements = [];
232
+ walk.simple(parsed.ast, {
233
+ CallExpression(node) {
234
+ const arg = node.arguments[0];
235
+ if (node.callee.type !== "Identifier" || !import_chart_helpers.CHANGE_HELPERS.has(node.callee.name)) {
236
+ return;
237
+ }
238
+ if (arg?.type === "Identifier") {
239
+ replacements.push(arg);
240
+ names.add(arg.name);
241
+ } else if (arg?.type === "Literal" && typeof arg.value === "string") {
242
+ names.add(arg.value);
243
+ }
244
+ }
245
+ });
246
+ let result = code;
247
+ for (const { start, end, name } of replacements.sort((a, b) => b.start - a.start)) {
248
+ result = result.substring(0, start) + JSON.stringify(name) + result.substring(end);
249
+ }
250
+ return { code: result, names: [...names] };
251
+ }
252
+ function validateChart(chart) {
253
+ const functionNames = getFunctionNames(chart);
254
+ const problems = [];
255
+ for (const state of chart.states) {
256
+ for (const field of STATE_ACTIONS) {
257
+ for (const diagnostic of validateCode(state[field], "statements", chart.symbols, 0, functionNames)) {
258
+ problems.push({ kind: "state", id: state.id, field, diagnostic });
259
+ }
260
+ }
261
+ }
262
+ for (const transition of chart.transitions) {
263
+ for (const diagnostic of validateTransitionLabel(transition.label, chart.symbols, functionNames)) {
264
+ problems.push({ kind: "transition", id: transition.id, field: "label", diagnostic });
265
+ }
266
+ }
267
+ const symbolNames = new Set(chart.symbols.map((s) => s.name));
268
+ const seen = /* @__PURE__ */ new Set();
269
+ for (const fn of chart.functions || []) {
270
+ for (const diagnostic of validateCode(fn.code, "statements", chart.symbols, 0, functionNames)) {
271
+ problems.push({ kind: "function", id: fn.id, field: "code", diagnostic });
272
+ }
273
+ for (const { name, from, to } of getDeclarations(fn.code)) {
274
+ let key = null;
275
+ if (seen.has(name)) {
276
+ key = '"%s" is declared in more than one function block';
277
+ } else if (symbolNames.has(name) || GLOBALS.has(name)) {
278
+ key = '"%s" is already the name of a variable';
279
+ }
280
+ if (key) {
281
+ problems.push({
282
+ kind: "function",
283
+ id: fn.id,
284
+ field: "code",
285
+ diagnostic: createDiagnostic(from, to, "error", key, [name])
286
+ });
287
+ }
288
+ seen.add(name);
289
+ }
290
+ }
291
+ return problems;
292
+ }
293
+ // Annotate the CommonJS export names for ESM import in node:
294
+ 0 && (module.exports = {
295
+ GLOBALS,
296
+ getDeclarations,
297
+ getFunctionNames,
298
+ quoteChangeArguments,
299
+ validateChart,
300
+ validateCode,
301
+ validateTransitionLabel
302
+ });
303
+ //# sourceMappingURL=chart-validation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/chart-validation.ts"],
4
+ "sourcesContent": ["/*\n * Checks conditions and actions of a chart: JavaScript syntax, unknown variables and events.\n * Used by the editor (to underline errors) and by the runtime (to log them when a chart starts).\n */\n\nimport * as acorn from \"acorn\";\nimport * as walk from \"acorn-walk\";\nimport { CHANGE_HELPERS, HELPERS } from \"./chart-helpers\";\nimport { LabelSyntaxError, formatMessage, parseTransitionLabelWithRanges } from \"./chart-model\";\nimport type { Chart, ChartSymbol } from \"./chart-model\";\n\n/** Names which can be used in conditions and actions besides the chart variables */\nexport const GLOBALS = new Set([\n // the helper functions, e.g. log() and setState()\n ...Object.keys(HELPERS),\n \"undefined\",\n \"NaN\",\n \"Infinity\",\n \"Math\",\n \"Date\",\n \"JSON\",\n \"Number\",\n \"String\",\n \"Boolean\",\n \"Array\",\n \"Object\",\n \"RegExp\",\n \"Map\",\n \"Set\",\n \"Error\",\n \"parseInt\",\n \"parseFloat\",\n \"isNaN\",\n \"isFinite\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n]);\n\n/** Fields of a state which contain actions */\nconst STATE_ACTIONS = [\"entry\", \"during\", \"exit\"] as const;\n\nexport type CodeKind = \"expression\" | \"statements\";\n\nexport interface Diagnostic {\n /** Position in the checked text */\n from: number;\n to: number;\n severity: \"error\" | \"warning\";\n /** English message */\n message: string;\n /** Message with %s placeholders, used to translate it */\n key: string;\n args: string[];\n}\n\nfunction createDiagnostic(\n from: number,\n to: number,\n severity: \"error\" | \"warning\",\n key: string,\n args: string[] = [],\n): Diagnostic {\n return { from, to, severity, key, args, message: formatMessage(key, args) };\n}\n\n/**\n * Parses JavaScript and converts syntax errors to diagnostics\n *\n * @param code The code to parse\n * @param kind Expression or statements\n */\nfunction parseCode(code: string, kind: CodeKind): { ast: acorn.Node } | { diagnostic: Diagnostic } {\n try {\n if (kind === \"statements\") {\n return { ast: acorn.parse(code, { ecmaVersion: \"latest\", sourceType: \"script\" }) };\n }\n const ast = acorn.parseExpressionAt(code, 0, { ecmaVersion: \"latest\" });\n const rest = code.substring(ast.end);\n if (rest.trim()) {\n const from = ast.end + rest.length - rest.trimStart().length;\n return { diagnostic: createDiagnostic(from, code.length, \"error\", 'Unexpected \"%s\"', [rest.trim()]) };\n }\n return { ast };\n } catch (err) {\n const pos = typeof err.pos === \"number\" ? Math.min(err.pos, code.length) : 0;\n // acorn adds the position \"(line:column)\" to its messages, it is shown by the underline anyway\n const message = String(err.message).replace(/\\s*\\(\\d+:\\d+\\)$/, \"\");\n // underline the token at the error position, or the last character if the code ends unexpectedly\n const from = pos < code.length ? pos : Math.max(0, code.length - 1);\n const token = /^(\\w+|\\S)/.exec(code.substring(from));\n const to = Math.min(code.length, from + (token ? token[0].length : 1));\n return { diagnostic: createDiagnostic(from, to, \"error\", \"Syntax error: %s\", [message]) };\n }\n}\n\n/**\n * Checks a condition or action\n *\n * @param code The code to check\n * @param kind Condition (expression) or action (statements)\n * @param symbols The variables of the chart\n * @param offset Position of the code in the text, added to all positions\n * @param functionNames Names declared in the function blocks of the chart\n */\nexport function validateCode(\n code: string | undefined,\n kind: CodeKind,\n symbols: ChartSymbol[],\n offset = 0,\n functionNames: string[] = [],\n): Diagnostic[] {\n if (!code?.trim()) {\n return [];\n }\n const parsed = parseCode(code, kind);\n if (\"diagnostic\" in parsed) {\n const d = parsed.diagnostic;\n return [{ ...d, from: d.from + offset, to: d.to + offset }];\n }\n\n /** names declared in the code itself (let, const, function parameters, ...) */\n const declared = new Set<string>();\n const references: { node: acorn.Identifier; write: boolean }[] = [];\n walk.fullAncestor(parsed.ast, (node, _state, ancestors, type) => {\n if (node.type !== \"Identifier\") {\n return;\n }\n const parent = ancestors[ancestors.length - 2] as acorn.AnyNode | undefined;\n if (type === \"VariablePattern\") {\n // acorn-walk uses \"VariablePattern\" for declarations and for assignment targets\n if (parent?.type === \"AssignmentExpression\" && parent.left === node) {\n references.push({ node, write: true });\n } else {\n declared.add(node.name);\n }\n } else {\n references.push({ node, write: parent?.type === \"UpdateExpression\" });\n }\n });\n\n const inputs = new Set(symbols.filter(s => s.scope === \"input\").map(s => s.name));\n const symbolNames = new Set(symbols.map(s => s.name));\n const known = new Set([...symbolNames, ...functionNames]);\n const diagnostics: Diagnostic[] = [];\n\n // the change detection needs a variable of the chart, not any value\n walk.simple(parsed.ast, {\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\" || !CHANGE_HELPERS.has(node.callee.name)) {\n return;\n }\n const arg = node.arguments[0];\n let valid;\n if (arg?.type === \"Identifier\") {\n // an unknown name is already reported as unknown variable\n valid =\n symbolNames.has(arg.name) ||\n !(known.has(arg.name) || declared.has(arg.name) || GLOBALS.has(arg.name));\n } else {\n valid = arg?.type === \"Literal\" && typeof arg.value === \"string\" && symbolNames.has(arg.value);\n }\n if (!valid) {\n const { start, end } = arg ?? node;\n diagnostics.push(\n createDiagnostic(\n start + offset,\n end + offset,\n \"error\",\n \"%s() needs a variable of the chart as first argument\",\n [node.callee.name],\n ),\n );\n }\n },\n });\n for (const { node, write } of references) {\n const from = node.start + offset;\n const to = node.end + offset;\n if (!known.has(node.name) && !declared.has(node.name) && !GLOBALS.has(node.name)) {\n diagnostics.push(createDiagnostic(from, to, \"error\", 'Unknown variable \"%s\"', [node.name]));\n } else if (write && inputs.has(node.name) && !declared.has(node.name)) {\n diagnostics.push(\n createDiagnostic(from, to, \"warning\", 'Input \"%s\" is overwritten on its next change', [node.name]),\n );\n }\n }\n return diagnostics;\n}\n\n/**\n * Checks a transition label: its structure, the event and the JavaScript of condition and action\n *\n * @param label The label text\n * @param symbols The variables of the chart\n * @param functionNames Names declared in the function blocks of the chart\n */\nexport function validateTransitionLabel(\n label: string | undefined,\n symbols: ChartSymbol[],\n functionNames: string[] = [],\n): Diagnostic[] {\n let parsed;\n try {\n parsed = parseTransitionLabelWithRanges(label);\n } catch (err) {\n if (err instanceof LabelSyntaxError) {\n return [createDiagnostic(err.from, err.to, \"error\", err.key, err.args)];\n }\n throw err;\n }\n const { label: parts, ranges } = parsed;\n\n const diagnostics: Diagnostic[] = [];\n if (parts.event && ranges.event && !symbols.some(s => s.scope === \"input\" && s.name === parts.event)) {\n diagnostics.push(\n createDiagnostic(\n ranges.event.from,\n ranges.event.to,\n \"error\",\n 'Unknown event \"%s\", use the name of an input',\n [parts.event],\n ),\n );\n }\n if (parts.condition && ranges.condition) {\n diagnostics.push(...validateCode(parts.condition, \"expression\", symbols, ranges.condition.from, functionNames));\n }\n if (parts.action && ranges.action) {\n diagnostics.push(...validateCode(parts.action, \"statements\", symbols, ranges.action.from, functionNames));\n }\n return diagnostics;\n}\n\n/** A name declared at the top level of a function block */\nexport interface Declaration {\n name: string;\n /** e.g. \"clamp(x, lo, hi)\", null if it is no function */\n signature: string | null;\n /** Position of the name in the code */\n from: number;\n to: number;\n}\n\n/**\n * Finds the names declared at the top level of a function block: functions, but also constants etc.\n *\n * @param code The code of the function block\n * @returns empty if the code has syntax errors\n */\nexport function getDeclarations(code: string | undefined): Declaration[] {\n if (!code?.trim()) {\n return [];\n }\n const parsed = parseCode(code, \"statements\");\n if (\"diagnostic\" in parsed) {\n return [];\n }\n const signature = (fn: acorn.Function, name: string): string =>\n `${name}(${fn.params.map(p => code.substring(p.start, p.end)).join(\", \")})`;\n\n const declarations: Declaration[] = [];\n for (const node of (parsed.ast as acorn.Program).body) {\n if (node.type === \"FunctionDeclaration\" && node.id) {\n const { name, start, end } = node.id;\n declarations.push({ name, signature: signature(node, name), from: start, to: end });\n } else if (node.type === \"VariableDeclaration\") {\n for (const declarator of node.declarations) {\n if (declarator.id.type !== \"Identifier\") {\n continue;\n }\n const { name, start, end } = declarator.id;\n const init = declarator.init;\n const isFunction = init?.type === \"ArrowFunctionExpression\" || init?.type === \"FunctionExpression\";\n declarations.push({ name, signature: isFunction ? signature(init, name) : null, from: start, to: end });\n }\n }\n }\n return declarations;\n}\n\n/**\n * Names declared in all function blocks of a chart\n *\n * @param chart The chart\n */\nexport function getFunctionNames(chart: Chart): string[] {\n return (chart.functions || []).flatMap(fn => getDeclarations(fn.code).map(d => d.name));\n}\n\n/**\n * Replaces the variable in the first argument of hasChanged(), hasChangedFrom() and hasChangedTo() by its name\n * in quotes: these helpers need the name of the variable, not its value\n *\n * @param code The code\n * @param kind Expression or statements\n * @returns the changed code and the names of the variables, the unchanged code if it has syntax errors\n */\nexport function quoteChangeArguments(code: string, kind: CodeKind): { code: string; names: string[] } {\n const parsed = code.trim() ? parseCode(code, kind) : null;\n if (!parsed || \"diagnostic\" in parsed) {\n return { code, names: [] };\n }\n const names = new Set<string>();\n const replacements: acorn.Identifier[] = [];\n walk.simple(parsed.ast, {\n CallExpression(node) {\n const arg = node.arguments[0];\n if (node.callee.type !== \"Identifier\" || !CHANGE_HELPERS.has(node.callee.name)) {\n return;\n }\n if (arg?.type === \"Identifier\") {\n replacements.push(arg);\n names.add(arg.name);\n } else if (arg?.type === \"Literal\" && typeof arg.value === \"string\") {\n names.add(arg.value);\n }\n },\n });\n let result = code;\n for (const { start, end, name } of replacements.sort((a, b) => b.start - a.start)) {\n result = result.substring(0, start) + JSON.stringify(name) + result.substring(end);\n }\n return { code: result, names: [...names] };\n}\n\nexport interface ChartProblem {\n kind: \"state\" | \"transition\" | \"function\";\n /** ID of the state, transition or function block */\n id: string;\n /** \"entry\", \"during\", \"exit\", \"label\" or \"code\" */\n field: string;\n diagnostic: Diagnostic;\n}\n\n/**\n * Checks all actions, transition labels and function blocks of a chart\n *\n * @param chart The chart\n */\nexport function validateChart(chart: Chart): ChartProblem[] {\n const functionNames = getFunctionNames(chart);\n const problems: ChartProblem[] = [];\n for (const state of chart.states) {\n for (const field of STATE_ACTIONS) {\n for (const diagnostic of validateCode(state[field], \"statements\", chart.symbols, 0, functionNames)) {\n problems.push({ kind: \"state\", id: state.id, field, diagnostic });\n }\n }\n }\n for (const transition of chart.transitions) {\n for (const diagnostic of validateTransitionLabel(transition.label, chart.symbols, functionNames)) {\n problems.push({ kind: \"transition\", id: transition.id, field: \"label\", diagnostic });\n }\n }\n\n // a name may only be declared once in all function blocks, and not hide a variable\n const symbolNames = new Set(chart.symbols.map(s => s.name));\n const seen = new Set<string>();\n for (const fn of chart.functions || []) {\n for (const diagnostic of validateCode(fn.code, \"statements\", chart.symbols, 0, functionNames)) {\n problems.push({ kind: \"function\", id: fn.id, field: \"code\", diagnostic });\n }\n for (const { name, from, to } of getDeclarations(fn.code)) {\n let key = null;\n if (seen.has(name)) {\n key = '\"%s\" is declared in more than one function block';\n } else if (symbolNames.has(name) || GLOBALS.has(name)) {\n key = '\"%s\" is already the name of a variable';\n }\n if (key) {\n problems.push({\n kind: \"function\",\n id: fn.id,\n field: \"code\",\n diagnostic: createDiagnostic(from, to, \"error\", key, [name]),\n });\n }\n seen.add(name);\n }\n }\n return problems;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }