iobroker.statechart 0.1.1 → 0.3.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.
- package/LICENSE +21 -21
- package/README.md +59 -438
- package/admin/build/tab.js +133 -130
- package/admin/statechart.png +0 -0
- package/admin/{style.css → tab.css} +0 -2
- package/admin/tab_m.html +1 -1
- package/build/lib/chart-analysis.js +367 -0
- package/build/lib/chart-analysis.js.map +7 -0
- package/build/lib/chart-codegen.js +405 -0
- package/build/lib/chart-codegen.js.map +7 -0
- package/build/lib/chart-helpers.js +102 -0
- package/build/lib/chart-helpers.js.map +7 -0
- package/build/lib/chart-model.js +477 -0
- package/build/lib/chart-model.js.map +7 -0
- package/build/lib/chart-runtime.js +1521 -0
- package/build/lib/chart-runtime.js.map +7 -0
- package/build/lib/chart-structure.js +172 -0
- package/build/lib/chart-structure.js.map +7 -0
- package/build/lib/chart-validation.js +372 -0
- package/build/lib/chart-validation.js.map +7 -0
- package/build/main.js +638 -0
- package/build/main.js.map +7 -0
- package/io-package.json +31 -34
- package/package.json +21 -17
- package/admin/i18n/de.json +0 -4
- package/admin/i18n/en.json +0 -4
- package/admin/i18n/es.json +0 -4
- package/admin/i18n/fr.json +0 -4
- package/admin/i18n/it.json +0 -4
- package/admin/i18n/nl.json +0 -4
- package/admin/i18n/pl.json +0 -4
- package/admin/i18n/pt.json +0 -4
- package/admin/i18n/ru.json +0 -4
- package/admin/i18n/uk.json +0 -4
- package/admin/i18n/zh-cn.json +0 -4
- package/admin/jsonConfig.json +0 -19
- package/admin/statechart.svg +0 -38
- package/lib/adapter-config.d.ts +0 -19
- package/lib/chart-codegen.js +0 -436
- package/lib/chart-codegen.test.js +0 -132
- package/lib/chart-helpers.js +0 -74
- package/lib/chart-helpers.test.js +0 -38
- package/lib/chart-model.js +0 -577
- package/lib/chart-model.test.js +0 -189
- package/lib/chart-runtime.js +0 -797
- package/lib/chart-runtime.test.js +0 -699
- package/lib/chart-structure.js +0 -106
- package/lib/chart-validation.js +0 -328
- package/lib/chart-validation.test.js +0 -149
- package/main.js +0 -279
|
@@ -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, TIME_OF_DAY, TIME_UNITS, parseTransitionLabel } from \"./chart-model\";\nimport type { Chart, ChartState, ChartSymbol, ChartTransition, TemporalExpression } from \"./chart-model\";\nimport { ChartStructure, HISTORY_SUFFIX } from \"./chart-structure\";\nimport { getDeclarations, prepareHelperCalls, 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\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** advanceTime() fires at most this many timers, e.g. every(1, msec) over a day would never end */\nconst MAX_ADVANCE_TIMERS = 10_000;\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 /** Wakeups by each input since each active state was entered, by state (missing in older versions) */\n counts?: Record<string, Record<string, number>>;\n /** Since when the condition of each after(n, unit, condition) is true, by transition (missing in older versions) */\n trueSince?: Record<string, number>;\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, notes and colors are only documentation\n states: chart.states.map(({ x: _x, y: _y, width: _w, height: _h, comment: _c, color: _co, ...state }) => state),\n transitions: chart.transitions.map(\n ({\n sourceHandle: _s,\n targetHandle: _t,\n sourceAnchor: _sa,\n targetAnchor: _ta,\n labelOffset: _lo,\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\n/** Position of the ioBroker system, for the astro events */\nexport interface Location {\n /** Degrees north, negative for south */\n latitude: number;\n /** Degrees east, negative for west */\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 /**\n * \"start\": the chart was started, \"transition\": a transition was taken,\n * \"effect\": a simulation did not write an output or did not execute setState() etc.,\n * \"break\": a simulation stopped at a breakpoint\n */\n kind: \"start\" | \"transition\" | \"effect\" | \"break\";\n /** The chart runs as simulation */\n simulated?: boolean;\n /** Effect: what was not executed, e.g. 'light = true' or 'setState(\"x\", 1)'. Break: where it stopped */\n text?: string;\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 /** Reads a state with its ack flag and time stamps, for getState(), falls back to readState() */\n getState?: (stateId: string) => Promise<ioBroker.State | null | undefined>;\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 /** Starts a timer, the adapter clears its timers when it is unloaded. Default: the global setTimeout() */\n setTimeout?: (callback: () => void, ms: number) => unknown;\n /** Stops a timer started by setTimeout() */\n clearTimeout?: (handle: unknown) => void;\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 /** Simulation: called when the status changes */\n onSimulationStatus?: (status: SimulationStatus) => void;\n /** Writes to the log of the adapter */\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, e.g. after(5, sec) */\n temporal?: TemporalExpression;\n /** The condition of after(n, unit, condition) */\n temporalCondition: vm.Script | null;\n condition: vm.Script | null;\n}\n\n/** What getState() returns, like the JavaScript adapter */\nexport interface StateSnapshot {\n /** The value */\n val: any;\n /** Confirmed by the device or adapter (true), or a command (false) */\n ack: boolean;\n /** Time of the last update (ms since 1970) */\n ts: number;\n /** Time of the last change (ms since 1970) */\n lc: number;\n}\n\n/**\n * @param state A state of ioBroker\n * @returns the part of it which getState() returns, null if the state does not exist\n */\nfunction toSnapshot(state: ioBroker.State | null | undefined): StateSnapshot | null {\n return state ? { val: state.val, ack: !!state.ack, ts: state.ts, lc: state.lc } : null;\n}\n\n/** A timer which may be re-armed, see ChartRuntime.scheduleAt() */\ninterface Timer {\n handle?: unknown;\n /** When it fires (ms since 1970, in the time of the chart, see ChartRuntime.now()) */\n due?: number;\n callback?: () => void;\n /** What the timer is for, shown in the simulation, e.g. \"Off -> On\" */\n label?: string;\n}\n\n/** Simulation: a wakeup which waits while the simulation is paused */\ntype QueuedWakeup =\n | { kind: \"input\"; name: string; value: any }\n | { kind: \"event\"; name: string }\n | { kind: \"timer\"; fired: string | null }\n /** the rest of a super step which was stopped at a breakpoint */\n | { kind: \"continue\" };\n\n/** The status of a simulation, shown in the editor */\nexport interface SimulationStatus {\n /** Paused: the wakeups wait in a queue for the next step */\n paused: boolean;\n /** Added to the real time: the time of the simulation is Date.now() + timeOffset */\n timeOffset: number;\n /** Number of wakeups waiting while paused */\n queued: number;\n /** The next timer, null if there is none */\n nextTimer: { due: number; label: string } | null;\n /** Where the simulation stopped at a breakpoint, null if it was not stopped by one */\n breakpoint: string | 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 the timers of\n * the temporal transitions of the active states. Transitions with event are only checked when that input changed,\n * all others on every wakeup. Temporal transitions, measured from entering their source state:\n * - after(n, unit) is valid from n units on, so its condition is checked again on every following wakeup\n * - before(n, unit) is valid during the first n units, it has no timer\n * - at(n, unit) and every(n, unit) are only valid in the wakeup of their timer\n * - op(n, input) counts the wakeups by the input instead of the time, and is only valid in those wakeups\n * - after(n, unit, condition) is valid when the condition is true for n units, measured on the wakeups\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 * The children of a parallel state (or the top level of a parallel chart) are all active: in step 4, each of them\n * is processed in its execution order. A transition in one of them does not stop the others, unless it left\n * the parallel state.\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<Timer>();\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 /** how often each state was entered, to notice that a parallel state was left and entered again */\n readonly entryCount = new Map<string, number>();\n /** timers of the temporal transitions by state */\n readonly timers = new Map<string, Timer[]>();\n /** after(n, unit) transitions whose time has come */\n readonly expired = new Set<string>();\n /** at() and every() transitions whose timer caused the current wakeup */\n readonly firedTimers = new Set<string>();\n /** wakeups by each input since each active state was entered, by state */\n readonly inputCounts = new Map<string, Map<string, number>>();\n /** since when the condition of each after(n, unit, condition) of the active states is true, by transition */\n readonly trueSince = new Map<string, number>();\n /** timers of after(n, unit, condition), by transition */\n readonly durationTimers = new Map<string, Timer>();\n /** for duration(): since when the value of each call is true, by call and state */\n readonly durationCalls = new Map<string, { since: number; state: string | null }>();\n /** number of duration() calls found in the code, to give each of them an ID */\n durationCallCount = 0;\n /** the state whose condition or action is executed, used by elapsed() and duration() */\n context: string | null = null;\n /** timers of inputs with debounce, by variable name */\n readonly debounceTimers = new Map<string, unknown>();\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 /** the IDs of the states read by getState(), they are read at the start and then kept up to date */\n readonly readStateIds = new Set<string>();\n /** the states read by getState(), null if a state does not exist */\n readonly stateCache = new Map<string, StateSnapshot | null>();\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 /** true while a wakeup is processed, effects outside of wakeups are published right away */\n wakingUp = false;\n /** all running timers, to fire them early when the time of a simulation is advanced */\n readonly scheduled = new Set<Timer>();\n /** simulation: added to the real time, see advanceTime() */\n timeOffset = 0;\n /** simulation: paused, the wakeups wait in the queue */\n paused = false;\n /** simulation: the wakeups which wait while paused */\n readonly queue: QueuedWakeup[] = [];\n /** simulation: IDs of the states and transitions with a breakpoint */\n breakpoints = new Set<string>();\n /** simulation: set when a breakpoint is reached during a wakeup, it pauses after the step */\n pendingBreak: string | null = null;\n /** simulation: where it stopped at a breakpoint, until it continues */\n breakpointHit: string | null = null;\n /** JSON of the last status passed to host.onSimulationStatus() */\n lastStatus = \"\";\n /** the current time, can be replaced in tests. A simulation can be ahead of the real time. */\n now = (): number => Date.now() + this.timeOffset;\n\n /**\n * @param chartId ID of the chart object\n * @param chart The chart\n * @param host The connection to the outside world\n * @param simulated Simulation: the inputs are only changed by simulateInput(), outputs, setState() etc. are not\n * written but recorded in the history, nothing is persisted\n */\n constructor(\n readonly chartId: string,\n readonly chart: Chart,\n readonly host: RuntimeHost,\n readonly simulated = false,\n ) {\n this.structure = new ChartStructure(chart);\n this.statesById = this.structure.statesById;\n // the time units can be used in the helpers, e.g. elapsed(min)\n this.sandbox = vm.createContext({ ...this.createHelpers(), ...TIME_UNITS });\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.temporal?.condition, \"expression\");\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. and the IDs of the duration() calls,\n * see prepareHelperCalls()\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 = prepareHelperCalls(code, kind, () => `d${++this.durationCallCount}`);\n prepared = quoted.code;\n for (const name of quoted.names) {\n this.changeVariables.add(name);\n }\n for (const id of quoted.stateIds) {\n this.readStateIds.add(id);\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 * IDs of all states whose changes must be passed to handleStateChange(): the inputs and the states read by\n * getState()\n */\n get subscribedStateIds(): string[] {\n // a simulation does not react on the real inputs\n return [...new Set([...(this.simulated ? [] : this.inputStateIds), ...this.readStateIds])];\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 id of this.readStateIds) {\n try {\n let state;\n if (this.host.getState) {\n state = await this.host.getState(id);\n } else {\n const val = await this.host.readState(id);\n // without ack and time stamps, undefined: the state does not exist\n state =\n val === undefined\n ? null\n : ({ val, ack: true, ts: this.now(), lc: this.now() } as ioBroker.State);\n }\n this.stateCache.set(id, toSnapshot(state));\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] Cannot read ${id}: ${err.message}`);\n this.stateCache.set(id, null);\n }\n }\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 // effects of the entry actions are published together with the start, see recordEffect()\n this.wakingUp = true;\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 // before the effects of the entry actions\n this.pendingHistory.unshift({ ts: this.now(), kind: \"start\", restored, active: this.activeNames });\n this.wakingUp = false;\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.inputCounts.set(id, new Map(Object.entries(persisted.counts?.[id] ?? {})));\n for (const transition of this.temporalTransitions.get(id) || []) {\n const since = persisted.trueSince?.[transition.id];\n if (since !== undefined) {\n // the timer is started when the condition is checked on the wakeup after the start\n this.trueSince.set(transition.id, since);\n }\n }\n this.startTimers(id);\n }\n }\n\n /**\n * Publishes the active states after each transition, and logs errors of the state machine\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 {\n ...persisted,\n entered: persisted.entered || {},\n locals: persisted.locals || {},\n counts: persisted.counts || {},\n trueSince: persisted.trueSince || {},\n };\n }\n\n /**\n * Stores the current state of the chart, if it changed since the last time\n */\n persist(): void {\n // a simulation does not change the stored state of the real chart\n if (!this.actor || !this.host.persist || this.simulated) {\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 counts: Object.fromEntries(\n [...this.inputCounts]\n .filter(([, counts]) => counts.size)\n .map(([id, counts]) => [id, Object.fromEntries(counts)]),\n ),\n trueSince: Object.fromEntries(this.trueSince),\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 if (this.simulated && this.breakpoints.has(id)) {\n this.pendingBreak ??= this.statesById.get(id)?.name ?? id;\n }\n this.enteredAt.set(id, this.now());\n this.entryCount.set(id, (this.entryCount.get(id) ?? 0) + 1);\n this.inputCounts.set(id, new Map());\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 this.cancelTimer(timer);\n }\n this.timers.delete(id);\n this.inputCounts.delete(id);\n for (const transition of this.temporalTransitions.get(id) || []) {\n this.expired.delete(transition.id);\n this.stopDuration(transition.id);\n }\n // duration() starts again when the state is entered again\n for (const [key, call] of this.durationCalls) {\n if (call.state === id) {\n this.durationCalls.delete(key);\n }\n }\n }\n\n /**\n * Stops measuring how long the condition of an after(n, unit, condition) is true\n *\n * @param id ID of the transition\n */\n stopDuration(id: string): void {\n this.trueSince.delete(id);\n this.cancelTimer(this.durationTimers.get(id));\n this.durationTimers.delete(id);\n }\n\n /**\n * Starts a timer with the functions of the host, so the adapter can clear it when it is unloaded\n *\n * @param callback Called when the time has come\n * @param ms The delay\n * @returns the handle to stop it\n */\n startTimeout(callback: () => void, ms: number): unknown {\n return this.host.setTimeout ? this.host.setTimeout(callback, ms) : globalThis.setTimeout(callback, ms);\n }\n\n /**\n * @param handle The handle of a timer started by startTimeout(), may be undefined\n */\n stopTimeout(handle: unknown): void {\n if (handle === undefined) {\n return;\n }\n if (this.host.clearTimeout) {\n this.host.clearTimeout(handle);\n } else {\n globalThis.clearTimeout(handle as NodeJS.Timeout);\n }\n }\n\n /**\n * @param timer The timer to stop, may be undefined\n */\n cancelTimer(timer: Timer | undefined): void {\n if (timer) {\n this.stopTimeout(timer.handle);\n this.scheduled.delete(timer);\n }\n }\n\n /**\n * Wakes up the chart for a timer. A paused simulation queues the wakeup.\n *\n * @param fired ID of the at() or every() transition whose timer fired, they are only valid in this wakeup\n */\n timerWakeup(fired: string | null): void {\n if (this.simulated && this.paused) {\n this.queue.push({ kind: \"timer\", fired });\n this.publishLive();\n return;\n }\n if (fired) {\n this.firedTimers.add(fired);\n }\n try {\n this.wakeup(null);\n } finally {\n if (fired) {\n this.firedTimers.delete(fired);\n }\n }\n }\n\n /**\n * Calls the callback at the given time, also after delays which are too long for setTimeout()\n *\n * @param due The time (ms since 1970), the callback is called right away if it has passed\n * @param timer Gets the handle of the timeout, to clear it\n * @param callback Called at the time\n */\n scheduleAt(due: number, timer: Timer, callback: () => void): void {\n this.stopTimeout(timer.handle);\n timer.due = due;\n timer.callback = callback;\n this.scheduled.add(timer);\n const remaining = due - this.now();\n timer.handle = this.startTimeout(\n () => {\n if (remaining > MAX_TIMEOUT_MS && due - this.now() > 0) {\n this.scheduleAt(due, timer, callback);\n } else {\n this.scheduled.delete(timer);\n callback();\n }\n },\n Math.min(Math.max(remaining, 0), MAX_TIMEOUT_MS),\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: Timer[] = [];\n this.timers.set(id, timers);\n for (const transition of this.temporalTransitions.get(id) || []) {\n const { operator, ms, condition, time } = transition.temporal as TemporalExpression;\n if (time !== undefined) {\n const timer: Timer = { label: transition.where };\n timers.push(timer);\n this.scheduleDaily(id, transition, timer, this.now());\n continue;\n }\n // before() needs no timer, counting expressions wait for their input, and the timer of\n // after(n, unit, condition) starts when the condition is true\n if (ms === undefined || operator === \"before\" || condition !== undefined) {\n continue;\n }\n const timer: Timer = { label: transition.where };\n timers.push(timer);\n const fire = (due: number): void => {\n if (operator === \"after\") {\n this.expired.add(transition.id);\n this.timerWakeup(null);\n return;\n }\n this.timerWakeup(transition.id);\n // unless the wakeup left the state\n if (operator === \"every\" && this.timers.get(id)?.includes(timer)) {\n this.scheduleAt(due + ms, timer, () => fire(due + ms));\n }\n };\n let due = entered + ms;\n if (operator === \"every\" && due < this.now()) {\n // after a restart: the next time in the rhythm, the times missed while the adapter was stopped are skipped\n due = entered + Math.ceil((this.now() - entered) / ms) * ms;\n }\n this.scheduleAt(due, timer, () => fire(due));\n }\n }\n\n /**\n * Starts the timer of at(\"sunset\", offset) or at(\"22:30\") for the next time, which wakes up the chart\n *\n * @param stateId ID of the source state\n * @param transition The transition\n * @param timer Gets the handle of the timeout\n * @param after The timer is started for the next time after this one (ms since 1970)\n */\n scheduleDaily(stateId: string, transition: CheckedTransition, timer: Timer, after: number): void {\n let due;\n try {\n due = this.getNextDailyTime(transition.temporal as TemporalExpression, after);\n } catch (err) {\n this.host.log.warn(`[${this.chart.name}] ${transition.where}: ${err.message}`);\n return;\n }\n if (due === null) {\n // e.g. no sunset for a week in polar regions: checked again tomorrow\n this.scheduleAt(after + DAY_MS, timer, () =>\n this.scheduleDaily(stateId, transition, timer, after + DAY_MS),\n );\n return;\n }\n this.scheduleAt(due, timer, () => {\n this.timerWakeup(transition.id);\n // the next day, unless the wakeup left the state\n if (this.timers.get(stateId)?.includes(timer)) {\n this.scheduleDaily(stateId, transition, timer, Math.max(due, this.now()));\n }\n });\n }\n\n /**\n * @param temporal at(\"sunset\", offset) or at(\"22:30\")\n * @param after The time is searched after this one (ms since 1970)\n * @returns the next time (ms since 1970), null if there is none in the next week (astro events in polar regions)\n * @throws {Error} for astro events if no location is configured\n */\n getNextDailyTime(temporal: TemporalExpression, after: number): number | null {\n const time = temporal.time as string;\n const offset = (temporal.offsetMinutes ?? 0) * 60_000;\n const day = new Date(after);\n // yesterday as well: with a positive offset, the time of yesterday may still come\n day.setDate(day.getDate() - 1);\n for (let i = 0; i < 9; i++) {\n let at: number | null;\n if (TIME_OF_DAY.test(time)) {\n const [hours, minutes, seconds = 0] = time.split(\":\").map(Number);\n at = new Date(day).setHours(hours, minutes, seconds, 0);\n } else {\n // noon, so the astro events are those of this day\n const event = this.getSunTimes(new Date(new Date(day).setHours(12, 0, 0, 0)))[time];\n at = event instanceof Date ? event.getTime() : null;\n }\n if (at !== null && at + offset > after) {\n return at + offset;\n }\n day.setDate(day.getDate() + 1);\n }\n return null;\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 ? `/${field}` : \"\"}`;\n } else if (kind === \"symbol\") {\n where = `Variable ${id}`;\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 // hints of the analysis, e.g. unused variables, are often intended\n const log = { error: this.host.log.error, warning: this.host.log.warn, info: this.host.log.debug }[\n diagnostic.severity\n ];\n log(`[${this.chart.name}] ${where}: ${diagnostic.message}`);\n }\n }\n\n /**\n * Stops the state machine and all timers, delayed writes are discarded\n */\n stop(): void {\n this.actor?.stop();\n this.actor = null;\n for (const timer of this.scheduled) {\n this.stopTimeout(timer.handle);\n }\n this.scheduled.clear();\n this.timers.clear();\n this.expired.clear();\n this.durationTimers.clear();\n for (const timer of this.debounceTimers.values()) {\n this.stopTimeout(timer);\n }\n this.debounceTimers.clear();\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 const describe = (name: string, args: any[]): string =>\n `${name}(${args.map(arg => (arg === undefined ? \"undefined\" : JSON.stringify(arg))).join(\", \")})`;\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 if (this.simulated) {\n this.recordEffect(describe(\"setState\", [id, value, ...(ack ? [true] : [])]));\n return;\n }\n void write(id, value, ack);\n },\n setStateDelayed: (id: string, value: any, delayMs: number, ack = false) => {\n const timer: Timer = { label: describe(\"setStateDelayed\", [id, value]) };\n this.delayedWrites.add(timer);\n this.scheduleAt(this.now() + Math.max(Number(delayMs) || 0, 0), timer, () => {\n this.delayedWrites.delete(timer);\n if (this.simulated) {\n this.recordEffect(describe(\"setState\", [id, value, ...(ack ? [true] : [])]));\n return;\n }\n void write(id, value, ack);\n });\n },\n sendTo: (instance: string, command: string, message: any) => {\n if (this.simulated) {\n this.recordEffect(describe(\"sendTo\", [instance, command, message]));\n return;\n }\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 getState: (id: string) => {\n if (!this.stateCache.has(id)) {\n throw new Error(\n `getState() can only read states whose ID is written as text, e.g. getState(\"${id}\")`,\n );\n }\n const state = this.stateCache.get(id);\n // a copy, so the code cannot change the cache\n return state ? { ...state } : null;\n },\n elapsed: (unit = TIME_UNITS.sec) => {\n const entered = this.context === null ? undefined : this.enteredAt.get(this.context);\n if (entered === undefined) {\n throw new Error(\"elapsed() can only be used in conditions and in the actions of states\");\n }\n return (this.now() - entered) / unit;\n },\n // the ID of the call is added by prepareHelperCalls()\n duration: (call: string, value: any, unit = TIME_UNITS.sec) => {\n const key = `${call}@${this.context}`;\n if (!value) {\n this.durationCalls.delete(key);\n return 0;\n }\n const since = this.durationCalls.get(key)?.since ?? this.now();\n this.durationCalls.set(key, { since, state: this.context });\n return (this.now() - since) / unit;\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 one of the subscribedStateIds is updated\n *\n * @param stateId ID of the updated state\n * @param state The new state\n */\n handleStateChange(stateId: string, state: ioBroker.State): void {\n if (this.readStateIds.has(stateId)) {\n this.stateCache.set(stateId, toSnapshot(state));\n }\n if (!this.simulated) {\n this.handleInput(stateId, state.val, { ack: state.ack });\n }\n }\n\n /**\n * Simulation: sets the value of an input and wakes up the chart, like a change of the input\n *\n * @param name Name of the input\n * @param val The new value\n * @returns false if the chart has no input with this name\n */\n simulateInput(name: string, val: any): boolean {\n const symbol = this.chart.symbols.find(s => s.scope === \"input\" && s.name === name);\n if (!symbol || !this.actor) {\n return false;\n }\n if (this.paused) {\n this.queue.push({ kind: \"input\", name, value: val });\n this.publishLive();\n return true;\n }\n // the filters by ack and the debounce do not apply to values set by hand\n this.applyInput(symbol, val);\n return true;\n }\n\n /**\n * Simulation: pauses, the following wakeups wait in a queue\n */\n pauseSimulation(): void {\n this.paused = true;\n this.publishLive();\n }\n\n /**\n * Simulation: processes the queued wakeups until a breakpoint is reached, then continues normally\n */\n resumeSimulation(): void {\n this.paused = false;\n this.breakpointHit = null;\n while (!this.paused && this.queue.length) {\n this.processQueued(this.queue.shift() as QueuedWakeup);\n }\n this.publishLive();\n }\n\n /**\n * Simulation: processes the next queued wakeup, and stays paused\n *\n * @returns false if no wakeup was queued\n */\n stepSimulation(): boolean {\n const next = this.queue.shift();\n if (!next) {\n return false;\n }\n this.breakpointHit = null;\n this.paused = false;\n try {\n this.processQueued(next);\n } finally {\n this.paused = true;\n }\n this.publishLive();\n return true;\n }\n\n /**\n * @param wakeup A wakeup which waited while the simulation was paused\n */\n processQueued(wakeup: QueuedWakeup): void {\n if (wakeup.kind === \"input\") {\n const symbol = this.chart.symbols.find(s => s.scope === \"input\" && s.name === wakeup.name);\n if (symbol) {\n this.applyInput(symbol, wakeup.value);\n }\n } else if (wakeup.kind === \"event\") {\n this.wakeup(wakeup.name);\n } else if (wakeup.kind === \"timer\") {\n this.timerWakeup(wakeup.fired);\n } else {\n this.wakeup(null);\n }\n }\n\n /**\n * Simulation: lets time pass. The timers which are due meanwhile fire in the order of their time, a paused\n * simulation queues their wakeups.\n *\n * @param ms The time to advance\n */\n advanceTime(ms: number): void {\n const target = this.now() + Math.max(0, ms);\n for (let fired = 0; ; fired++) {\n let next: Timer | undefined;\n for (const timer of this.scheduled) {\n if ((timer.due as number) <= target && (!next || (timer.due as number) < (next.due as number))) {\n next = timer;\n }\n }\n if (!next) {\n break;\n }\n if (fired >= MAX_ADVANCE_TIMERS) {\n this.host.log.warn(`[${this.chart.name}] Stopped advancing the time after ${fired} timers`);\n return;\n }\n this.timeOffset += Math.max(0, (next.due as number) - this.now());\n this.cancelTimer(next);\n (next.callback as () => void)();\n }\n this.timeOffset += Math.max(0, target - this.now());\n // the remaining timers wait for the new time\n for (const timer of [...this.scheduled]) {\n this.scheduleAt(timer.due as number, timer, timer.callback as () => void);\n }\n this.publishLive();\n }\n\n /**\n * Simulation: advances the time to the next timer, see advanceTime()\n *\n * @returns false if there is no timer\n */\n advanceToNextTimer(): boolean {\n const next = this.getNextTimer();\n if (!next) {\n return false;\n }\n this.advanceTime(next.due - this.now());\n return true;\n }\n\n /**\n * @returns the timer which fires next, null if there is none\n */\n getNextTimer(): { due: number; label: string } | null {\n let next: Timer | undefined;\n for (const timer of this.scheduled) {\n if (!next || (timer.due as number) < (next.due as number)) {\n next = timer;\n }\n }\n return next ? { due: next.due as number, label: next.label ?? \"\" } : null;\n }\n\n /**\n * Simulation: records something which was not executed, shown in the history\n *\n * @param text What was not executed\n */\n recordEffect(text: string): void {\n this.pendingHistory.push({ ts: this.now(), kind: \"effect\", text, active: this.activeNames });\n // e.g. setStateDelayed(): its time came without a wakeup\n if (!this.wakingUp) {\n this.publishLive();\n }\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 this.stopTimeout(this.debounceTimers.get(symbol.name));\n this.debounceTimers.set(\n symbol.name,\n this.startTimeout(() => {\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 * Wakes up the chart with the event of an input, without changing the value of the input\n * (state charts.<chart>.event)\n *\n * @param name Name of the input\n * @returns false if the chart has no input with this name\n */\n handleEvent(name: string): boolean {\n if (!this.chart.symbols.some(s => s.scope === \"input\" && s.name === name)) {\n return false;\n }\n if (this.simulated && this.paused) {\n this.queue.push({ kind: \"event\", name });\n this.publishLive();\n } else {\n this.wakeup(name);\n }\n return true;\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.wakingUp = true;\n try {\n this.processWakeup(input);\n // functions called in conditions may have changed outputs as well\n this.writeChangedOutputs();\n } finally {\n this.wakingUp = false;\n }\n if (this.pendingBreak) {\n // simulation: the following wakeups wait until the user continues\n this.paused = true;\n this.breakpointHit = this.pendingBreak;\n this.pendingHistory.push({\n ts: this.now(),\n kind: \"break\",\n text: this.pendingBreak,\n active: this.activeNames,\n });\n this.pendingBreak = null;\n }\n this.persist();\n this.publishLive();\n }\n\n /**\n * @param input Name of the input which caused the wakeup, null for timers and the start\n */\n processWakeup(input: string | null): void {\n this.rememberValues();\n if (input !== null) {\n for (const [id, counts] of this.inputCounts) {\n // only the inputs counted by the state, so other wakeups do not change the persisted data\n if (this.temporalTransitions.get(id)?.some(t => t.temporal?.event === input)) {\n counts.set(input, (counts.get(input) ?? 0) + 1);\n }\n }\n }\n this.updateDurations();\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 if (this.pendingBreak) {\n // simulation: the rest of the super step is the next step\n this.queue.unshift({ kind: \"continue\" });\n break;\n }\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 // the states entered by this wakeup start measuring their after(n, unit, condition)\n this.updateDurations();\n }\n\n /**\n * Checks the conditions of after(n, unit, condition) of the active states, and starts a timer which wakes up the\n * chart when a condition has been true for the time\n */\n updateDurations(): void {\n for (const id of this.activeIds) {\n for (const transition of this.temporalTransitions.get(id) || []) {\n const temporal = transition.temporal as TemporalExpression;\n if (temporal.condition === undefined) {\n continue;\n }\n if (!this.run(transition.temporalCondition, `${transition.where}/after condition`, id)) {\n this.stopDuration(transition.id);\n continue;\n }\n const since = this.trueSince.get(transition.id) ?? this.now();\n this.trueSince.set(transition.id, since);\n if (!this.durationTimers.has(transition.id)) {\n const timer: Timer = { label: transition.where };\n this.durationTimers.set(transition.id, timer);\n this.scheduleAt(since + (temporal.ms as number), timer, () => {\n this.durationTimers.delete(transition.id);\n this.timerWakeup(null);\n });\n }\n }\n }\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 return this.processChildren(null, input);\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.simulated\n ? this.pendingHistory.map(entry => ({ ...entry, simulated: true }))\n : this.pendingHistory;\n this.pendingHistory = [];\n this.host.onHistory?.(entries);\n }\n if (this.simulated && this.host.onSimulationStatus) {\n const status: SimulationStatus = {\n paused: this.paused,\n timeOffset: this.timeOffset,\n queued: this.queue.length,\n nextTimer: this.getNextTimer(),\n breakpoint: this.breakpointHit,\n };\n const json = JSON.stringify(status);\n if (json !== this.lastStatus) {\n this.lastStatus = json;\n this.host.onSimulationStatus(status);\n }\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`, id);\n }\n if (this.takeFirstValid(this.innerTransitions.get(id), input)) {\n return true;\n }\n return this.processChildren(id, input);\n }\n\n /**\n * Processes the active child of a state, or all children of a parallel state, see the class description\n *\n * @param parent ID of the state, null for the top level\n * @param input Name of the input which caused the wakeup, null for timers\n * @returns true if a transition was taken\n */\n processChildren(parent: string | null, input: string | null): boolean {\n if (!this.structure.isParallel(parent)) {\n for (const child of this.getActiveChildren(parent)) {\n if (this.processState(child, input)) {\n return true;\n }\n }\n return false;\n }\n const entries = parent && this.entryCount.get(parent);\n let taken = false;\n for (const child of this.structure.getChildren(parent)) {\n // a transition of a previous child left the parallel state (and maybe entered it again)\n if (parent && (!this.activeIds.includes(parent) || this.entryCount.get(parent) !== entries)) {\n break;\n }\n if (this.activeIds.includes(child.id) && this.processState(child.id, input)) {\n taken = true;\n }\n }\n return taken;\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 (!this.isTriggered(transition, input)) {\n continue;\n }\n if (\n transition.condition &&\n !this.run(transition.condition, `${transition.where}/condition`, transition.source)\n ) {\n continue;\n }\n // the transition is listed before the effects of its actions\n const at = this.pendingHistory.length;\n if (this.simulated && this.breakpoints.has(transition.id)) {\n this.pendingBreak ??= `${transition.from} \u2192 ${transition.to}`;\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.splice(at, 0, {\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 The transition\n * @param input Name of the input which caused the wakeup, null for timers\n * @returns true if its event and its temporal expression allow it in this wakeup (the condition is not checked)\n */\n isTriggered(transition: CheckedTransition, input: string | null): boolean {\n if (transition.event && transition.event !== input) {\n return false;\n }\n const temporal = transition.temporal;\n if (!temporal) {\n return true;\n }\n if (temporal.event !== undefined) {\n if (temporal.event !== input) {\n return false;\n }\n const count = this.inputCounts.get(transition.source)?.get(temporal.event) ?? 0;\n const n = temporal.count as number;\n switch (temporal.operator) {\n case \"after\":\n return count >= n;\n case \"before\":\n return count < n;\n case \"at\":\n return count === n;\n case \"every\":\n return count % n === 0;\n }\n }\n const ms = temporal.ms as number;\n if (temporal.condition !== undefined) {\n const since = this.trueSince.get(transition.id);\n return since !== undefined && this.now() - since >= ms;\n }\n const entered = this.enteredAt.get(transition.source);\n switch (temporal.operator) {\n case \"after\":\n // the timer may fire a bit early, or not at all while the adapter was stopped\n return this.expired.has(transition.id) || (entered !== undefined && this.now() - entered >= ms);\n case \"before\":\n return entered !== undefined && this.now() - entered < ms;\n default:\n // at() and every()\n return this.firedTimers.has(transition.id);\n }\n }\n\n /**\n * @returns the configuration of the XState machine: the states with their entry and exit actions, the\n * transitions as guarded events\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`, state.id)] : []),\n ],\n exit: [\n ...(state.exit ? [() => this.runAction(state.exit, `${state.name}/exit`, state.id)] : []),\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.temporal !== undefined),\n );\n\n const subStates = structure.getChildren(state.id);\n if (subStates.length) {\n if (structure.isParallel(state.id)) {\n // all children are active, XState enters them in their execution order\n node.type = \"parallel\";\n } else {\n node.initial = structure.getInitialChild(state.id);\n }\n node.states = Object.fromEntries(subStates.map(s => [s.id, buildState(s)]));\n if (structure.hasHistory(state.id)) {\n // without history yet, XState enters the initial state\n node.states[HISTORY_SUFFIX] = { id: `${state.id}${HISTORY_SUFFIX}`, type: \"history\" };\n }\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 ...(structure.isParallel(null) ? { type: \"parallel\" } : { 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 if (this.structure.getCrossedParallel(transition) !== undefined) {\n // already logged as problem of the chart\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 temporalCondition = label.temporal?.condition\n ? this.compile(`(${this.prepareCode(label.temporal.condition, \"expression\")})`, `${where}/after condition`)\n : null;\n const { inner, reenter } = this.structure.getTransitionKind(transition);\n const config = {\n target: `#${this.structure.getTargetId(transition)}`,\n reenter,\n actions: label.action ? [() => this.runAction(label.action, `${where}/action`, source.id)] : [],\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 temporal: label.temporal,\n temporalCondition,\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 * @param context The state whose condition or action it is, for elapsed() and duration()\n */\n run(script: vm.Script | null, where: string, context: string | null = this.context): any {\n if (!script) {\n return undefined;\n }\n const previous = this.context;\n this.context = context;\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 } finally {\n this.context = previous;\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 * @param context The state whose action it is (the source state for transition actions)\n */\n runAction(code: string | undefined, where: string, context: 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, context);\n this.writeChangedOutputs();\n }\n\n /**\n * Writes the outputs whose values were changed by actions to their states, in a simulation only records them\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 if (this.simulated) {\n this.recordEffect(`${symbol.name} = ${val === undefined ? \"undefined\" : JSON.stringify(val)}`);\n continue;\n }\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": "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",
|
|
6
|
+
"names": ["crypto", "vm", "timer", "due", "SunCalc", "json"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
HISTORY_SUFFIX: () => HISTORY_SUFFIX,
|
|
23
|
+
sortByOrder: () => sortByOrder
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(chart_structure_exports);
|
|
26
|
+
function sortByOrder(states) {
|
|
27
|
+
return [...states].sort((a, b) => (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER));
|
|
28
|
+
}
|
|
29
|
+
const HISTORY_SUFFIX = "$history";
|
|
30
|
+
class ChartStructure {
|
|
31
|
+
/**
|
|
32
|
+
* @param chart The chart whose structure is prepared
|
|
33
|
+
*/
|
|
34
|
+
constructor(chart) {
|
|
35
|
+
this.chart = chart;
|
|
36
|
+
this.statesById = new Map(chart.states.map((s) => [s.id, s]));
|
|
37
|
+
for (const state of chart.states) {
|
|
38
|
+
const parent = state.parent && this.statesById.has(state.parent) ? state.parent : "";
|
|
39
|
+
this.childrenByParent.set(parent, [...this.childrenByParent.get(parent) || [], state]);
|
|
40
|
+
}
|
|
41
|
+
for (const transition of chart.transitions) {
|
|
42
|
+
const list = this.transitionsBySource.get(transition.source) || [];
|
|
43
|
+
this.transitionsBySource.set(transition.source, [...list, transition]);
|
|
44
|
+
}
|
|
45
|
+
for (const [parent, children] of this.childrenByParent) {
|
|
46
|
+
if (this.isParallel(parent || null)) {
|
|
47
|
+
this.childrenByParent.set(parent, sortByOrder(children));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const list of this.transitionsBySource.values()) {
|
|
51
|
+
list.sort((a, b) => (a.priority ?? Number.MAX_SAFE_INTEGER) - (b.priority ?? Number.MAX_SAFE_INTEGER));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** All states by their ID */
|
|
55
|
+
statesById;
|
|
56
|
+
/** children by parent ID, "" for the top level */
|
|
57
|
+
childrenByParent = /* @__PURE__ */ new Map();
|
|
58
|
+
/** transitions by source, sorted by priority */
|
|
59
|
+
transitionsBySource = /* @__PURE__ */ new Map();
|
|
60
|
+
/**
|
|
61
|
+
* @param parentId null for the top level
|
|
62
|
+
* @returns true if the children of the state (or the top level states) are parallel
|
|
63
|
+
*/
|
|
64
|
+
isParallel(parentId) {
|
|
65
|
+
return !!(parentId ? this.statesById.get(parentId)?.parallel : this.chart.parallel);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @param parentId null for the top level
|
|
69
|
+
* @returns the children, those of a parallel state in their execution order
|
|
70
|
+
*/
|
|
71
|
+
getChildren(parentId) {
|
|
72
|
+
return this.childrenByParent.get(parentId || "") || [];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The initial state of a level: the configured one if it is a child of this level, otherwise the first child
|
|
76
|
+
*
|
|
77
|
+
* @param parentId null for the top level
|
|
78
|
+
* @returns undefined if the level has no states
|
|
79
|
+
*/
|
|
80
|
+
getInitialChild(parentId) {
|
|
81
|
+
const children = this.getChildren(parentId);
|
|
82
|
+
const configured = parentId ? this.statesById.get(parentId)?.initial : this.chart.initial;
|
|
83
|
+
return children.some((s) => s.id === configured) ? configured : children[0]?.id;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* @param stateId ID of the state
|
|
87
|
+
* @returns true if the state has a history junction which is used: it has exclusive children
|
|
88
|
+
*/
|
|
89
|
+
hasHistory(stateId) {
|
|
90
|
+
return !!this.statesById.get(stateId)?.history && this.getChildren(stateId).length > 0 && !this.isParallel(stateId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The XState target of a transition. Like in Stateflow, all transitions ending at a state with history junction
|
|
94
|
+
* enter it through the history junction, also its self transitions and those from its children.
|
|
95
|
+
*
|
|
96
|
+
* @param transition The transition
|
|
97
|
+
* @returns the ID of the target state or of its history node
|
|
98
|
+
*/
|
|
99
|
+
getTargetId(transition) {
|
|
100
|
+
return this.hasHistory(transition.target) ? `${transition.target}${HISTORY_SUFFIX}` : transition.target;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* @param stateId ID of the source state
|
|
104
|
+
* @returns the transitions starting at the state, sorted by priority
|
|
105
|
+
*/
|
|
106
|
+
getTransitions(stateId) {
|
|
107
|
+
return this.transitionsBySource.get(stateId) || [];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @param ancestorId ID of the possible ancestor
|
|
111
|
+
* @param id ID of the possible descendant
|
|
112
|
+
* @returns true if the state "id" is a (direct or indirect) child of "ancestorId"
|
|
113
|
+
*/
|
|
114
|
+
isDescendant(ancestorId, id) {
|
|
115
|
+
let parent = this.statesById.get(id)?.parent;
|
|
116
|
+
for (let i = 0; parent && i < this.statesById.size; i++) {
|
|
117
|
+
if (parent === ancestorId) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
parent = this.statesById.get(parent)?.parent;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* @param id ID of the state
|
|
126
|
+
* @returns the state and its ancestors, the top level state first
|
|
127
|
+
*/
|
|
128
|
+
getPath(id) {
|
|
129
|
+
const path = [];
|
|
130
|
+
for (let current = id; current && path.length <= this.statesById.size; ) {
|
|
131
|
+
path.unshift(current);
|
|
132
|
+
current = this.statesById.get(current)?.parent;
|
|
133
|
+
}
|
|
134
|
+
return path;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Transitions between parallel states are not possible, also not between their children: both are active
|
|
138
|
+
*
|
|
139
|
+
* @param transition The transition
|
|
140
|
+
* @returns the parallel state (null for the top level) whose children the transition connects, undefined if none
|
|
141
|
+
*/
|
|
142
|
+
getCrossedParallel(transition) {
|
|
143
|
+
const source = this.getPath(transition.source);
|
|
144
|
+
const target = this.getPath(transition.target);
|
|
145
|
+
for (let i = 0; i < Math.min(source.length, target.length); i++) {
|
|
146
|
+
if (source[i] !== target[i]) {
|
|
147
|
+
const parent = i ? source[i - 1] : null;
|
|
148
|
+
return this.isParallel(parent) ? parent : void 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* How a transition is executed
|
|
155
|
+
*
|
|
156
|
+
* @param transition The transition
|
|
157
|
+
*/
|
|
158
|
+
getTransitionKind(transition) {
|
|
159
|
+
const { source, target } = transition;
|
|
160
|
+
const toChild = this.isDescendant(source, target);
|
|
161
|
+
const inner = toChild && !transition.reenterParent;
|
|
162
|
+
const reenter = source === target || toChild && !inner || this.isDescendant(target, source);
|
|
163
|
+
return { inner, reenter };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
167
|
+
0 && (module.exports = {
|
|
168
|
+
ChartStructure,
|
|
169
|
+
HISTORY_SUFFIX,
|
|
170
|
+
sortByOrder
|
|
171
|
+
});
|
|
172
|
+
//# 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\n/**\n * Sorts parallel sibling states by their execution order. The sort is stable: states without order keep their\n * order, after the others.\n *\n * @param states The siblings\n */\nexport function sortByOrder<T extends { order?: number }>(states: T[]): T[] {\n return [...states].sort((a, b) => (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER));\n}\n\n/** Appended to the ID of a state with history for the ID of its XState history node */\nexport const HISTORY_SUFFIX = \"$history\";\n\n/** How a transition is taken, depending on how its source and target are nested */\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\n/**\n * The structure of a chart, prepared for fast lookups: the states by ID, the children of each state, the\n * transitions of each state\n */\nexport class ChartStructure {\n /** All states by their ID */\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 /**\n * @param chart The chart whose structure is prepared\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 [parent, children] of this.childrenByParent) {\n if (this.isParallel(parent || null)) {\n this.childrenByParent.set(parent, sortByOrder(children));\n }\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 * @returns true if the children of the state (or the top level states) are parallel\n */\n isParallel(parentId: string | null): boolean {\n return !!(parentId ? this.statesById.get(parentId)?.parallel : this.chart.parallel);\n }\n\n /**\n * @param parentId null for the top level\n * @returns the children, those of a parallel state in their execution order\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 state\n * @returns true if the state has a history junction which is used: it has exclusive children\n */\n hasHistory(stateId: string): boolean {\n return (\n !!this.statesById.get(stateId)?.history && this.getChildren(stateId).length > 0 && !this.isParallel(stateId)\n );\n }\n\n /**\n * The XState target of a transition. Like in Stateflow, all transitions ending at a state with history junction\n * enter it through the history junction, also its self transitions and those from its children.\n *\n * @param transition The transition\n * @returns the ID of the target state or of its history node\n */\n getTargetId(transition: ChartTransition): string {\n return this.hasHistory(transition.target) ? `${transition.target}${HISTORY_SUFFIX}` : transition.target;\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 * @param id ID of the state\n * @returns the state and its ancestors, the top level state first\n */\n getPath(id: string): string[] {\n const path: string[] = [];\n // the counter protects against cycles in invalid charts\n for (let current: string | null | undefined = id; current && path.length <= this.statesById.size;) {\n path.unshift(current);\n current = this.statesById.get(current)?.parent;\n }\n return path;\n }\n\n /**\n * Transitions between parallel states are not possible, also not between their children: both are active\n *\n * @param transition The transition\n * @returns the parallel state (null for the top level) whose children the transition connects, undefined if none\n */\n getCrossedParallel(transition: ChartTransition): string | null | undefined {\n const source = this.getPath(transition.source);\n const target = this.getPath(transition.target);\n for (let i = 0; i < Math.min(source.length, target.length); i++) {\n if (source[i] !== target[i]) {\n const parent = i ? source[i - 1] : null;\n return this.isParallel(parent) ? parent : undefined;\n }\n }\n // the same state, or one is an ancestor of the other\n return undefined;\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": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|