iobroker.statechart 0.2.0 → 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 +42 -530
- package/admin/build/tab.js +118 -117
- 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 +82 -15
- package/build/lib/chart-codegen.js.map +3 -3
- package/build/lib/chart-helpers.js +12 -0
- package/build/lib/chart-helpers.js.map +2 -2
- package/build/lib/chart-model.js +138 -14
- package/build/lib/chart-model.js.map +2 -2
- package/build/lib/chart-runtime.js +732 -87
- package/build/lib/chart-runtime.js.map +3 -3
- package/build/lib/chart-structure.js +73 -2
- package/build/lib/chart-structure.js.map +2 -2
- package/build/lib/chart-validation.js +86 -17
- package/build/lib/chart-validation.js.map +3 -3
- package/build/main.js +330 -34
- package/build/main.js.map +2 -2
- package/io-package.json +18 -34
- package/package.json +2 -1
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/chart-codegen.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Generates readable JavaScript from a chart. It shows how the runtime executes the chart:\n * the XState machine, and the functions which select the transitions in Stateflow order.\n * The code is only shown to the user, the runtime does not execute it.\n */\n\nimport { HELPERS } from \"./chart-helpers\";\nimport { MAX_SUPER_STEPS, parseTransitionLabel } from \"./chart-model\";\nimport type { Chart, ChartState, ChartTransition, TransitionLabel } from \"./chart-model\";\nimport { ChartStructure } from \"./chart-structure\";\nimport type { TransitionKind } from \"./chart-structure\";\n\nconst INDENT = \" \";\n\nfunction indent(text: string, level: number): string {\n const prefix = INDENT.repeat(level);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? prefix + line : \"\"))\n .join(\"\\n\");\n}\n\n/**\n * Text for a // comment, on one line\n *\n * @param text The text, may have several lines\n */\nfunction oneLine(text: string | undefined): string {\n return (text || \"\").replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * A comment or note as // lines\n *\n * @param text The comment\n * @param prefix Indentation and optional text before the first line, e.g. \"Note: \"\n * @param indentation Added before each line\n * @returns no lines for an empty text\n */\nfunction commentLines(text: string | undefined, prefix = \"\", indentation = \"\"): string[] {\n if (!text?.trim()) {\n return [];\n }\n return text\n .trim()\n .split(\"\\n\")\n .map((line, i) => `${indentation}// ${i ? \" \".repeat(prefix.length) : prefix}${line.trimEnd()}`.trimEnd());\n}\n\n/**\n * Converts a state ID to a valid identifier for the names of the generated functions\n *\n * @param id ID of the state\n */\nfunction identifier(id: string): string {\n const name = id.replace(/[^\\w$]/g, \"_\");\n return /^\\d/.test(name) ? `_${name}` : name;\n}\n\n/**\n * @param key The property name\n * @returns the key for an object literal, in quotes only if necessary\n */\nfunction propertyKey(key: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(key) ? key : JSON.stringify(key);\n}\n\n/**\n * Removes the indentation all lines have in common, so the code can be indented again\n *\n * @param code The code\n */\nfunction dedent(code: string): string {\n const lines = code\n .replace(/\\s+$/, \"\")\n .replace(/^\\s*\\n/, \"\")\n .split(\"\\n\");\n const common = Math.min(...lines.filter(l => l.trim()).map(l => /^\\s*/.exec(l)?.[0].length ?? 0));\n return lines.map(l => l.substring(Number.isFinite(common) ? common : 0)).join(\"\\n\");\n}\n\n/**\n * An arrow function executing an action, or null if there is no action\n *\n * @param code The action\n * @param level Indentation level of the line the function starts in\n */\nfunction actionFunction(code: string | undefined, level: number): string | null {\n if (!code?.trim()) {\n return null;\n }\n return `() => {\\n${indent(dedent(code), level + 1)}\\n${INDENT.repeat(level)}}`;\n}\n\n/**\n * Generates the code of a chart\n *\n * @param chart The chart\n * @param chartId ID of the chart object, used for the machine ID like in the runtime\n */\nexport function generateChartCode(chart: Chart, chartId: string): string {\n const structure = new ChartStructure(chart);\n const stateName = (id: string): string => structure.statesById.get(id)?.name ?? id;\n\n /**\n * Parses a label, null if it is invalid or the target is unknown (the runtime ignores these transitions)\n *\n * @param transition The transition\n */\n const parse = (transition: ChartTransition): { label: TransitionLabel } | { error: string } => {\n if (!structure.statesById.has(transition.target)) {\n return { error: \"unknown target\" };\n }\n try {\n return { label: parseTransitionLabel(transition.label) };\n } catch (err) {\n return { error: err.message };\n }\n };\n\n /**\n * @param transition The transition\n * @returns e.g. \"Off -> On: motion[motion]\"\n */\n const describe = (transition: ChartTransition): string =>\n `${stateName(transition.source)} -> ${stateName(transition.target)}${\n transition.label?.trim() ? `: ${oneLine(transition.label)}` : \"\"\n }`;\n\n const lines = [\n `// Code generated from the chart \"${oneLine(chart.name)}\" by the statechart adapter.`,\n \"// It shows how the adapter executes the chart. It is not executed itself, changes here have no effect.\",\n \"\",\n ...(chart.comment?.trim() ? [...commentLines(chart.comment), \"\"] : []),\n ...(chart.notes || []).flatMap(note => [...commentLines(note.text, \"Note: \"), \"\"]),\n 'const { createActor, createMachine } = require(\"xstate\");',\n \"\",\n ];\n\n // variables\n lines.push(\"// ---------- Variables ----------\", \"\");\n const outputs = chart.symbols.filter(s => s.scope === \"output\" && s.stateId);\n if (!chart.symbols.length) {\n lines.push(\"// no variables\");\n }\n for (const symbol of chart.symbols) {\n if (symbol.scope === \"local\") {\n lines.push(`let ${symbol.name} = ${JSON.stringify(symbol.initial) ?? \"undefined\"}; // local`);\n } else if (!symbol.stateId) {\n lines.push(`let ${symbol.name}; // ${symbol.scope} without state`);\n } else if (symbol.scope === \"input\") {\n const trigger = [\n symbol.trigger === \"change\" ? \"on value changes\" : \"on every update\",\n symbol.ack === \"ack\" ? \"only confirmed values (ack = true)\" : \"\",\n symbol.ack === \"command\" ? \"only commands (ack = false)\" : \"\",\n symbol.debounceMs ? `after ${symbol.debounceMs} ms without updates` : \"\",\n ]\n .filter(Boolean)\n .join(\", \");\n lines.push(\n `let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)}); // input, wakes up the chart ${trigger}`,\n );\n } else {\n lines.push(\n `let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)}); // output, see writeChangedOutputs()`,\n );\n }\n }\n if (outputs.length) {\n lines.push(\"\", \"// the last written value of each output\");\n lines.push(`const written = { ${outputs.map(s => s.name).join(\", \")} };`);\n }\n lines.push(\"\");\n\n // function blocks\n for (const fn of chart.functions || []) {\n if (fn.code.trim()) {\n lines.push(\"// ---------- Function block ----------\", \"\", ...commentLines(fn.comment), dedent(fn.code), \"\");\n }\n }\n\n // machine\n lines.push(\n \"// ---------- State machine ----------\",\n \"\",\n \"// The transitions are selected by the process functions below (Stateflow order),\",\n \"// XState only executes them: exit actions, transition action, entry actions.\",\n \"const machine = createMachine({\",\n `${INDENT}id: ${JSON.stringify(`chart_${chartId}`)},`,\n );\n\n const transitionConfig = (\n transition: ChartTransition,\n kind: TransitionKind,\n label: TransitionLabel,\n level: number,\n ): string => {\n const parts = [`target: ${JSON.stringify(`#${transition.target}`)}`];\n if (kind.reenter) {\n parts.push(\"reenter: true\");\n }\n const action = actionFunction(label.action, level);\n if (action) {\n parts.push(`actions: ${action}`);\n }\n return `{ ${parts.join(\", \")} }`;\n };\n\n const buildState = (state: ChartState, level: number): void => {\n const i1 = INDENT.repeat(level);\n const i2 = INDENT.repeat(level + 1);\n const i3 = INDENT.repeat(level + 2);\n lines.push(\n `${i1}// ${oneLine(state.name)}`,\n ...commentLines(state.comment, \"\", i1),\n `${i1}${propertyKey(state.id)}: {`,\n );\n lines.push(`${i2}id: ${JSON.stringify(state.id)},`);\n for (const field of [\"entry\", \"exit\"] as const) {\n const action = actionFunction(state[field], level + 1);\n if (action) {\n lines.push(`${i2}${field}: ${action},`);\n }\n }\n\n const on: string[] = [];\n for (const transition of structure.getTransitions(state.id)) {\n const parsed = parse(transition);\n if (\"error\" in parsed) {\n on.push(`${i3}// ${describe(transition)}: ignored, ${parsed.error}`);\n continue;\n }\n const config = transitionConfig(\n transition,\n structure.getTransitionKind(transition),\n parsed.label,\n level + 2,\n );\n on.push(\n `${i3}// ${describe(transition)}`,\n ...commentLines(transition.comment, \"\", i3),\n `${i3}${JSON.stringify(`T.${transition.id}`)}: ${config},`,\n );\n }\n if (on.length) {\n lines.push(`${i2}on: {`, ...on, `${i2}},`);\n }\n\n const children = structure.getChildren(state.id);\n if (children.length) {\n lines.push(`${i2}initial: ${JSON.stringify(structure.getInitialChild(state.id))},`, `${i2}states: {`);\n for (const child of children) {\n buildState(child, level + 2);\n }\n lines.push(`${i2}},`);\n }\n lines.push(`${i1}},`);\n };\n\n const topLevel = structure.getChildren(null);\n if (topLevel.length) {\n lines.push(`${INDENT}initial: ${JSON.stringify(structure.getInitialChild(null))},`, `${INDENT}states: {`);\n for (const state of topLevel) {\n buildState(state, 2);\n }\n lines.push(`${INDENT}},`);\n }\n lines.push(\n \"});\",\n \"\",\n \"const actor = createActor(machine);\",\n \"actor.start();\",\n \"// once right after the start, so transitions without event are taken without waiting for an input\",\n \"wakeup(null);\",\n \"\",\n );\n\n // wakeup and process functions\n /**\n * @param states The states which may be active\n * @param level Indentation level\n * @param prefix \"return \" inside process functions\n */\n const callActive = (states: ChartState[], level: number, prefix: string): string[] =>\n states.map(\n s =>\n `${INDENT.repeat(level)}if (isActive(${JSON.stringify(s.id)})) {\\n` +\n `${INDENT.repeat(level + 1)}${prefix}process_${identifier(s.id)}(input);\\n` +\n `${INDENT.repeat(level)}}`,\n );\n\n lines.push(\n \"// ---------- Wakeup ----------\",\n \"\",\n \"/**\",\n \" * Called once for every change of an input, after its variable got the new value,\",\n \" * when the time of an after(...) of an active state has come, and once after the start\",\n \" * (input is null for the last two).\",\n \" * Starting with the outermost active state, each active state is processed, see process_...().\",\n \" *\",\n \" * @param {string | null} input name of the changed input\",\n \" */\",\n \"function wakeup(input) {\",\n ...(chart.superStep\n ? [\n `${INDENT}// super step: take transitions until none is valid anymore, at most ${MAX_SUPER_STEPS}.`,\n `${INDENT}// The event of the input is only present in the first step.`,\n `${INDENT}for (let steps = 0; steps < ${MAX_SUPER_STEPS} && step(input); steps++) {`,\n `${INDENT}${INDENT}input = null;`,\n `${INDENT}}`,\n ]\n : [`${INDENT}step(input);`]),\n `${INDENT}writeChangedOutputs();`,\n \"}\",\n \"\",\n \"/**\",\n \" * Processes the active states once\",\n \" *\",\n \" * @param {string | null} input name of the changed input, null if the step has no event\",\n \" * @returns {boolean} true if a transition was taken\",\n \" */\",\n \"function step(input) {\",\n // only one state of the top level is active\n ...callActive(topLevel, 1, \"return \"),\n `${INDENT}return false;`,\n \"}\",\n \"\",\n );\n\n /**\n * A check of a transition in a process function\n *\n * @param transition The transition\n * @param label Its parsed label\n */\n const check = (transition: ChartTransition, label: TransitionLabel): string[] => {\n const conditions: string[] = [];\n if (label.event) {\n conditions.push(`input === ${JSON.stringify(label.event)}`);\n }\n if (label.afterMs !== undefined) {\n // valid from the moment on, not only when the timer expires\n conditions.push(`elapsed(${JSON.stringify(transition.source)}) >= ${label.afterMs}`);\n }\n if (label.condition) {\n conditions.push(`(${label.condition})`);\n }\n return [\n `${INDENT}// ${describe(transition)}`,\n ...commentLines(transition.comment, \"\", INDENT),\n `${INDENT}if (${conditions.join(\" && \") || \"true\"}) {`,\n `${INDENT}${INDENT}actor.send({ type: ${JSON.stringify(`T.${transition.id}`)} });`,\n `${INDENT}${INDENT}return true;`,\n `${INDENT}}`,\n ];\n };\n\n for (const state of chart.states) {\n const outer: string[] = [];\n const inner: string[] = [];\n for (const transition of structure.getTransitions(state.id)) {\n const parsed = parse(transition);\n if (\"error\" in parsed) {\n continue;\n }\n (structure.getTransitionKind(transition).inner ? inner : outer).push(...check(transition, parsed.label));\n }\n const children = structure.getChildren(state.id);\n lines.push(\n \"/**\",\n ` * ${oneLine(state.name)}`,\n ...(state.comment?.trim()\n ? [\n \" *\",\n // \"*/\" would end the comment\n ...state.comment\n .trim()\n .split(\"\\n\")\n .map(line => ` * ${line.trimEnd().replace(/\\*\\//g, \"* /\")}`.trimEnd()),\n ]\n : []),\n \" *\",\n \" * @param {string | null} input name of the changed input, null for timers\",\n \" * @returns {boolean} true if a transition was taken\",\n \" */\",\n `function process_${identifier(state.id)}(input) {`,\n `${INDENT}// 1. transitions leaving the state`,\n ...(outer.length ? outer : [`${INDENT}// none`]),\n `${INDENT}// 2. during action`,\n state.during?.trim() ? `${INDENT}{\\n${indent(dedent(state.during), 2)}\\n${INDENT}}` : `${INDENT}// none`,\n `${INDENT}// 3. inner transitions (to own sub states, the state stays active)`,\n ...(inner.length ? inner : [`${INDENT}// none`]),\n `${INDENT}// 4. active sub state`,\n ...(children.length ? callActive(children, 1, \"return \") : [`${INDENT}// none`]),\n `${INDENT}return false;`,\n \"}\",\n \"\",\n );\n }\n\n // helpers\n lines.push(\n \"// ---------- Helpers ----------\",\n \"\",\n \"/** Writes every output whose value was changed by an action */\",\n \"function writeChangedOutputs() {\",\n ...outputs.map(\n s =>\n `${INDENT}if (${s.name} !== written.${s.name}) {\\n` +\n `${INDENT}${INDENT}written.${s.name} = ${s.name};\\n` +\n `${INDENT}${INDENT}setState(${JSON.stringify(s.stateId)}, ${s.name});\\n` +\n `${INDENT}}`,\n ),\n \"}\",\n \"\",\n \"// Provided by the adapter:\",\n \"// getState(id) current value of an ioBroker state\",\n \"// isActive(stateId) true if the state of the chart is active\",\n \"// elapsed(stateId) milliseconds since the state was entered; when it reaches the delay of an\",\n \"// after(...) of the state, a timer calls wakeup(null)\",\n \"// At the start of each wakeup, the adapter stores the values of the variables used in hasChanged(),\",\n \"// hasChangedFrom() and hasChangedTo(), these compare them with the values of the previous wakeup.\",\n \"//\",\n \"// Helper functions for conditions, actions and function blocks:\",\n ...Object.values(HELPERS).map(helper => `// ${helper.signature}\\n// ${helper.description}`),\n \"//\",\n \"// The adapter stores the active states, the times they were entered and the locals in the state\",\n \"// charts.<chart>.snapshot. After a restart of the adapter it continues with them, without executing the\",\n \"// entry actions again, if the chart was not changed meanwhile. Then it wakes up once, like after a start.\",\n \"\",\n );\n return lines.join(\"\\n\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,2BAAwB;AACxB,yBAAsD;AAEtD,6BAA+
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["/*\n * Generates readable JavaScript from a chart. It shows how the runtime executes the chart:\n * the XState machine, and the functions which select the transitions in Stateflow order.\n * The code is only shown to the user, the runtime does not execute it.\n */\n\nimport { HELPERS } from \"./chart-helpers\";\nimport { MAX_SUPER_STEPS, parseTransitionLabel } from \"./chart-model\";\nimport type { Chart, ChartState, ChartTransition, TemporalExpression, TransitionLabel } from \"./chart-model\";\nimport { ChartStructure, HISTORY_SUFFIX } from \"./chart-structure\";\nimport type { TransitionKind } from \"./chart-structure\";\n\nconst INDENT = \" \";\n\nfunction indent(text: string, level: number): string {\n const prefix = INDENT.repeat(level);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? prefix + line : \"\"))\n .join(\"\\n\");\n}\n\n/**\n * Text for a // comment, on one line\n *\n * @param text The text, may have several lines\n */\nfunction oneLine(text: string | undefined): string {\n return (text || \"\").replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * A comment or note as // lines\n *\n * @param text The comment\n * @param prefix Indentation and optional text before the first line, e.g. \"Note: \"\n * @param indentation Added before each line\n * @returns no lines for an empty text\n */\nfunction commentLines(text: string | undefined, prefix = \"\", indentation = \"\"): string[] {\n if (!text?.trim()) {\n return [];\n }\n return text\n .trim()\n .split(\"\\n\")\n .map((line, i) => `${indentation}// ${i ? \" \".repeat(prefix.length) : prefix}${line.trimEnd()}`.trimEnd());\n}\n\n/**\n * Converts a state ID to a valid identifier for the names of the generated functions\n *\n * @param id ID of the state\n */\nfunction identifier(id: string): string {\n const name = id.replace(/[^\\w$]/g, \"_\");\n return /^\\d/.test(name) ? `_${name}` : name;\n}\n\n/**\n * @param key The property name\n * @returns the key for an object literal, in quotes only if necessary\n */\nfunction propertyKey(key: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(key) ? key : JSON.stringify(key);\n}\n\n/**\n * Removes the indentation all lines have in common, so the code can be indented again\n *\n * @param code The code\n */\nfunction dedent(code: string): string {\n const lines = code\n .replace(/\\s+$/, \"\")\n .replace(/^\\s*\\n/, \"\")\n .split(\"\\n\");\n const common = Math.min(...lines.filter(l => l.trim()).map(l => /^\\s*/.exec(l)?.[0].length ?? 0));\n return lines.map(l => l.substring(Number.isFinite(common) ? common : 0)).join(\"\\n\");\n}\n\n/**\n * An arrow function executing an action, or null if there is no action\n *\n * @param code The action\n * @param level Indentation level of the line the function starts in\n */\nfunction actionFunction(code: string | undefined, level: number): string | null {\n if (!code?.trim()) {\n return null;\n }\n return `() => {\\n${indent(dedent(code), level + 1)}\\n${INDENT.repeat(level)}}`;\n}\n\n/**\n * Generates the code of a chart\n *\n * @param chart The chart\n * @param chartId ID of the chart object, used for the machine ID like in the runtime\n */\nexport function generateChartCode(chart: Chart, chartId: string): string {\n const structure = new ChartStructure(chart);\n const stateName = (id: string): string => structure.statesById.get(id)?.name ?? id;\n\n /**\n * Parses a label, null if it is invalid or the target is unknown (the runtime ignores these transitions)\n *\n * @param transition The transition\n */\n const parse = (transition: ChartTransition): { label: TransitionLabel } | { error: string } => {\n if (!structure.statesById.has(transition.target)) {\n return { error: \"unknown target\" };\n }\n try {\n return { label: parseTransitionLabel(transition.label) };\n } catch (err) {\n return { error: err.message };\n }\n };\n\n /**\n * @param transition The transition\n * @returns e.g. \"Off -> On: motion[motion]\"\n */\n const describe = (transition: ChartTransition): string =>\n `${stateName(transition.source)} -> ${stateName(transition.target)}${\n transition.label?.trim() ? `: ${oneLine(transition.label)}` : \"\"\n }`;\n\n const lines = [\n `// Code generated from the chart \"${oneLine(chart.name)}\" by the statechart adapter.`,\n \"// It shows how the adapter executes the chart. It is not executed itself, changes here have no effect.\",\n \"\",\n ...(chart.comment?.trim() ? [...commentLines(chart.comment), \"\"] : []),\n ...(chart.notes || []).flatMap(note => [...commentLines(note.text, \"Note: \"), \"\"]),\n 'const { createActor, createMachine } = require(\"xstate\");',\n \"\",\n ];\n\n // variables\n lines.push(\"// ---------- Variables ----------\", \"\");\n const outputs = chart.symbols.filter(s => s.scope === \"output\" && s.stateId);\n if (!chart.symbols.length) {\n lines.push(\"// no variables\");\n }\n for (const symbol of chart.symbols) {\n if (symbol.scope === \"local\") {\n lines.push(`let ${symbol.name} = ${JSON.stringify(symbol.initial) ?? \"undefined\"}; // local`);\n } else if (!symbol.stateId) {\n lines.push(`let ${symbol.name}; // ${symbol.scope} without state`);\n } else if (symbol.scope === \"input\") {\n const trigger = [\n symbol.trigger === \"change\" ? \"on value changes\" : \"on every update\",\n symbol.ack === \"ack\" ? \"only confirmed values (ack = true)\" : \"\",\n symbol.ack === \"command\" ? \"only commands (ack = false)\" : \"\",\n symbol.debounceMs ? `after ${symbol.debounceMs} ms without updates` : \"\",\n ]\n .filter(Boolean)\n .join(\", \");\n lines.push(\n `let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)})?.val; // input, wakes up the chart ${trigger}`,\n );\n } else {\n lines.push(\n `let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)})?.val; // output, see writeChangedOutputs()`,\n );\n }\n }\n if (outputs.length) {\n lines.push(\"\", \"// the last written value of each output\");\n lines.push(`const written = { ${outputs.map(s => s.name).join(\", \")} };`);\n }\n lines.push(\"\");\n\n // function blocks\n for (const fn of chart.functions || []) {\n if (fn.code.trim()) {\n lines.push(\"// ---------- Function block ----------\", \"\", ...commentLines(fn.comment), dedent(fn.code), \"\");\n }\n }\n\n // machine\n lines.push(\n \"// ---------- State machine ----------\",\n \"\",\n \"// The transitions are selected by the process functions below (Stateflow order),\",\n \"// XState only executes them: exit actions, transition action, entry actions.\",\n \"const machine = createMachine({\",\n `${INDENT}id: ${JSON.stringify(`chart_${chartId}`)},`,\n );\n\n const transitionConfig = (\n transition: ChartTransition,\n kind: TransitionKind,\n label: TransitionLabel,\n level: number,\n ): string => {\n const parts = [`target: ${JSON.stringify(`#${structure.getTargetId(transition)}`)}`];\n if (kind.reenter) {\n parts.push(\"reenter: true\");\n }\n const action = actionFunction(label.action, level);\n if (action) {\n parts.push(`actions: ${action}`);\n }\n return `{ ${parts.join(\", \")} }`;\n };\n\n const buildState = (state: ChartState, level: number): void => {\n const i1 = INDENT.repeat(level);\n const i2 = INDENT.repeat(level + 1);\n const i3 = INDENT.repeat(level + 2);\n lines.push(\n `${i1}// ${oneLine(state.name)}`,\n ...commentLines(state.comment, \"\", i1),\n `${i1}${propertyKey(state.id)}: {`,\n );\n lines.push(`${i2}id: ${JSON.stringify(state.id)},`);\n for (const field of [\"entry\", \"exit\"] as const) {\n const action = actionFunction(state[field], level + 1);\n if (action) {\n lines.push(`${i2}${field}: ${action},`);\n }\n }\n\n const on: string[] = [];\n for (const transition of structure.getTransitions(state.id)) {\n const parsed = parse(transition);\n if (\"error\" in parsed) {\n on.push(`${i3}// ${describe(transition)}: ignored, ${parsed.error}`);\n continue;\n }\n const config = transitionConfig(\n transition,\n structure.getTransitionKind(transition),\n parsed.label,\n level + 2,\n );\n on.push(\n `${i3}// ${describe(transition)}`,\n ...commentLines(transition.comment, \"\", i3),\n `${i3}${JSON.stringify(`T.${transition.id}`)}: ${config},`,\n );\n }\n if (on.length) {\n lines.push(`${i2}on: {`, ...on, `${i2}},`);\n }\n\n const children = structure.getChildren(state.id);\n if (children.length) {\n lines.push(\n structure.isParallel(state.id)\n ? `${i2}type: \"parallel\", // all sub states are active, entered in their execution order`\n : `${i2}initial: ${JSON.stringify(structure.getInitialChild(state.id))},`,\n `${i2}states: {`,\n );\n for (const child of children) {\n buildState(child, level + 2);\n }\n if (structure.hasHistory(state.id)) {\n const id = `${state.id}${HISTORY_SUFFIX}`;\n lines.push(\n `${i3}// history junction: returns to the last active sub state, the first time to the initial one`,\n `${i3}${JSON.stringify(HISTORY_SUFFIX)}: { id: ${JSON.stringify(id)}, type: \"history\" },`,\n );\n }\n lines.push(`${i2}},`);\n }\n lines.push(`${i1}},`);\n };\n\n const topLevel = structure.getChildren(null);\n if (topLevel.length) {\n lines.push(\n structure.isParallel(null)\n ? `${INDENT}type: \"parallel\", // all top level states are active, entered in their execution order`\n : `${INDENT}initial: ${JSON.stringify(structure.getInitialChild(null))},`,\n `${INDENT}states: {`,\n );\n for (const state of topLevel) {\n buildState(state, 2);\n }\n lines.push(`${INDENT}},`);\n }\n lines.push(\n \"});\",\n \"\",\n \"const actor = createActor(machine);\",\n \"actor.start();\",\n \"// once right after the start, so transitions without event are taken without waiting for an input\",\n \"wakeup(null);\",\n \"\",\n );\n\n // wakeup and process functions\n /**\n * @param states The states which may be active\n * @param level Indentation level\n * @param prefix \"return \" inside process functions\n */\n const callActive = (states: ChartState[], level: number, prefix: string): string[] =>\n states.map(\n s =>\n `${INDENT.repeat(level)}if (isActive(${JSON.stringify(s.id)})) {\\n` +\n `${INDENT.repeat(level + 1)}${prefix}process_${identifier(s.id)}(input);\\n` +\n `${INDENT.repeat(level)}}`,\n );\n\n /**\n * Processes the active child of a state, or all children of a parallel state\n *\n * @param parent ID of the state, null for the top level\n * @param children The children\n * @returns lines of a process function, with indentation level 1\n */\n const processChildren = (parent: string | null, children: ChartState[]): string[] => {\n if (!structure.isParallel(parent)) {\n return [...callActive(children, 1, \"return \"), `${INDENT}return false;`];\n }\n const lines = [\n `${INDENT}// all sub states are active (parallel), they are processed in their execution order.`,\n `${INDENT}// A transition in one of them does not stop the others, unless it left this state.`,\n ...(parent ? [`${INDENT}const entries = entryCount(${JSON.stringify(parent)});`] : []),\n `${INDENT}let taken = false;`,\n ];\n children.forEach((child, i) => {\n if (i && parent) {\n lines.push(\n `${INDENT}if (!isActive(${JSON.stringify(parent)}) || entryCount(${JSON.stringify(parent)}) !== entries) {`,\n `${INDENT}${INDENT}return true; // left (and maybe entered again) by the transition`,\n `${INDENT}}`,\n );\n }\n lines.push(`${INDENT}taken = process_${identifier(child.id)}(input) || taken;`);\n });\n lines.push(`${INDENT}return taken;`);\n return lines;\n };\n\n lines.push(\n \"// ---------- Wakeup ----------\",\n \"\",\n \"/**\",\n \" * Called once for every change of an input, after its variable got the new value,\",\n \" * when the time of an after(...) of an active state has come, and once after the start\",\n \" * (input is null for the last two).\",\n \" * Starting with the outermost active state, each active state is processed, see process_...().\",\n \" *\",\n \" * @param {string | null} input name of the changed input\",\n \" */\",\n \"function wakeup(input) {\",\n ...(chart.superStep\n ? [\n `${INDENT}// super step: take transitions until none is valid anymore, at most ${MAX_SUPER_STEPS}.`,\n `${INDENT}// The event of the input is only present in the first step.`,\n `${INDENT}for (let steps = 0; steps < ${MAX_SUPER_STEPS} && step(input); steps++) {`,\n `${INDENT}${INDENT}input = null;`,\n `${INDENT}}`,\n ]\n : [`${INDENT}step(input);`]),\n `${INDENT}writeChangedOutputs();`,\n \"}\",\n \"\",\n \"/**\",\n \" * Processes the active states once\",\n \" *\",\n \" * @param {string | null} input name of the changed input, null if the step has no event\",\n \" * @returns {boolean} true if a transition was taken\",\n \" */\",\n \"function step(input) {\",\n ...processChildren(null, topLevel),\n \"}\",\n \"\",\n );\n\n /**\n * The check of a temporal expression, see the helpers provided by the adapter at the end of the code\n *\n * @param transition The transition\n * @param temporal Its temporal expression\n */\n const temporalCheck = (transition: ChartTransition, temporal: TemporalExpression): string => {\n const id = JSON.stringify(transition.id);\n const source = JSON.stringify(transition.source);\n if (temporal.event !== undefined) {\n const event = JSON.stringify(temporal.event);\n const count = `inputCount(${source}, ${event})`;\n const checks = {\n after: `${count} >= ${temporal.count}`,\n before: `${count} < ${temporal.count}`,\n at: `${count} === ${temporal.count}`,\n every: `${count} % ${temporal.count} === 0`,\n };\n return `input === ${event} && ${checks[temporal.operator]}`;\n }\n if (temporal.condition !== undefined) {\n return `trueFor(${id}) >= ${temporal.ms}`;\n }\n switch (temporal.operator) {\n case \"after\":\n // valid from the moment on, not only when the timer expires\n return `timeInState(${source}) >= ${temporal.ms}`;\n case \"before\":\n return `timeInState(${source}) < ${temporal.ms}`;\n default:\n return `timerFired(${id})`;\n }\n };\n\n /**\n * A check of a transition in a process function\n *\n * @param transition The transition\n * @param label Its parsed label\n */\n const check = (transition: ChartTransition, label: TransitionLabel): string[] => {\n const conditions: string[] = [];\n if (label.event) {\n conditions.push(`input === ${JSON.stringify(label.event)}`);\n }\n if (label.temporal) {\n conditions.push(temporalCheck(transition, label.temporal));\n }\n if (label.condition) {\n conditions.push(`(${label.condition})`);\n }\n return [\n `${INDENT}// ${describe(transition)}`,\n ...commentLines(transition.comment, \"\", INDENT),\n `${INDENT}if (${conditions.join(\" && \") || \"true\"}) {`,\n `${INDENT}${INDENT}actor.send({ type: ${JSON.stringify(`T.${transition.id}`)} });`,\n `${INDENT}${INDENT}return true;`,\n `${INDENT}}`,\n ];\n };\n\n for (const state of chart.states) {\n const outer: string[] = [];\n const inner: string[] = [];\n for (const transition of structure.getTransitions(state.id)) {\n const parsed = parse(transition);\n if (\"error\" in parsed) {\n continue;\n }\n (structure.getTransitionKind(transition).inner ? inner : outer).push(...check(transition, parsed.label));\n }\n const children = structure.getChildren(state.id);\n lines.push(\n \"/**\",\n ` * ${oneLine(state.name)}`,\n ...(state.comment?.trim()\n ? [\n \" *\",\n // \"*/\" would end the comment\n ...state.comment\n .trim()\n .split(\"\\n\")\n .map(line => ` * ${line.trimEnd().replace(/\\*\\//g, \"* /\")}`.trimEnd()),\n ]\n : []),\n \" *\",\n \" * @param {string | null} input name of the changed input, null for timers\",\n \" * @returns {boolean} true if a transition was taken\",\n \" */\",\n `function process_${identifier(state.id)}(input) {`,\n `${INDENT}// 1. transitions leaving the state`,\n ...(outer.length ? outer : [`${INDENT}// none`]),\n `${INDENT}// 2. during action`,\n state.during?.trim() ? `${INDENT}{\\n${indent(dedent(state.during), 2)}\\n${INDENT}}` : `${INDENT}// none`,\n `${INDENT}// 3. inner transitions (to own sub states, the state stays active)`,\n ...(inner.length ? inner : [`${INDENT}// none`]),\n `${INDENT}// 4. ${structure.isParallel(state.id) && children.length ? \"all sub states\" : \"active sub state\"}`,\n ...(children.length ? processChildren(state.id, children) : [`${INDENT}// none`, `${INDENT}return false;`]),\n \"}\",\n \"\",\n );\n }\n\n // helpers\n lines.push(\n \"// ---------- Helpers ----------\",\n \"\",\n \"/** Writes every output whose value was changed by an action */\",\n \"function writeChangedOutputs() {\",\n ...outputs.map(\n s =>\n `${INDENT}if (${s.name} !== written.${s.name}) {\\n` +\n `${INDENT}${INDENT}written.${s.name} = ${s.name};\\n` +\n `${INDENT}${INDENT}setState(${JSON.stringify(s.stateId)}, ${s.name});\\n` +\n `${INDENT}}`,\n ),\n \"}\",\n \"\",\n \"// Provided by the adapter:\",\n \"// isActive(stateId) true if the state of the chart is active\",\n \"// entryCount(stateId) how often the state was entered\",\n \"// timeInState(stateId) milliseconds since the state was entered; when it reaches the delay of an\",\n \"// after(n, unit) or at(n, unit) of the state, a timer calls wakeup(null)\",\n '// timerFired(id) true in the wakeup(null) of the timer of at(n, unit), every(n, unit) or at(\"sunset\")',\n '// of the transition; at(\"sunset\", offset) and at(\"22:30\") have a timer for every day',\n \"// inputCount(stateId, input)\",\n \"// the wakeups by the input since the state was entered, for e.g. after(3, button)\",\n \"// trueFor(id) milliseconds the condition of after(n, unit, condition) of the transition has been true,\",\n \"// checked at the start and at the end of every wakeup; a timer calls wakeup(null) when\",\n \"// it reaches the delay\",\n \"// At the start of each wakeup, the adapter stores the values of the variables used in hasChanged(),\",\n \"// hasChangedFrom() and hasChangedTo(), these compare them with the values of the previous wakeup.\",\n \"//\",\n \"// Helper functions for conditions, actions and function blocks:\",\n ...Object.values(HELPERS).map(helper => `// ${helper.signature}\\n// ${helper.description}`),\n \"//\",\n \"// The adapter stores the active states, the times they were entered and the locals in the state\",\n \"// charts.<chart>.snapshot. After a restart of the adapter it continues with them, without executing the\",\n \"// entry actions again, if the chart was not changed meanwhile. Then it wakes up once, like after a start.\",\n \"\",\n );\n return lines.join(\"\\n\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["lines"]
|
|
7
7
|
}
|
|
@@ -53,6 +53,18 @@ const HELPERS = {
|
|
|
53
53
|
signature: 'astroTime("sunset", offsetMinutes = 0)',
|
|
54
54
|
description: "Time of an astro event today: sunrise, sunset, dawn, dusk, solarNoon, nauticalDawn, nauticalDusk, goldenHour, goldenHourEnd, night, nightEnd"
|
|
55
55
|
},
|
|
56
|
+
getState: {
|
|
57
|
+
signature: 'getState("0_userdata.0.temperature")',
|
|
58
|
+
description: "Reads any ioBroker state: { val, ack, ts, lc }, null if it does not exist. The ID must be written as text. Unlike inputs, the state does not wake up the chart"
|
|
59
|
+
},
|
|
60
|
+
elapsed: {
|
|
61
|
+
signature: "elapsed(sec)",
|
|
62
|
+
description: "Time since the state was entered (for transitions: the source state), in sec (default), msec or min"
|
|
63
|
+
},
|
|
64
|
+
duration: {
|
|
65
|
+
signature: "duration(condition, sec)",
|
|
66
|
+
description: "Time the condition has been true without interruption, measured on the wakeups, in sec (default), msec or min. Does not wake up the chart, see after(n, unit, condition)"
|
|
67
|
+
},
|
|
56
68
|
hasChanged: {
|
|
57
69
|
signature: "hasChanged(variable)",
|
|
58
70
|
description: "true if the value of the variable at the start of this wakeup differs from the value at the start of the previous wakeup"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/chart-helpers.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Helper functions which can be used in conditions, actions and function blocks.\n * The descriptions are shared by the editor (completion), the validation and the code generator,\n * the runtime implements them (see ChartRuntime.createHelpers()).\n */\n\nexport interface HelperDescription {\n signature: string;\n description: string;\n}\n\nexport const HELPERS: Record<string, HelperDescription> = {\n log: {\n signature: 'log(message, level = \"info\")',\n description: 'Writes a message to the ioBroker log, level \"debug\", \"info\", \"warn\" or \"error\"',\n },\n setState: {\n signature: \"setState(id, value, ack = false)\",\n description: \"Writes a value to any ioBroker state\",\n },\n setStateDelayed: {\n signature: \"setStateDelayed(id, value, delayMs, ack = false)\",\n description: \"Writes a value after a delay, cancelled when the chart stops\",\n },\n sendTo: {\n signature: \"sendTo(instance, command, message)\",\n description: 'Sends a message to an adapter, e.g. sendTo(\"telegram.0\", \"send\", { text: \"Hello\" })',\n },\n isTimeBetween: {\n signature: 'isTimeBetween(\"22:00\", \"06:00\")',\n description: \"true if the current time is in the range, also over midnight\",\n },\n isDaytime: {\n signature: \"isDaytime()\",\n description: \"true between sunrise and sunset, at the location of the ioBroker system settings\",\n },\n astroTime: {\n signature: 'astroTime(\"sunset\", offsetMinutes = 0)',\n description:\n \"Time of an astro event today: sunrise, sunset, dawn, dusk, solarNoon, nauticalDawn, nauticalDusk, goldenHour, goldenHourEnd, night, nightEnd\",\n },\n hasChanged: {\n signature: \"hasChanged(variable)\",\n description:\n \"true if the value of the variable at the start of this wakeup differs from the value at the start of the previous wakeup\",\n },\n hasChangedFrom: {\n signature: \"hasChangedFrom(variable, value)\",\n description: \"true if the variable has changed (see hasChanged) and its previous value was the given value\",\n },\n hasChangedTo: {\n signature: \"hasChangedTo(variable, value)\",\n description:\n \"true if the variable has changed (see hasChanged) to the given value, e.g. hasChangedTo(button, true)\",\n },\n};\n\n/**\n * The helpers of the change detection. Their first argument is a variable of the chart, the runtime passes its\n * name instead of its value, see quoteChangeArguments().\n */\nexport const CHANGE_HELPERS = new Set([\"hasChanged\", \"hasChangedFrom\", \"hasChangedTo\"]);\n\n/**\n * @param time \"HH:mm\" or \"HH:mm:ss\"\n * @returns seconds since midnight\n * @throws {Error} if the time is invalid\n */\nexport function parseTime(time: string): number {\n const match = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/.exec(String(time).trim());\n if (!match || Number(match[1]) > 23 || Number(match[2]) > 59 || Number(match[3] ?? 0) > 59) {\n throw new Error(`Invalid time \"${time}\", expected e.g. \"22:30\"`);\n }\n return Number(match[1]) * 3600 + Number(match[2]) * 60 + Number(match[3] ?? 0);\n}\n\n/**\n * @param start \"HH:mm\", inclusive\n * @param end \"HH:mm\", exclusive. A range over midnight ends on the next day.\n * @param now The time to check\n */\nexport function isTimeBetween(start: string, end: string, now = new Date()): boolean {\n const from = parseTime(start);\n const to = parseTime(end);\n const current = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();\n return from <= to ? current >= from && current < to : current >= from || current < to;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/*\n * Helper functions which can be used in conditions, actions and function blocks.\n * The descriptions are shared by the editor (completion), the validation and the code generator,\n * the runtime implements them (see ChartRuntime.createHelpers()).\n */\n\n/** A helper function as it is shown in the completion of the code editor */\nexport interface HelperDescription {\n /** How it is called, e.g. \"isTimeBetween(from, to)\" */\n signature: string;\n /** What it does */\n description: string;\n}\n\nexport const HELPERS: Record<string, HelperDescription> = {\n log: {\n signature: 'log(message, level = \"info\")',\n description: 'Writes a message to the ioBroker log, level \"debug\", \"info\", \"warn\" or \"error\"',\n },\n setState: {\n signature: \"setState(id, value, ack = false)\",\n description: \"Writes a value to any ioBroker state\",\n },\n setStateDelayed: {\n signature: \"setStateDelayed(id, value, delayMs, ack = false)\",\n description: \"Writes a value after a delay, cancelled when the chart stops\",\n },\n sendTo: {\n signature: \"sendTo(instance, command, message)\",\n description: 'Sends a message to an adapter, e.g. sendTo(\"telegram.0\", \"send\", { text: \"Hello\" })',\n },\n isTimeBetween: {\n signature: 'isTimeBetween(\"22:00\", \"06:00\")',\n description: \"true if the current time is in the range, also over midnight\",\n },\n isDaytime: {\n signature: \"isDaytime()\",\n description: \"true between sunrise and sunset, at the location of the ioBroker system settings\",\n },\n astroTime: {\n signature: 'astroTime(\"sunset\", offsetMinutes = 0)',\n description:\n \"Time of an astro event today: sunrise, sunset, dawn, dusk, solarNoon, nauticalDawn, nauticalDusk, goldenHour, goldenHourEnd, night, nightEnd\",\n },\n getState: {\n signature: 'getState(\"0_userdata.0.temperature\")',\n description:\n \"Reads any ioBroker state: { val, ack, ts, lc }, null if it does not exist. The ID must be written as text. Unlike inputs, the state does not wake up the chart\",\n },\n elapsed: {\n signature: \"elapsed(sec)\",\n description:\n \"Time since the state was entered (for transitions: the source state), in sec (default), msec or min\",\n },\n duration: {\n signature: \"duration(condition, sec)\",\n description:\n \"Time the condition has been true without interruption, measured on the wakeups, in sec (default), msec or min. Does not wake up the chart, see after(n, unit, condition)\",\n },\n hasChanged: {\n signature: \"hasChanged(variable)\",\n description:\n \"true if the value of the variable at the start of this wakeup differs from the value at the start of the previous wakeup\",\n },\n hasChangedFrom: {\n signature: \"hasChangedFrom(variable, value)\",\n description: \"true if the variable has changed (see hasChanged) and its previous value was the given value\",\n },\n hasChangedTo: {\n signature: \"hasChangedTo(variable, value)\",\n description:\n \"true if the variable has changed (see hasChanged) to the given value, e.g. hasChangedTo(button, true)\",\n },\n};\n\n/**\n * The helpers of the change detection. Their first argument is a variable of the chart, the runtime passes its\n * name instead of its value, see quoteChangeArguments().\n */\nexport const CHANGE_HELPERS = new Set([\"hasChanged\", \"hasChangedFrom\", \"hasChangedTo\"]);\n\n/**\n * @param time \"HH:mm\" or \"HH:mm:ss\"\n * @returns seconds since midnight\n * @throws {Error} if the time is invalid\n */\nexport function parseTime(time: string): number {\n const match = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/.exec(String(time).trim());\n if (!match || Number(match[1]) > 23 || Number(match[2]) > 59 || Number(match[3] ?? 0) > 59) {\n throw new Error(`Invalid time \"${time}\", expected e.g. \"22:30\"`);\n }\n return Number(match[1]) * 3600 + Number(match[2]) * 60 + Number(match[3] ?? 0);\n}\n\n/**\n * @param start \"HH:mm\", inclusive\n * @param end \"HH:mm\", exclusive. A range over midnight ends on the next day.\n * @param now The time to check\n */\nexport function isTimeBetween(start: string, end: string, now = new Date()): boolean {\n const from = parseTime(start);\n const to = parseTime(end);\n const current = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();\n return from <= to ? current >= from && current < to : current >= from || current < to;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcO,MAAM,UAA6C;AAAA,EACtD,KAAK;AAAA,IACD,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,UAAU;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,iBAAiB;AAAA,IACb,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,QAAQ;AAAA,IACJ,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,eAAe;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,IACP,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,IACP,WAAW;AAAA,IACX,aACI;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACN,WAAW;AAAA,IACX,aACI;AAAA,EACR;AAAA,EACA,SAAS;AAAA,IACL,WAAW;AAAA,IACX,aACI;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACN,WAAW;AAAA,IACX,aACI;AAAA,EACR;AAAA,EACA,YAAY;AAAA,IACR,WAAW;AAAA,IACX,aACI;AAAA,EACR;AAAA,EACA,gBAAgB;AAAA,IACZ,WAAW;AAAA,IACX,aAAa;AAAA,EACjB;AAAA,EACA,cAAc;AAAA,IACV,WAAW;AAAA,IACX,aACI;AAAA,EACR;AACJ;AAMO,MAAM,iBAAiB,oBAAI,IAAI,CAAC,cAAc,kBAAkB,cAAc,CAAC;AAO/E,SAAS,UAAU,MAAsB;AAC5C,QAAM,QAAQ,mCAAmC,KAAK,OAAO,IAAI,EAAE,KAAK,CAAC;AACzE,MAAI,CAAC,SAAS,OAAO,MAAM,CAAC,CAAC,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC,IAAI,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI;AACxF,UAAM,IAAI,MAAM,iBAAiB,IAAI,0BAA0B;AAAA,EACnE;AACA,SAAO,OAAO,MAAM,CAAC,CAAC,IAAI,OAAO,OAAO,MAAM,CAAC,CAAC,IAAI,KAAK,OAAO,MAAM,CAAC,KAAK,CAAC;AACjF;AAOO,SAAS,cAAc,OAAe,KAAa,MAAM,oBAAI,KAAK,GAAY;AACjF,QAAM,OAAO,UAAU,KAAK;AAC5B,QAAM,KAAK,UAAU,GAAG;AACxB,QAAM,UAAU,IAAI,SAAS,IAAI,OAAO,IAAI,WAAW,IAAI,KAAK,IAAI,WAAW;AAC/E,SAAO,QAAQ,KAAK,WAAW,QAAQ,UAAU,KAAK,WAAW,QAAQ,UAAU;AACvF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/lib/chart-model.js
CHANGED
|
@@ -18,10 +18,15 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var chart_model_exports = {};
|
|
20
20
|
__export(chart_model_exports, {
|
|
21
|
+
ASTRO_EVENTS: () => ASTRO_EVENTS,
|
|
21
22
|
CHART_MODEL_VERSION: () => CHART_MODEL_VERSION,
|
|
23
|
+
COLOR_PATTERN: () => COLOR_PATTERN,
|
|
22
24
|
EXPORT_FORMAT: () => EXPORT_FORMAT,
|
|
23
25
|
LabelSyntaxError: () => LabelSyntaxError,
|
|
24
26
|
MAX_SUPER_STEPS: () => MAX_SUPER_STEPS,
|
|
27
|
+
TEMPORAL_OPERATORS: () => TEMPORAL_OPERATORS,
|
|
28
|
+
TIME_OF_DAY: () => TIME_OF_DAY,
|
|
29
|
+
TIME_UNITS: () => TIME_UNITS,
|
|
25
30
|
createChart: () => createChart,
|
|
26
31
|
createExport: () => createExport,
|
|
27
32
|
formatMessage: () => formatMessage,
|
|
@@ -33,6 +38,8 @@ __export(chart_model_exports, {
|
|
|
33
38
|
module.exports = __toCommonJS(chart_model_exports);
|
|
34
39
|
const CHART_MODEL_VERSION = 1;
|
|
35
40
|
const MAX_SUPER_STEPS = 100;
|
|
41
|
+
const COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
42
|
+
const TEMPORAL_OPERATORS = ["after", "before", "at", "every"];
|
|
36
43
|
const TIME_UNITS = {
|
|
37
44
|
msec: 1,
|
|
38
45
|
sec: 1e3,
|
|
@@ -88,6 +95,102 @@ function readEnclosed(text, start, open, close) {
|
|
|
88
95
|
}
|
|
89
96
|
throw new LabelSyntaxError('Missing "%s"', [close], start, text.length);
|
|
90
97
|
}
|
|
98
|
+
const ASTRO_EVENTS = [
|
|
99
|
+
"sunrise",
|
|
100
|
+
"sunriseEnd",
|
|
101
|
+
"goldenHourEnd",
|
|
102
|
+
"solarNoon",
|
|
103
|
+
"goldenHour",
|
|
104
|
+
"sunsetStart",
|
|
105
|
+
"sunset",
|
|
106
|
+
"dusk",
|
|
107
|
+
"nauticalDusk",
|
|
108
|
+
"night",
|
|
109
|
+
"nadir",
|
|
110
|
+
"nightEnd",
|
|
111
|
+
"nauticalDawn",
|
|
112
|
+
"dawn"
|
|
113
|
+
];
|
|
114
|
+
const TIME_OF_DAY = /^([01]?\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
|
|
115
|
+
const INVALID_TEMPORAL = 'Invalid temporal expression "%s", expected e.g. after(5, sec), every(10, min), after(3, button), after(5, min, condition) or at("sunset", -30)';
|
|
116
|
+
function splitArguments(text, from, to) {
|
|
117
|
+
const args = [];
|
|
118
|
+
let depth = 0;
|
|
119
|
+
let quote = null;
|
|
120
|
+
let start = from;
|
|
121
|
+
const push = (end) => {
|
|
122
|
+
const raw = text.substring(start, end);
|
|
123
|
+
const trimmed = raw.trim();
|
|
124
|
+
args.push({ text: trimmed, from: start + raw.indexOf(trimmed) });
|
|
125
|
+
};
|
|
126
|
+
for (let i = from; i < to; i++) {
|
|
127
|
+
const c = text[i];
|
|
128
|
+
if (quote) {
|
|
129
|
+
if (c === "\\") {
|
|
130
|
+
i++;
|
|
131
|
+
} else if (c === quote) {
|
|
132
|
+
quote = null;
|
|
133
|
+
}
|
|
134
|
+
} else if (c === '"' || c === "'" || c === "`") {
|
|
135
|
+
quote = c;
|
|
136
|
+
} else if ("([{".includes(c)) {
|
|
137
|
+
depth++;
|
|
138
|
+
} else if (")]}".includes(c)) {
|
|
139
|
+
depth--;
|
|
140
|
+
} else if (c === "," && depth === 0) {
|
|
141
|
+
push(i);
|
|
142
|
+
start = i + 1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
push(to);
|
|
146
|
+
return args;
|
|
147
|
+
}
|
|
148
|
+
function parseTemporal(text, operator, from, open, end) {
|
|
149
|
+
const fail = () => {
|
|
150
|
+
throw new LabelSyntaxError(INVALID_TEMPORAL, [text.substring(from, end)], from, end);
|
|
151
|
+
};
|
|
152
|
+
const args = splitArguments(text, open + 1, end - 1);
|
|
153
|
+
const quoted = /^(["'])(.*)\1$/.exec(args[0]?.text ?? "");
|
|
154
|
+
if (quoted) {
|
|
155
|
+
const time = quoted[2].trim();
|
|
156
|
+
if (operator !== "at" || args.length > 2) {
|
|
157
|
+
fail();
|
|
158
|
+
}
|
|
159
|
+
if (!ASTRO_EVENTS.includes(time) && !TIME_OF_DAY.test(time)) {
|
|
160
|
+
throw new LabelSyntaxError(
|
|
161
|
+
'Unknown time "%s", use a time like "22:30" or one of: %s',
|
|
162
|
+
[time, ASTRO_EVENTS.join(", ")],
|
|
163
|
+
args[0].from,
|
|
164
|
+
args[0].from + args[0].text.length
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
const temporal = { operator, time };
|
|
168
|
+
if (args.length === 2) {
|
|
169
|
+
temporal.offsetMinutes = /^[-+]?\d+(?:\.\d+)?$/.test(args[1].text) ? parseFloat(args[1].text) : fail();
|
|
170
|
+
}
|
|
171
|
+
return { temporal };
|
|
172
|
+
}
|
|
173
|
+
const number = /^\d+(?:\.\d+)?$/.test(args[0]?.text) ? parseFloat(args[0].text) : fail();
|
|
174
|
+
const unit = args[1]?.text ?? "";
|
|
175
|
+
if (operator === "every" && number === 0) {
|
|
176
|
+
fail();
|
|
177
|
+
}
|
|
178
|
+
if (Object.hasOwn(TIME_UNITS, unit)) {
|
|
179
|
+
const temporal = { operator, ms: number * TIME_UNITS[unit] };
|
|
180
|
+
if (args.length === 3 && operator === "after" && args[2].text) {
|
|
181
|
+
temporal.condition = args[2].text;
|
|
182
|
+
return { temporal, condition: { from: args[2].from, to: args[2].from + args[2].text.length } };
|
|
183
|
+
}
|
|
184
|
+
return args.length === 2 ? { temporal } : fail();
|
|
185
|
+
}
|
|
186
|
+
if (args.length !== 2 || !/^[A-Za-z_$][\w$]*$/.test(unit) || !Number.isInteger(number) || number < 1) {
|
|
187
|
+
fail();
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
temporal: { operator, count: number, event: unit },
|
|
191
|
+
event: { from: args[1].from, to: args[1].from + unit.length }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
91
194
|
function parseTransitionLabelWithRanges(label) {
|
|
92
195
|
const result = {};
|
|
93
196
|
const ranges = {};
|
|
@@ -106,19 +209,17 @@ function parseTransitionLabelWithRanges(label) {
|
|
|
106
209
|
const from = pos;
|
|
107
210
|
pos += event[0].length;
|
|
108
211
|
skipSpace();
|
|
109
|
-
if (event[0]
|
|
110
|
-
const {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
212
|
+
if (TEMPORAL_OPERATORS.includes(event[0]) && text[pos] === "(") {
|
|
213
|
+
const { end } = readEnclosed(text, pos, "(", ")");
|
|
214
|
+
const parsed = parseTemporal(text, event[0], from, pos, end);
|
|
215
|
+
result.temporal = parsed.temporal;
|
|
216
|
+
ranges.temporal = { from, to: end };
|
|
217
|
+
if (parsed.event) {
|
|
218
|
+
ranges.temporalEvent = parsed.event;
|
|
219
|
+
}
|
|
220
|
+
if (parsed.condition) {
|
|
221
|
+
ranges.temporalCondition = parsed.condition;
|
|
119
222
|
}
|
|
120
|
-
result.afterMs = parseFloat(afterMatch[1]) * TIME_UNITS[afterMatch[2]];
|
|
121
|
-
ranges.after = { from, to: end };
|
|
122
223
|
pos = end;
|
|
123
224
|
} else {
|
|
124
225
|
result.event = event[0];
|
|
@@ -214,8 +315,18 @@ function normalizeChart(data, where) {
|
|
|
214
315
|
for (const field of ["entry", "during", "exit", "initial", "comment"]) {
|
|
215
316
|
optionalString(state[field], `${at}: "${field}" is no text`);
|
|
216
317
|
}
|
|
318
|
+
if (state.order !== void 0 && !Number.isFinite(state.order)) {
|
|
319
|
+
fail(`${at}: "order" is no number`);
|
|
320
|
+
}
|
|
321
|
+
if (state.color !== void 0 && !(typeof state.color === "string" && COLOR_PATTERN.test(state.color))) {
|
|
322
|
+
fail(`${at}: "color" is no color like "#d6eaf8"`);
|
|
323
|
+
}
|
|
324
|
+
const { parallel, history, ...rest } = state;
|
|
217
325
|
return {
|
|
218
|
-
...
|
|
326
|
+
...rest,
|
|
327
|
+
// the defaults (exclusive, no history) are not stored, like in the editor
|
|
328
|
+
...parallel === true ? { parallel } : {},
|
|
329
|
+
...history === true ? { history } : {},
|
|
219
330
|
name: typeof state.name === "string" && state.name ? state.name : state.id,
|
|
220
331
|
parent: state.parent || null,
|
|
221
332
|
x: Number.isFinite(state.x) ? state.x : 0,
|
|
@@ -252,7 +363,9 @@ function normalizeChart(data, where) {
|
|
|
252
363
|
if (transition.priority !== void 0 && !Number.isFinite(transition.priority)) {
|
|
253
364
|
fail(`${at}: "priority" is no number`);
|
|
254
365
|
}
|
|
255
|
-
|
|
366
|
+
const { labelOffset, ...rest } = transition;
|
|
367
|
+
const validOffset = isObject(labelOffset) && Number.isFinite(labelOffset.x) && Number.isFinite(labelOffset.y);
|
|
368
|
+
return { ...rest, ...validOffset ? { labelOffset: { x: labelOffset.x, y: labelOffset.y } } : {} };
|
|
256
369
|
});
|
|
257
370
|
const symbolNames = /* @__PURE__ */ new Set();
|
|
258
371
|
const symbols = data.symbols.map((symbol, i) => {
|
|
@@ -313,6 +426,12 @@ function normalizeChart(data, where) {
|
|
|
313
426
|
if (chart.superStep !== true) {
|
|
314
427
|
delete chart.superStep;
|
|
315
428
|
}
|
|
429
|
+
if (chart.parallel !== true) {
|
|
430
|
+
delete chart.parallel;
|
|
431
|
+
}
|
|
432
|
+
if (chart.orthogonalTransitions !== true) {
|
|
433
|
+
delete chart.orthogonalTransitions;
|
|
434
|
+
}
|
|
316
435
|
return chart;
|
|
317
436
|
}
|
|
318
437
|
function parseExport(text) {
|
|
@@ -338,10 +457,15 @@ function parseExport(text) {
|
|
|
338
457
|
}
|
|
339
458
|
// Annotate the CommonJS export names for ESM import in node:
|
|
340
459
|
0 && (module.exports = {
|
|
460
|
+
ASTRO_EVENTS,
|
|
341
461
|
CHART_MODEL_VERSION,
|
|
462
|
+
COLOR_PATTERN,
|
|
342
463
|
EXPORT_FORMAT,
|
|
343
464
|
LabelSyntaxError,
|
|
344
465
|
MAX_SUPER_STEPS,
|
|
466
|
+
TEMPORAL_OPERATORS,
|
|
467
|
+
TIME_OF_DAY,
|
|
468
|
+
TIME_UNITS,
|
|
345
469
|
createChart,
|
|
346
470
|
createExport,
|
|
347
471
|
formatMessage,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/chart-model.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * The chart model shared by the editor (admin tab) and the runtime (adapter).\n *\n * A chart is stored as object \"statechart.<instance>.charts.<chartId>\" (type \"channel\"),\n * the model itself lives in `native.chart` of that object.\n */\n\n/** Current version of the chart model, increase on incompatible changes */\nexport const CHART_MODEL_VERSION = 1;\n\n/** Maximum number of transitions in one wakeup with super step semantics, protects against loops */\nexport const MAX_SUPER_STEPS = 100;\n\nexport type SymbolScope = \"input\" | \"output\" | \"local\";\n\nexport type InputTrigger = \"update\" | \"change\";\n\n/** \"ack\": only confirmed values, \"command\": only commands (ack=false) */\nexport type AckFilter = \"any\" | \"ack\" | \"command\";\n\n/**\n * A variable which can be used in conditions and actions.\n * Inputs and outputs are mapped to ioBroker states, locals only live inside the chart.\n */\nexport interface ChartSymbol {\n /** Name used in conditions and actions, must be a valid JavaScript identifier */\n name: string;\n /** Input (read from state), output (written to state) or local */\n scope: SymbolScope;\n /** ioBroker state ID for inputs and outputs */\n stateId?: string;\n /** Initial value for locals */\n initial?: any;\n /** Inputs only: wake up the chart on every update (default) or only on changes */\n trigger?: InputTrigger;\n /** Inputs only: which updates are used, depending on their ack flag, default \"any\" */\n ack?: AckFilter;\n /** Inputs only: wake up the chart only after the input had no update for this time */\n debounceMs?: number;\n}\n\nexport interface ChartState {\n /** Unique and stable ID inside the chart */\n id: string;\n /** Display name, also used for the \"activeState\" state */\n name: string;\n /** ID of the parent state, null/undefined for top level states */\n parent?: string | null;\n /** ID of the initial child state (only for states with children) */\n initial?: string;\n /** Action executed when the state is entered */\n entry?: string;\n /** Action executed on every wakeup while the state is active and no transition is taken */\n during?: string;\n /** Action executed when the state is left */\n exit?: string;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Position in the editor, relative to the parent state */\n x: number;\n /** Position in the editor, relative to the parent state */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\nexport interface ChartTransition {\n /** Unique and stable ID inside the chart */\n id: string;\n /** ID of the source state */\n source: string;\n /** ID of the target state */\n target: string;\n /** Transition label in Stateflow syntax: event[condition]{action} */\n label?: string;\n /** Evaluation order of transitions with the same source, lower is first */\n priority?: number;\n /**\n * Only for transitions from a state to one of its own children: leave and enter the source state again.\n * Default is an inner transition, which keeps the source state active.\n */\n reenterParent?: boolean;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Side of the source state where the arrow starts (editor only) */\n sourceHandle?: string;\n /** Side of the target state where the arrow ends (editor only) */\n targetHandle?: string;\n /** Where the arrow starts on the border of the source state, automatic if missing (editor only) */\n sourceAnchor?: EdgeAnchor;\n /** Where the arrow ends on the border of the target state, automatic if missing (editor only) */\n targetAnchor?: EdgeAnchor;\n}\n\n/** A point on the border of a state, set by dragging an end of a transition in the editor */\nexport interface EdgeAnchor {\n side: \"top\" | \"right\" | \"bottom\" | \"left\";\n /** Position along the side: 0 = left/top end, 1 = right/bottom end */\n pos: number;\n}\n\n/**\n * A block with JavaScript code, executed once when the chart starts.\n * The functions declared in it can be used in all conditions and actions of the chart.\n */\nexport interface ChartFunction {\n /** Unique and stable ID inside the chart */\n id: string;\n /** JavaScript, usually one or more function declarations */\n code: string;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Position in the editor */\n x: number;\n /** Position in the editor */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\n/**\n * A note on the canvas of the editor, like an annotation in Stateflow. No influence on the execution.\n */\nexport interface ChartNote {\n /** Unique and stable ID inside the chart */\n id: string;\n text: string;\n /** ID of the state the note is placed in, it moves together with it */\n parent?: string | null;\n /** Position in the editor, relative to the parent state */\n x: number;\n /** Position in the editor, relative to the parent state */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\nexport interface Chart {\n /** Model version, see CHART_MODEL_VERSION */\n version: number;\n /** Display name */\n name: string;\n /** If the chart is executed by the adapter */\n enabled: boolean;\n /** Continue with the state from before a restart of the adapter, default true */\n restoreState?: boolean;\n /**\n * Super step semantics: after a transition, the chart is checked again right away, until no transition is valid\n * anymore (at most MAX_SUPER_STEPS transitions per wakeup). Default false: one transition per wakeup.\n */\n superStep?: boolean;\n /** ID of the initial top level state (default transition) */\n initial?: string;\n symbols: ChartSymbol[];\n states: ChartState[];\n transitions: ChartTransition[];\n /** Missing in charts created before function blocks existed */\n functions?: ChartFunction[];\n /** Missing in charts created before notes existed */\n notes?: ChartNote[];\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n}\n\nexport interface TransitionLabel {\n /** Name of the triggering event (an input symbol), undefined = any wakeup */\n event?: string;\n /** Delay of a temporal transition after(n, unit) in milliseconds */\n afterMs?: number;\n /** Guard expression */\n condition?: string;\n /** Transition action */\n action?: string;\n}\n\nconst TIME_UNITS: Record<string, number> = {\n msec: 1,\n sec: 1000,\n min: 60_000,\n};\n\n/**\n * Creates a new, empty chart. It is paused, the user starts it when it is ready.\n *\n * @param name Display name\n */\nexport function createChart(name: string): Chart {\n return {\n version: CHART_MODEL_VERSION,\n name,\n enabled: false,\n symbols: [],\n states: [],\n transitions: [],\n functions: [],\n notes: [],\n };\n}\n\n/**\n * Converts a display name to an ID which can be used in ioBroker object IDs\n *\n * @param name Display name\n */\nexport function nameToId(name: string): string {\n return (\n name\n .trim()\n .toLowerCase()\n .replace(/\u00E4/g, \"ae\")\n .replace(/\u00F6/g, \"oe\")\n .replace(/\u00FC/g, \"ue\")\n .replace(/\u00DF/g, \"ss\")\n .replace(/[^a-z0-9_-]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\") || \"chart\"\n );\n}\n\nexport interface TextRange {\n /** Index of the first character */\n from: number;\n /** Index after the last character */\n to: number;\n}\n\n/** Positions of the parts in the label text */\nexport interface TransitionLabelRanges {\n event?: TextRange;\n /** The whole after(...) expression */\n after?: TextRange;\n /** Content of [...] without the brackets */\n condition?: TextRange;\n /** Content of {...} without the brackets */\n action?: TextRange;\n}\n\n/**\n * Fills the %s placeholders of a message\n *\n * @param key Message with %s placeholders\n * @param args Values for the placeholders\n */\nexport function formatMessage(key: string, args: string[]): string {\n let i = 0;\n return key.replace(/%s/g, () => args[i++] ?? \"\");\n}\n\n/**\n * Error in the structure of a transition label, knows where in the label the problem is\n */\nexport class LabelSyntaxError extends Error {\n /**\n * @param key Message with %s placeholders, used to translate the message\n * @param args Values for the placeholders\n * @param from Start of the problem in the label\n * @param to End of the problem in the label\n */\n constructor(\n public readonly key: string,\n public readonly args: string[],\n public readonly from: number,\n public readonly to: number,\n ) {\n super(formatMessage(key, args));\n }\n}\n\n/**\n * Reads a part enclosed in brackets, nested brackets of the same type are allowed\n *\n * @param text The label\n * @param start Index of the opening bracket\n * @param open Opening bracket\n * @param close Closing bracket\n * @returns from is the index of the (trimmed) content, end is the index after the closing bracket\n */\nfunction readEnclosed(\n text: string,\n start: number,\n open: string,\n close: string,\n): { content: string; from: number; end: number } {\n let depth = 0;\n for (let i = start; i < text.length; i++) {\n if (text[i] === open) {\n depth++;\n } else if (text[i] === close) {\n depth--;\n if (depth === 0) {\n const raw = text.substring(start + 1, i);\n const content = raw.trim();\n return { content, from: start + 1 + raw.indexOf(content), end: i + 1 };\n }\n }\n }\n throw new LabelSyntaxError('Missing \"%s\"', [close], start, text.length);\n}\n\n/**\n * Parses a transition label and returns where its parts are, see parseTransitionLabel\n *\n * @param label The label text\n * @throws {LabelSyntaxError}\n */\nexport function parseTransitionLabelWithRanges(label: string | undefined): {\n label: TransitionLabel;\n ranges: TransitionLabelRanges;\n} {\n const result: TransitionLabel = {};\n const ranges: TransitionLabelRanges = {};\n const text = label || \"\";\n let pos = 0;\n\n const skipSpace = (): void => {\n while (pos < text.length && /\\s/.test(text[pos])) {\n pos++;\n }\n };\n\n skipSpace();\n const eventMatch = /[A-Za-z_$][\\w$]*/y;\n eventMatch.lastIndex = pos;\n const event = eventMatch.exec(text);\n if (event) {\n const from = pos;\n pos += event[0].length;\n skipSpace();\n if (event[0] === \"after\" && text[pos] === \"(\") {\n const { content, end } = readEnclosed(text, pos, \"(\", \")\");\n const afterMatch = /^(\\d+(?:\\.\\d+)?)\\s*,\\s*(msec|sec|min)$/.exec(content);\n if (!afterMatch) {\n throw new LabelSyntaxError(\n 'Invalid temporal expression \"%s\", expected e.g. after(5, sec)',\n [`after(${content})`],\n from,\n end,\n );\n }\n result.afterMs = parseFloat(afterMatch[1]) * TIME_UNITS[afterMatch[2]];\n ranges.after = { from, to: end };\n pos = end;\n } else {\n result.event = event[0];\n ranges.event = { from, to: from + event[0].length };\n }\n }\n\n skipSpace();\n if (text[pos] === \"[\") {\n const { content, from, end } = readEnclosed(text, pos, \"[\", \"]\");\n result.condition = content;\n ranges.condition = { from, to: from + content.length };\n pos = end;\n }\n\n skipSpace();\n if (text[pos] === \"{\") {\n const { content, from, end } = readEnclosed(text, pos, \"{\", \"}\");\n result.action = content;\n ranges.action = { from, to: from + content.length };\n pos = end;\n }\n\n skipSpace();\n if (pos < text.length) {\n throw new LabelSyntaxError(\n 'Unexpected \"%s\", expected event[condition]{action}',\n [text.substring(pos).trim()],\n pos,\n text.length,\n );\n }\n return { label: result, ranges };\n}\n\n/**\n * Parses a transition label in Stateflow syntax: event[condition]{action}\n * All parts are optional. Instead of an event, after(n, sec|msec|min) creates a temporal transition.\n *\n * @param label The label text\n * @throws {LabelSyntaxError}\n */\nexport function parseTransitionLabel(label: string | undefined): TransitionLabel {\n return parseTransitionLabelWithRanges(label).label;\n}\n\n/** Identifies files with exported charts */\nexport const EXPORT_FORMAT = \"iobroker.statechart\";\n\n/** Files exported before the adapter was renamed from \"state-machine\" to \"statechart\" */\nconst LEGACY_EXPORT_FORMATS = [\"iobroker.state-machine\"];\n\n/** The content of an export file */\nexport interface ChartExport {\n format: string;\n version: number;\n exported: string;\n charts: Chart[];\n}\n\n/**\n * The content of an export file\n *\n * @param charts The exported charts\n */\nexport function createExport(charts: Chart[]): ChartExport {\n return { format: EXPORT_FORMAT, version: CHART_MODEL_VERSION, exported: new Date().toISOString(), charts };\n}\n\nconst IDENTIFIER = /^[A-Za-z_$][\\w$]*$/;\nconst SCOPES = [\"input\", \"output\", \"local\"];\n\nfunction isObject(value: any): value is Record<string, any> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Checks a chart of an export file and fills in defaults for missing optional values\n *\n * @param data The chart as read from the file\n * @param where Prefix of error messages, e.g. \"Chart 1\"\n * @throws {Error} if the chart is invalid\n */\nfunction normalizeChart(data: any, where: string): Chart {\n const fail = (message: string): never => {\n throw new Error(`${where}: ${message}`);\n };\n if (!isObject(data)) {\n fail(\"not an object\");\n }\n if (typeof data.version === \"number\" && data.version > CHART_MODEL_VERSION) {\n fail(`created with a newer version of the adapter (chart version ${data.version})`);\n }\n for (const list of [\"states\", \"transitions\", \"symbols\"]) {\n if (!Array.isArray(data[list])) {\n fail(`\"${list}\" is missing or no list`);\n }\n }\n for (const list of [\"functions\", \"notes\"]) {\n if (data[list] !== undefined && !Array.isArray(data[list])) {\n fail(`\"${list}\" is no list`);\n }\n }\n const functions: any[] = data.functions || [];\n const notes: any[] = data.notes || [];\n\n // states, function blocks and notes are all nodes in the editor, so their IDs must be unique together\n const nodeIds = new Set<string>();\n const checkId = (item: any, kind: string, index: number): string => {\n if (!isObject(item) || typeof item.id !== \"string\" || !item.id) {\n fail(`${kind} ${index + 1} has no ID`);\n }\n if (nodeIds.has(item.id)) {\n fail(`${kind} ${item.id}: the ID is used more than once`);\n }\n nodeIds.add(item.id);\n return item.id;\n };\n const optionalString = (value: any, message: string): void => {\n if (value !== undefined && value !== null && typeof value !== \"string\") {\n fail(message);\n }\n };\n\n data.states.forEach((state: any, i: number) => checkId(state, \"state\", i));\n functions.forEach((fn, i) => checkId(fn, \"function block\", i));\n notes.forEach((note, i) => checkId(note, \"note\", i));\n const stateIds = new Set(data.states.map((s: any) => s.id));\n optionalString(data.comment, '\"comment\" is no text');\n\n const states: ChartState[] = data.states.map((state: any) => {\n const at = `state ${state.id}`;\n if (state.parent && !stateIds.has(state.parent)) {\n fail(`${at}: unknown parent state \"${state.parent}\"`);\n }\n for (const field of [\"entry\", \"during\", \"exit\", \"initial\", \"comment\"]) {\n optionalString(state[field], `${at}: \"${field}\" is no text`);\n }\n return {\n ...state,\n name: typeof state.name === \"string\" && state.name ? state.name : state.id,\n parent: state.parent || null,\n x: Number.isFinite(state.x) ? state.x : 0,\n y: Number.isFinite(state.y) ? state.y : 0,\n };\n });\n\n // a parent must not be its own (indirect) child\n const parentOf = new Map(states.map(s => [s.id, s.parent]));\n for (const state of states) {\n let parent = state.parent;\n for (let i = 0; parent; i++) {\n if (parent === state.id || i > states.length) {\n fail(`state ${state.id}: the parent states form a cycle`);\n }\n parent = parentOf.get(parent) ?? null;\n }\n }\n\n const transitionIds = new Set<string>();\n const transitions: ChartTransition[] = data.transitions.map((transition: any, i: number) => {\n if (!isObject(transition) || typeof transition.id !== \"string\" || !transition.id) {\n fail(`transition ${i + 1} has no ID`);\n }\n const at = `transition ${transition.id}`;\n if (transitionIds.has(transition.id)) {\n fail(`${at}: the ID is used more than once`);\n }\n transitionIds.add(transition.id);\n for (const end of [\"source\", \"target\"]) {\n if (!stateIds.has(transition[end])) {\n fail(`${at}: unknown ${end} state \"${transition[end]}\"`);\n }\n }\n optionalString(transition.label, `${at}: \"label\" is no text`);\n optionalString(transition.comment, `${at}: \"comment\" is no text`);\n if (transition.priority !== undefined && !Number.isFinite(transition.priority)) {\n fail(`${at}: \"priority\" is no number`);\n }\n return { ...transition };\n });\n\n const symbolNames = new Set<string>();\n const symbols: ChartSymbol[] = data.symbols.map((symbol: any, i: number) => {\n if (!isObject(symbol) || typeof symbol.name !== \"string\" || !IDENTIFIER.test(symbol.name)) {\n fail(`variable ${i + 1}: invalid name`);\n }\n if (symbolNames.has(symbol.name)) {\n fail(`variable ${symbol.name}: the name is used more than once`);\n }\n symbolNames.add(symbol.name);\n if (!SCOPES.includes(symbol.scope)) {\n fail(`variable ${symbol.name}: invalid kind \"${symbol.scope}\"`);\n }\n optionalString(symbol.stateId, `variable ${symbol.name}: \"stateId\" is no text`);\n if (symbol.trigger !== undefined && ![\"update\", \"change\"].includes(symbol.trigger)) {\n fail(`variable ${symbol.name}: invalid trigger \"${symbol.trigger}\"`);\n }\n if (symbol.ack !== undefined && ![\"any\", \"ack\", \"command\"].includes(symbol.ack)) {\n fail(`variable ${symbol.name}: invalid ack filter \"${symbol.ack}\"`);\n }\n if (symbol.debounceMs !== undefined && !(Number.isFinite(symbol.debounceMs) && symbol.debounceMs >= 0)) {\n fail(`variable ${symbol.name}: \"debounceMs\" is no number of 0 or more`);\n }\n return { ...symbol };\n });\n\n const normalizedFunctions: ChartFunction[] = functions.map(fn => {\n if (typeof fn.code !== \"string\") {\n fail(`function block ${fn.id}: \"code\" is no text`);\n }\n optionalString(fn.comment, `function block ${fn.id}: \"comment\" is no text`);\n return { ...fn, x: Number.isFinite(fn.x) ? fn.x : 0, y: Number.isFinite(fn.y) ? fn.y : 0 };\n });\n\n const normalizedNotes: ChartNote[] = notes.map(note => {\n optionalString(note.text, `note ${note.id}: \"text\" is no text`);\n if (note.parent && !stateIds.has(note.parent)) {\n fail(`note ${note.id}: unknown parent state \"${note.parent}\"`);\n }\n return {\n ...note,\n text: note.text || \"\",\n parent: note.parent || null,\n x: Number.isFinite(note.x) ? note.x : 0,\n y: Number.isFinite(note.y) ? note.y : 0,\n };\n });\n\n const chart: Chart = {\n ...data,\n version: CHART_MODEL_VERSION,\n name: typeof data.name === \"string\" && data.name.trim() ? data.name.trim() : where,\n initial: typeof data.initial === \"string\" && stateIds.has(data.initial) ? data.initial : undefined,\n enabled: data.enabled !== false,\n symbols,\n states,\n transitions,\n functions: normalizedFunctions,\n notes: normalizedNotes,\n };\n // the default (off) is not stored, like in the editor\n if (chart.superStep !== true) {\n delete chart.superStep;\n }\n return chart;\n}\n\n/**\n * Reads the charts of an export file. A single chart (without the export wrapper) is accepted as well.\n *\n * @param text Content of the file\n * @throws {Error} if the file is invalid\n */\nexport function parseExport(text: string): Chart[] {\n let data;\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new Error(`No valid JSON: ${err.message}`);\n }\n if (isObject(data) && (data.format === EXPORT_FORMAT || LEGACY_EXPORT_FORMATS.includes(data.format))) {\n if (typeof data.version === \"number\" && data.version > CHART_MODEL_VERSION) {\n throw new Error(`The file was created with a newer version of the adapter (version ${data.version})`);\n }\n if (!Array.isArray(data.charts) || !data.charts.length) {\n throw new Error(\"The file contains no charts\");\n }\n return data.charts.map((chart: any, i: number) => normalizeChart(chart, `Chart ${i + 1}`));\n }\n if (isObject(data) && Array.isArray(data.states)) {\n return [normalizeChart(data, \"Chart\")];\n }\n throw new Error(\"The file contains no charts of the statechart adapter\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,MAAM,sBAAsB;AAG5B,MAAM,kBAAkB;AA0K/B,MAAM,aAAqC;AAAA,EACvC,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACT;AAOO,SAAS,YAAY,MAAqB;AAC7C,SAAO;AAAA,IACH,SAAS;AAAA,IACT;AAAA,IACA,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,IACV,QAAQ,CAAC;AAAA,IACT,aAAa,CAAC;AAAA,IACd,WAAW,CAAC;AAAA,IACZ,OAAO,CAAC;AAAA,EACZ;AACJ;AAOO,SAAS,SAAS,MAAsB;AAC3C,SACI,KACK,KAAK,EACL,YAAY,EACZ,QAAQ,MAAM,IAAI,EAClB,QAAQ,MAAM,IAAI,EAClB,QAAQ,MAAM,IAAI,EAClB,QAAQ,MAAM,IAAI,EAClB,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,YAAY,EAAE,KAAK;AAExC;AA0BO,SAAS,cAAc,KAAa,MAAwB;AAC/D,MAAI,IAAI;AACR,SAAO,IAAI,QAAQ,OAAO,MAAM,KAAK,GAAG,KAAK,EAAE;AACnD;AAKO,MAAM,yBAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOxC,YACoB,KACA,MACA,MACA,IAClB;AACE,UAAM,cAAc,KAAK,IAAI,CAAC;AALd;AACA;AACA;AACA;AAAA,EAGpB;AACJ;AAWA,SAAS,aACL,MACA,OACA,MACA,OAC8C;AAC9C,MAAI,QAAQ;AACZ,WAAS,IAAI,OAAO,IAAI,KAAK,QAAQ,KAAK;AACtC,QAAI,KAAK,CAAC,MAAM,MAAM;AAClB;AAAA,IACJ,WAAW,KAAK,CAAC,MAAM,OAAO;AAC1B;AACA,UAAI,UAAU,GAAG;AACb,cAAM,MAAM,KAAK,UAAU,QAAQ,GAAG,CAAC;AACvC,cAAM,UAAU,IAAI,KAAK;AACzB,eAAO,EAAE,SAAS,MAAM,QAAQ,IAAI,IAAI,QAAQ,OAAO,GAAG,KAAK,IAAI,EAAE;AAAA,MACzE;AAAA,IACJ;AAAA,EACJ;AACA,QAAM,IAAI,iBAAiB,gBAAgB,CAAC,KAAK,GAAG,OAAO,KAAK,MAAM;AAC1E;AAQO,SAAS,+BAA+B,OAG7C;AACE,QAAM,SAA0B,CAAC;AACjC,QAAM,SAAgC,CAAC;AACvC,QAAM,OAAO,SAAS;AACtB,MAAI,MAAM;AAEV,QAAM,YAAY,MAAY;AAC1B,WAAO,MAAM,KAAK,UAAU,KAAK,KAAK,KAAK,GAAG,CAAC,GAAG;AAC9C;AAAA,IACJ;AAAA,EACJ;AAEA,YAAU;AACV,QAAM,aAAa;AACnB,aAAW,YAAY;AACvB,QAAM,QAAQ,WAAW,KAAK,IAAI;AAClC,MAAI,OAAO;AACP,UAAM,OAAO;AACb,WAAO,MAAM,CAAC,EAAE;AAChB,cAAU;AACV,QAAI,MAAM,CAAC,MAAM,WAAW,KAAK,GAAG,MAAM,KAAK;AAC3C,YAAM,EAAE,SAAS,IAAI,IAAI,aAAa,MAAM,KAAK,KAAK,GAAG;AACzD,YAAM,aAAa,yCAAyC,KAAK,OAAO;AACxE,UAAI,CAAC,YAAY;AACb,cAAM,IAAI;AAAA,UACN;AAAA,UACA,CAAC,SAAS,OAAO,GAAG;AAAA,UACpB;AAAA,UACA;AAAA,QACJ;AAAA,MACJ;AACA,aAAO,UAAU,WAAW,WAAW,CAAC,CAAC,IAAI,WAAW,WAAW,CAAC,CAAC;AACrE,aAAO,QAAQ,EAAE,MAAM,IAAI,IAAI;AAC/B,YAAM;AAAA,IACV,OAAO;AACH,aAAO,QAAQ,MAAM,CAAC;AACtB,aAAO,QAAQ,EAAE,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,OAAO;AAAA,IACtD;AAAA,EACJ;AAEA,YAAU;AACV,MAAI,KAAK,GAAG,MAAM,KAAK;AACnB,UAAM,EAAE,SAAS,MAAM,IAAI,IAAI,aAAa,MAAM,KAAK,KAAK,GAAG;AAC/D,WAAO,YAAY;AACnB,WAAO,YAAY,EAAE,MAAM,IAAI,OAAO,QAAQ,OAAO;AACrD,UAAM;AAAA,EACV;AAEA,YAAU;AACV,MAAI,KAAK,GAAG,MAAM,KAAK;AACnB,UAAM,EAAE,SAAS,MAAM,IAAI,IAAI,aAAa,MAAM,KAAK,KAAK,GAAG;AAC/D,WAAO,SAAS;AAChB,WAAO,SAAS,EAAE,MAAM,IAAI,OAAO,QAAQ,OAAO;AAClD,UAAM;AAAA,EACV;AAEA,YAAU;AACV,MAAI,MAAM,KAAK,QAAQ;AACnB,UAAM,IAAI;AAAA,MACN;AAAA,MACA,CAAC,KAAK,UAAU,GAAG,EAAE,KAAK,CAAC;AAAA,MAC3B;AAAA,MACA,KAAK;AAAA,IACT;AAAA,EACJ;AACA,SAAO,EAAE,OAAO,QAAQ,OAAO;AACnC;AASO,SAAS,qBAAqB,OAA4C;AAC7E,SAAO,+BAA+B,KAAK,EAAE;AACjD;AAGO,MAAM,gBAAgB;AAG7B,MAAM,wBAAwB,CAAC,wBAAwB;AAehD,SAAS,aAAa,QAA8B;AACvD,SAAO,EAAE,QAAQ,eAAe,SAAS,qBAAqB,WAAU,oBAAI,KAAK,GAAE,YAAY,GAAG,OAAO;AAC7G;AAEA,MAAM,aAAa;AACnB,MAAM,SAAS,CAAC,SAAS,UAAU,OAAO;AAE1C,SAAS,SAAS,OAA0C;AACxD,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;AASA,SAAS,eAAe,MAAW,OAAsB;AACrD,QAAM,OAAO,CAAC,YAA2B;AACrC,UAAM,IAAI,MAAM,GAAG,KAAK,KAAK,OAAO,EAAE;AAAA,EAC1C;AACA,MAAI,CAAC,SAAS,IAAI,GAAG;AACjB,SAAK,eAAe;AAAA,EACxB;AACA,MAAI,OAAO,KAAK,YAAY,YAAY,KAAK,UAAU,qBAAqB;AACxE,SAAK,8DAA8D,KAAK,OAAO,GAAG;AAAA,EACtF;AACA,aAAW,QAAQ,CAAC,UAAU,eAAe,SAAS,GAAG;AACrD,QAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AAC5B,WAAK,IAAI,IAAI,yBAAyB;AAAA,IAC1C;AAAA,EACJ;AACA,aAAW,QAAQ,CAAC,aAAa,OAAO,GAAG;AACvC,QAAI,KAAK,IAAI,MAAM,UAAa,CAAC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AACxD,WAAK,IAAI,IAAI,cAAc;AAAA,IAC/B;AAAA,EACJ;AACA,QAAM,YAAmB,KAAK,aAAa,CAAC;AAC5C,QAAM,QAAe,KAAK,SAAS,CAAC;AAGpC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,UAAU,CAAC,MAAW,MAAc,UAA0B;AAChE,QAAI,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,OAAO,YAAY,CAAC,KAAK,IAAI;AAC5D,WAAK,GAAG,IAAI,IAAI,QAAQ,CAAC,YAAY;AAAA,IACzC;AACA,QAAI,QAAQ,IAAI,KAAK,EAAE,GAAG;AACtB,WAAK,GAAG,IAAI,IAAI,KAAK,EAAE,iCAAiC;AAAA,IAC5D;AACA,YAAQ,IAAI,KAAK,EAAE;AACnB,WAAO,KAAK;AAAA,EAChB;AACA,QAAM,iBAAiB,CAAC,OAAY,YAA0B;AAC1D,QAAI,UAAU,UAAa,UAAU,QAAQ,OAAO,UAAU,UAAU;AACpE,WAAK,OAAO;AAAA,IAChB;AAAA,EACJ;AAEA,OAAK,OAAO,QAAQ,CAAC,OAAY,MAAc,QAAQ,OAAO,SAAS,CAAC,CAAC;AACzE,YAAU,QAAQ,CAAC,IAAI,MAAM,QAAQ,IAAI,kBAAkB,CAAC,CAAC;AAC7D,QAAM,QAAQ,CAAC,MAAM,MAAM,QAAQ,MAAM,QAAQ,CAAC,CAAC;AACnD,QAAM,WAAW,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,MAAW,EAAE,EAAE,CAAC;AAC1D,iBAAe,KAAK,SAAS,sBAAsB;AAEnD,QAAM,SAAuB,KAAK,OAAO,IAAI,CAAC,UAAe;AACzD,UAAM,KAAK,SAAS,MAAM,EAAE;AAC5B,QAAI,MAAM,UAAU,CAAC,SAAS,IAAI,MAAM,MAAM,GAAG;AAC7C,WAAK,GAAG,EAAE,2BAA2B,MAAM,MAAM,GAAG;AAAA,IACxD;AACA,eAAW,SAAS,CAAC,SAAS,UAAU,QAAQ,WAAW,SAAS,GAAG;AACnE,qBAAe,MAAM,KAAK,GAAG,GAAG,EAAE,MAAM,KAAK,cAAc;AAAA,IAC/D;AACA,WAAO;AAAA,MACH,GAAG;AAAA,MACH,MAAM,OAAO,MAAM,SAAS,YAAY,MAAM,OAAO,MAAM,OAAO,MAAM;AAAA,MACxE,QAAQ,MAAM,UAAU;AAAA,MACxB,GAAG,OAAO,SAAS,MAAM,CAAC,IAAI,MAAM,IAAI;AAAA,MACxC,GAAG,OAAO,SAAS,MAAM,CAAC,IAAI,MAAM,IAAI;AAAA,IAC5C;AAAA,EACJ,CAAC;AAGD,QAAM,WAAW,IAAI,IAAI,OAAO,IAAI,OAAK,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC1D,aAAW,SAAS,QAAQ;AACxB,QAAI,SAAS,MAAM;AACnB,aAAS,IAAI,GAAG,QAAQ,KAAK;AACzB,UAAI,WAAW,MAAM,MAAM,IAAI,OAAO,QAAQ;AAC1C,aAAK,SAAS,MAAM,EAAE,kCAAkC;AAAA,MAC5D;AACA,eAAS,SAAS,IAAI,MAAM,KAAK;AAAA,IACrC;AAAA,EACJ;AAEA,QAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAM,cAAiC,KAAK,YAAY,IAAI,CAAC,YAAiB,MAAc;AACxF,QAAI,CAAC,SAAS,UAAU,KAAK,OAAO,WAAW,OAAO,YAAY,CAAC,WAAW,IAAI;AAC9E,WAAK,cAAc,IAAI,CAAC,YAAY;AAAA,IACxC;AACA,UAAM,KAAK,cAAc,WAAW,EAAE;AACtC,QAAI,cAAc,IAAI,WAAW,EAAE,GAAG;AAClC,WAAK,GAAG,EAAE,iCAAiC;AAAA,IAC/C;AACA,kBAAc,IAAI,WAAW,EAAE;AAC/B,eAAW,OAAO,CAAC,UAAU,QAAQ,GAAG;AACpC,UAAI,CAAC,SAAS,IAAI,WAAW,GAAG,CAAC,GAAG;AAChC,aAAK,GAAG,EAAE,aAAa,GAAG,WAAW,WAAW,GAAG,CAAC,GAAG;AAAA,MAC3D;AAAA,IACJ;AACA,mBAAe,WAAW,OAAO,GAAG,EAAE,sBAAsB;AAC5D,mBAAe,WAAW,SAAS,GAAG,EAAE,wBAAwB;AAChE,QAAI,WAAW,aAAa,UAAa,CAAC,OAAO,SAAS,WAAW,QAAQ,GAAG;AAC5E,WAAK,GAAG,EAAE,2BAA2B;AAAA,IACzC;AACA,WAAO,EAAE,GAAG,WAAW;AAAA,EAC3B,CAAC;AAED,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,UAAyB,KAAK,QAAQ,IAAI,CAAC,QAAa,MAAc;AACxE,QAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO,SAAS,YAAY,CAAC,WAAW,KAAK,OAAO,IAAI,GAAG;AACvF,WAAK,YAAY,IAAI,CAAC,gBAAgB;AAAA,IAC1C;AACA,QAAI,YAAY,IAAI,OAAO,IAAI,GAAG;AAC9B,WAAK,YAAY,OAAO,IAAI,mCAAmC;AAAA,IACnE;AACA,gBAAY,IAAI,OAAO,IAAI;AAC3B,QAAI,CAAC,OAAO,SAAS,OAAO,KAAK,GAAG;AAChC,WAAK,YAAY,OAAO,IAAI,mBAAmB,OAAO,KAAK,GAAG;AAAA,IAClE;AACA,mBAAe,OAAO,SAAS,YAAY,OAAO,IAAI,wBAAwB;AAC9E,QAAI,OAAO,YAAY,UAAa,CAAC,CAAC,UAAU,QAAQ,EAAE,SAAS,OAAO,OAAO,GAAG;AAChF,WAAK,YAAY,OAAO,IAAI,sBAAsB,OAAO,OAAO,GAAG;AAAA,IACvE;AACA,QAAI,OAAO,QAAQ,UAAa,CAAC,CAAC,OAAO,OAAO,SAAS,EAAE,SAAS,OAAO,GAAG,GAAG;AAC7E,WAAK,YAAY,OAAO,IAAI,yBAAyB,OAAO,GAAG,GAAG;AAAA,IACtE;AACA,QAAI,OAAO,eAAe,UAAa,EAAE,OAAO,SAAS,OAAO,UAAU,KAAK,OAAO,cAAc,IAAI;AACpG,WAAK,YAAY,OAAO,IAAI,0CAA0C;AAAA,IAC1E;AACA,WAAO,EAAE,GAAG,OAAO;AAAA,EACvB,CAAC;AAED,QAAM,sBAAuC,UAAU,IAAI,QAAM;AAC7D,QAAI,OAAO,GAAG,SAAS,UAAU;AAC7B,WAAK,kBAAkB,GAAG,EAAE,qBAAqB;AAAA,IACrD;AACA,mBAAe,GAAG,SAAS,kBAAkB,GAAG,EAAE,wBAAwB;AAC1E,WAAO,EAAE,GAAG,IAAI,GAAG,OAAO,SAAS,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,OAAO,SAAS,GAAG,CAAC,IAAI,GAAG,IAAI,EAAE;AAAA,EAC7F,CAAC;AAED,QAAM,kBAA+B,MAAM,IAAI,UAAQ;AACnD,mBAAe,KAAK,MAAM,QAAQ,KAAK,EAAE,qBAAqB;AAC9D,QAAI,KAAK,UAAU,CAAC,SAAS,IAAI,KAAK,MAAM,GAAG;AAC3C,WAAK,QAAQ,KAAK,EAAE,2BAA2B,KAAK,MAAM,GAAG;AAAA,IACjE;AACA,WAAO;AAAA,MACH,GAAG;AAAA,MACH,MAAM,KAAK,QAAQ;AAAA,MACnB,QAAQ,KAAK,UAAU;AAAA,MACvB,GAAG,OAAO,SAAS,KAAK,CAAC,IAAI,KAAK,IAAI;AAAA,MACtC,GAAG,OAAO,SAAS,KAAK,CAAC,IAAI,KAAK,IAAI;AAAA,IAC1C;AAAA,EACJ,CAAC;AAED,QAAM,QAAe;AAAA,IACjB,GAAG;AAAA,IACH,SAAS;AAAA,IACT,MAAM,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI;AAAA,IAC7E,SAAS,OAAO,KAAK,YAAY,YAAY,SAAS,IAAI,KAAK,OAAO,IAAI,KAAK,UAAU;AAAA,IACzF,SAAS,KAAK,YAAY;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,OAAO;AAAA,EACX;AAEA,MAAI,MAAM,cAAc,MAAM;AAC1B,WAAO,MAAM;AAAA,EACjB;AACA,SAAO;AACX;AAQO,SAAS,YAAY,MAAuB;AAC/C,MAAI;AACJ,MAAI;AACA,WAAO,KAAK,MAAM,IAAI;AAAA,EAC1B,SAAS,KAAK;AACV,UAAM,IAAI,MAAM,kBAAkB,IAAI,OAAO,EAAE;AAAA,EACnD;AACA,MAAI,SAAS,IAAI,MAAM,KAAK,WAAW,iBAAiB,sBAAsB,SAAS,KAAK,MAAM,IAAI;AAClG,QAAI,OAAO,KAAK,YAAY,YAAY,KAAK,UAAU,qBAAqB;AACxE,YAAM,IAAI,MAAM,qEAAqE,KAAK,OAAO,GAAG;AAAA,IACxG;AACA,QAAI,CAAC,MAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,KAAK,OAAO,QAAQ;AACpD,YAAM,IAAI,MAAM,6BAA6B;AAAA,IACjD;AACA,WAAO,KAAK,OAAO,IAAI,CAAC,OAAY,MAAc,eAAe,OAAO,SAAS,IAAI,CAAC,EAAE,CAAC;AAAA,EAC7F;AACA,MAAI,SAAS,IAAI,KAAK,MAAM,QAAQ,KAAK,MAAM,GAAG;AAC9C,WAAO,CAAC,eAAe,MAAM,OAAO,CAAC;AAAA,EACzC;AACA,QAAM,IAAI,MAAM,uDAAuD;AAC3E;",
|
|
4
|
+
"sourcesContent": ["/*\n * The chart model shared by the editor (admin tab) and the runtime (adapter).\n *\n * A chart is stored as object \"statechart.<instance>.charts.<chartId>\" (type \"channel\"),\n * the model itself lives in `native.chart` of that object.\n */\n\n/** Current version of the chart model, increase on incompatible changes */\nexport const CHART_MODEL_VERSION = 1;\n\n/** Maximum number of transitions in one wakeup with super step semantics, protects against loops */\nexport const MAX_SUPER_STEPS = 100;\n\nexport type SymbolScope = \"input\" | \"output\" | \"local\";\n\nexport type InputTrigger = \"update\" | \"change\";\n\n/** \"ack\": only confirmed values, \"command\": only commands (ack=false) */\nexport type AckFilter = \"any\" | \"ack\" | \"command\";\n\n/**\n * A variable which can be used in conditions and actions.\n * Inputs and outputs are mapped to ioBroker states, locals only live inside the chart.\n */\nexport interface ChartSymbol {\n /** Name used in conditions and actions, must be a valid JavaScript identifier */\n name: string;\n /** Input (read from state), output (written to state) or local */\n scope: SymbolScope;\n /** ioBroker state ID for inputs and outputs */\n stateId?: string;\n /** Initial value for locals */\n initial?: any;\n /** Inputs only: wake up the chart on every update (default) or only on changes */\n trigger?: InputTrigger;\n /** Inputs only: which updates are used, depending on their ack flag, default \"any\" */\n ack?: AckFilter;\n /** Inputs only: wake up the chart only after the input had no update for this time */\n debounceMs?: number;\n}\n\n/** A state of the chart, also a superstate with sub states */\nexport interface ChartState {\n /** Unique and stable ID inside the chart */\n id: string;\n /** Display name, also used for the \"activeState\" state */\n name: string;\n /** ID of the parent state, null/undefined for top level states */\n parent?: string | null;\n /** ID of the initial child state (only for states with exclusive children) */\n initial?: string;\n /**\n * Decomposition of the children: parallel (AND), all children are active at the same time.\n * Default is exclusive (OR), exactly one child is active.\n */\n parallel?: boolean;\n /** Children of a parallel state only: execution order among the siblings, lower is first */\n order?: number;\n /**\n * History junction, only for states with exclusive children: entering the state returns to the child which was\n * active when the state was left last. The initial state is only used when the state is entered the first time.\n */\n history?: boolean;\n /** Action executed when the state is entered */\n entry?: string;\n /** Action executed on every wakeup while the state is active and no transition is taken */\n during?: string;\n /** Action executed when the state is left */\n exit?: string;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Background color in the editor as \"#rrggbb\", the default color (light yellow) if missing (editor only) */\n color?: string;\n /** Position in the editor, relative to the parent state */\n x: number;\n /** Position in the editor, relative to the parent state */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\n/** Format of ChartState.color */\nexport const COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;\n\n/** A transition between two states, or from a state to itself */\nexport interface ChartTransition {\n /** Unique and stable ID inside the chart */\n id: string;\n /** ID of the source state */\n source: string;\n /** ID of the target state */\n target: string;\n /** Transition label in Stateflow syntax: event[condition]{action} */\n label?: string;\n /** Evaluation order of transitions with the same source, lower is first */\n priority?: number;\n /**\n * Only for transitions from a state to one of its own children: leave and enter the source state again.\n * Default is an inner transition, which keeps the source state active.\n */\n reenterParent?: boolean;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Side of the source state where the arrow starts (editor only) */\n sourceHandle?: string;\n /** Side of the target state where the arrow ends (editor only) */\n targetHandle?: string;\n /** Where the arrow starts on the border of the source state, automatic if missing (editor only) */\n sourceAnchor?: EdgeAnchor;\n /** Where the arrow ends on the border of the target state, automatic if missing (editor only) */\n targetAnchor?: EdgeAnchor;\n /** Moves the label away from the middle of the arrow, set by dragging it (editor only) */\n labelOffset?: {\n /** Horizontal distance */\n x: number;\n /** Vertical distance, pointing down */\n y: number;\n };\n}\n\n/** A point on the border of a state, set by dragging an end of a transition in the editor */\nexport interface EdgeAnchor {\n /** The side of the state */\n side: \"top\" | \"right\" | \"bottom\" | \"left\";\n /** Position along the side: 0 = left/top end, 1 = right/bottom end */\n pos: number;\n}\n\n/**\n * A block with JavaScript code, executed once when the chart starts.\n * The functions declared in it can be used in all conditions and actions of the chart.\n */\nexport interface ChartFunction {\n /** Unique and stable ID inside the chart */\n id: string;\n /** JavaScript, usually one or more function declarations */\n code: string;\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n /** Position in the editor */\n x: number;\n /** Position in the editor */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\n/**\n * A note on the canvas of the editor, like an annotation in Stateflow. No influence on the execution.\n */\nexport interface ChartNote {\n /** Unique and stable ID inside the chart */\n id: string;\n /** The text of the note */\n text: string;\n /** ID of the state the note is placed in, it moves together with it */\n parent?: string | null;\n /** Position in the editor, relative to the parent state */\n x: number;\n /** Position in the editor, relative to the parent state */\n y: number;\n /** Size in the editor */\n width?: number;\n /** Size in the editor */\n height?: number;\n}\n\n/** A chart, stored in native.chart of its object, see the top of this file */\nexport interface Chart {\n /** Model version, see CHART_MODEL_VERSION */\n version: number;\n /** Display name */\n name: string;\n /** If the chart is executed by the adapter */\n enabled: boolean;\n /** Continue with the state from before a restart of the adapter, default true */\n restoreState?: boolean;\n /**\n * Super step semantics: after a transition, the chart is checked again right away, until no transition is valid\n * anymore (at most MAX_SUPER_STEPS transitions per wakeup). Default false: one transition per wakeup.\n */\n superStep?: boolean;\n /** ID of the initial top level state (default transition) */\n initial?: string;\n /** The top level states are parallel (AND), see ChartState.parallel */\n parallel?: boolean;\n /** Transitions are drawn with horizontal and vertical lines and right angles instead of curves (editor only) */\n orthogonalTransitions?: boolean;\n /** The variables: inputs, outputs and locals */\n symbols: ChartSymbol[];\n /** All states, nested ones refer to their parent */\n states: ChartState[];\n /** All transitions */\n transitions: ChartTransition[];\n /** Missing in charts created before function blocks existed */\n functions?: ChartFunction[];\n /** Missing in charts created before notes existed */\n notes?: ChartNote[];\n /** Free text for the documentation, no influence on the execution */\n comment?: string;\n}\n\n/** Temporal logic operators, like in Stateflow */\nexport type TemporalOperator = \"after\" | \"before\" | \"at\" | \"every\";\n\nexport const TEMPORAL_OPERATORS: TemporalOperator[] = [\"after\", \"before\", \"at\", \"every\"];\n\n/**\n * A temporal expression in the trigger part of a transition label, measured from entering the source state:\n * - after(n, unit): from n units on\n * - before(n, unit): only during the first n units\n * - at(n, unit): exactly once, after n units\n * - every(n, unit): every n units\n * - op(n, input): the same, counting the wakeups by the input instead of the time\n * - after(n, unit, condition): as soon as the condition is true for n units without interruption\n * - at(\"sunset\", offsetMinutes) or at(\"22:30\"): every day at an astro event or a time of day, not measured from\n * entering the state\n */\nexport interface TemporalExpression {\n /** after, before, at or every */\n operator: TemporalOperator;\n /** at(...) every day: name of an astro event (see ASTRO_EVENTS) or a time of day \"HH:mm\" */\n time?: string;\n /** at(...) every day: minutes added to the time, may be negative */\n offsetMinutes?: number;\n /** Time based: the time in milliseconds */\n ms?: number;\n /** Counting: the number of wakeups by the input */\n count?: number;\n /** Counting: name of the input whose wakeups are counted */\n event?: string;\n /** after(n, unit, condition): the JavaScript expression which must be true for the time */\n condition?: string;\n}\n\n/** The parts of a transition label event[condition]{action}, see parseTransitionLabel() */\nexport interface TransitionLabel {\n /** Name of the triggering event (an input symbol), undefined = any wakeup */\n event?: string;\n /** Temporal transition, e.g. after(5, sec) */\n temporal?: TemporalExpression;\n /** Guard expression */\n condition?: string;\n /** Transition action */\n action?: string;\n}\n\n/** Milliseconds of the time units, they can also be used in conditions and actions, e.g. elapsed(min) */\nexport const TIME_UNITS: Record<string, number> = {\n msec: 1,\n sec: 1000,\n min: 60_000,\n};\n\n/**\n * Creates a new, empty chart. It is paused, the user starts it when it is ready.\n *\n * @param name Display name\n */\nexport function createChart(name: string): Chart {\n return {\n version: CHART_MODEL_VERSION,\n name,\n enabled: false,\n symbols: [],\n states: [],\n transitions: [],\n functions: [],\n notes: [],\n };\n}\n\n/**\n * Converts a display name to an ID which can be used in ioBroker object IDs\n *\n * @param name Display name\n */\nexport function nameToId(name: string): string {\n return (\n name\n .trim()\n .toLowerCase()\n .replace(/\u00E4/g, \"ae\")\n .replace(/\u00F6/g, \"oe\")\n .replace(/\u00FC/g, \"ue\")\n .replace(/\u00DF/g, \"ss\")\n .replace(/[^a-z0-9_-]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\") || \"chart\"\n );\n}\n\n/** A part of a text, used e.g. to underline an error */\nexport interface TextRange {\n /** Index of the first character */\n from: number;\n /** Index after the last character */\n to: number;\n}\n\n/** Positions of the parts in the label text */\nexport interface TransitionLabelRanges {\n /** The name of the event, missing for a temporal expression */\n event?: TextRange;\n /** The whole temporal expression, e.g. after(...) */\n temporal?: TextRange;\n /** The input of a counting temporal expression, e.g. button in after(3, button) */\n temporalEvent?: TextRange;\n /** The condition of after(n, unit, condition) */\n temporalCondition?: TextRange;\n /** Content of [...] without the brackets */\n condition?: TextRange;\n /** Content of {...} without the brackets */\n action?: TextRange;\n}\n\n/**\n * Fills the %s placeholders of a message\n *\n * @param key Message with %s placeholders\n * @param args Values for the placeholders\n */\nexport function formatMessage(key: string, args: string[]): string {\n let i = 0;\n return key.replace(/%s/g, () => args[i++] ?? \"\");\n}\n\n/**\n * Error in the structure of a transition label, knows where in the label the problem is\n */\nexport class LabelSyntaxError extends Error {\n /**\n * @param key Message with %s placeholders, used to translate the message\n * @param args Values for the placeholders\n * @param from Start of the problem in the label\n * @param to End of the problem in the label\n */\n constructor(\n public readonly key: string,\n public readonly args: string[],\n public readonly from: number,\n public readonly to: number,\n ) {\n super(formatMessage(key, args));\n }\n}\n\n/**\n * Reads a part enclosed in brackets, nested brackets of the same type are allowed\n *\n * @param text The label\n * @param start Index of the opening bracket\n * @param open Opening bracket\n * @param close Closing bracket\n * @returns from is the index of the (trimmed) content, end is the index after the closing bracket\n */\nfunction readEnclosed(\n text: string,\n start: number,\n open: string,\n close: string,\n): { content: string; from: number; end: number } {\n let depth = 0;\n for (let i = start; i < text.length; i++) {\n if (text[i] === open) {\n depth++;\n } else if (text[i] === close) {\n depth--;\n if (depth === 0) {\n const raw = text.substring(start + 1, i);\n const content = raw.trim();\n return { content, from: start + 1 + raw.indexOf(content), end: i + 1 };\n }\n }\n }\n throw new LabelSyntaxError('Missing \"%s\"', [close], start, text.length);\n}\n\n/** Astro events which can be used in at(\"sunset\") and astroTime(\"sunset\"), as calculated by suncalc */\nexport const ASTRO_EVENTS = [\n \"sunrise\",\n \"sunriseEnd\",\n \"goldenHourEnd\",\n \"solarNoon\",\n \"goldenHour\",\n \"sunsetStart\",\n \"sunset\",\n \"dusk\",\n \"nauticalDusk\",\n \"night\",\n \"nadir\",\n \"nightEnd\",\n \"nauticalDawn\",\n \"dawn\",\n];\n\n/** A time of day, \"HH:mm\" or \"HH:mm:ss\" */\nexport const TIME_OF_DAY = /^([01]?\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d)?$/;\n\n/** Message for invalid temporal expressions */\nconst INVALID_TEMPORAL =\n 'Invalid temporal expression \"%s\", expected e.g. after(5, sec), every(10, min), after(3, button), after(5, min, condition) or at(\"sunset\", -30)';\n\n/**\n * Splits the arguments of a call at the commas outside of brackets and strings\n *\n * @param text The label\n * @param from Index after the opening bracket\n * @param to Index of the closing bracket\n * @returns the arguments with their position, trimmed\n */\nfunction splitArguments(text: string, from: number, to: number): { text: string; from: number }[] {\n const args: { text: string; from: number }[] = [];\n let depth = 0;\n let quote: string | null = null;\n let start = from;\n const push = (end: number): void => {\n const raw = text.substring(start, end);\n const trimmed = raw.trim();\n args.push({ text: trimmed, from: start + raw.indexOf(trimmed) });\n };\n for (let i = from; i < to; i++) {\n const c = text[i];\n if (quote) {\n if (c === \"\\\\\") {\n i++;\n } else if (c === quote) {\n quote = null;\n }\n } else if (c === '\"' || c === \"'\" || c === \"`\") {\n quote = c;\n } else if (\"([{\".includes(c)) {\n depth++;\n } else if (\")]}\".includes(c)) {\n depth--;\n } else if (c === \",\" && depth === 0) {\n push(i);\n start = i + 1;\n }\n }\n push(to);\n return args;\n}\n\n/**\n * Parses the arguments of a temporal expression\n *\n * @param text The label\n * @param operator The operator\n * @param from Start of the expression (the operator)\n * @param open Index of the opening bracket\n * @param end Index after the closing bracket\n * @returns the expression and the positions of its input and condition\n * @throws {LabelSyntaxError}\n */\nfunction parseTemporal(\n text: string,\n operator: TemporalOperator,\n from: number,\n open: number,\n end: number,\n): { temporal: TemporalExpression; event?: TextRange; condition?: TextRange } {\n const fail = (): never => {\n throw new LabelSyntaxError(INVALID_TEMPORAL, [text.substring(from, end)], from, end);\n };\n const args = splitArguments(text, open + 1, end - 1);\n const quoted = /^([\"'])(.*)\\1$/.exec(args[0]?.text ?? \"\");\n if (quoted) {\n // every day at an astro event or a time of day: at(\"sunset\", -30)\n const time = quoted[2].trim();\n if (operator !== \"at\" || args.length > 2) {\n fail();\n }\n if (!ASTRO_EVENTS.includes(time) && !TIME_OF_DAY.test(time)) {\n throw new LabelSyntaxError(\n 'Unknown time \"%s\", use a time like \"22:30\" or one of: %s',\n [time, ASTRO_EVENTS.join(\", \")],\n args[0].from,\n args[0].from + args[0].text.length,\n );\n }\n const temporal: TemporalExpression = { operator, time };\n if (args.length === 2) {\n temporal.offsetMinutes = /^[-+]?\\d+(?:\\.\\d+)?$/.test(args[1].text) ? parseFloat(args[1].text) : fail();\n }\n return { temporal };\n }\n const number = /^\\d+(?:\\.\\d+)?$/.test(args[0]?.text) ? parseFloat(args[0].text) : fail();\n const unit = args[1]?.text ?? \"\";\n // every(0, sec) would never end\n if (operator === \"every\" && number === 0) {\n fail();\n }\n if (Object.hasOwn(TIME_UNITS, unit)) {\n const temporal: TemporalExpression = { operator, ms: number * TIME_UNITS[unit] };\n if (args.length === 3 && operator === \"after\" && args[2].text) {\n temporal.condition = args[2].text;\n return { temporal, condition: { from: args[2].from, to: args[2].from + args[2].text.length } };\n }\n return args.length === 2 ? { temporal } : fail();\n }\n // counting the wakeups by an input\n if (args.length !== 2 || !/^[A-Za-z_$][\\w$]*$/.test(unit) || !Number.isInteger(number) || number < 1) {\n fail();\n }\n return {\n temporal: { operator, count: number, event: unit },\n event: { from: args[1].from, to: args[1].from + unit.length },\n };\n}\n\n/**\n * Parses a transition label and returns where its parts are, see parseTransitionLabel\n *\n * @param label The label text\n * @throws {LabelSyntaxError}\n */\nexport function parseTransitionLabelWithRanges(label: string | undefined): {\n label: TransitionLabel;\n ranges: TransitionLabelRanges;\n} {\n const result: TransitionLabel = {};\n const ranges: TransitionLabelRanges = {};\n const text = label || \"\";\n let pos = 0;\n\n const skipSpace = (): void => {\n while (pos < text.length && /\\s/.test(text[pos])) {\n pos++;\n }\n };\n\n skipSpace();\n const eventMatch = /[A-Za-z_$][\\w$]*/y;\n eventMatch.lastIndex = pos;\n const event = eventMatch.exec(text);\n if (event) {\n const from = pos;\n pos += event[0].length;\n skipSpace();\n if (TEMPORAL_OPERATORS.includes(event[0] as TemporalOperator) && text[pos] === \"(\") {\n const { end } = readEnclosed(text, pos, \"(\", \")\");\n const parsed = parseTemporal(text, event[0] as TemporalOperator, from, pos, end);\n result.temporal = parsed.temporal;\n ranges.temporal = { from, to: end };\n if (parsed.event) {\n ranges.temporalEvent = parsed.event;\n }\n if (parsed.condition) {\n ranges.temporalCondition = parsed.condition;\n }\n pos = end;\n } else {\n result.event = event[0];\n ranges.event = { from, to: from + event[0].length };\n }\n }\n\n skipSpace();\n if (text[pos] === \"[\") {\n const { content, from, end } = readEnclosed(text, pos, \"[\", \"]\");\n result.condition = content;\n ranges.condition = { from, to: from + content.length };\n pos = end;\n }\n\n skipSpace();\n if (text[pos] === \"{\") {\n const { content, from, end } = readEnclosed(text, pos, \"{\", \"}\");\n result.action = content;\n ranges.action = { from, to: from + content.length };\n pos = end;\n }\n\n skipSpace();\n if (pos < text.length) {\n throw new LabelSyntaxError(\n 'Unexpected \"%s\", expected event[condition]{action}',\n [text.substring(pos).trim()],\n pos,\n text.length,\n );\n }\n return { label: result, ranges };\n}\n\n/**\n * Parses a transition label in Stateflow syntax: event[condition]{action}\n * All parts are optional. Instead of an event, a temporal expression like after(n, sec|msec|min) creates a\n * temporal transition, see TemporalExpression.\n *\n * @param label The label text\n * @throws {LabelSyntaxError}\n */\nexport function parseTransitionLabel(label: string | undefined): TransitionLabel {\n return parseTransitionLabelWithRanges(label).label;\n}\n\n/** Identifies files with exported charts */\nexport const EXPORT_FORMAT = \"iobroker.statechart\";\n\n/** Files exported before the adapter was renamed from \"state-machine\" to \"statechart\" */\nconst LEGACY_EXPORT_FORMATS = [\"iobroker.state-machine\"];\n\n/** The content of an export file */\nexport interface ChartExport {\n /** Identifies the file as export of this adapter, see EXPORT_FORMAT */\n format: string;\n /** Version of the chart model, see CHART_MODEL_VERSION */\n version: number;\n /** Time of the export as ISO string */\n exported: string;\n /** The exported charts */\n charts: Chart[];\n}\n\n/**\n * The content of an export file\n *\n * @param charts The exported charts\n */\nexport function createExport(charts: Chart[]): ChartExport {\n return { format: EXPORT_FORMAT, version: CHART_MODEL_VERSION, exported: new Date().toISOString(), charts };\n}\n\nconst IDENTIFIER = /^[A-Za-z_$][\\w$]*$/;\nconst SCOPES = [\"input\", \"output\", \"local\"];\n\nfunction isObject(value: any): value is Record<string, any> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Checks a chart of an export file and fills in defaults for missing optional values\n *\n * @param data The chart as read from the file\n * @param where Prefix of error messages, e.g. \"Chart 1\"\n * @throws {Error} if the chart is invalid\n */\nfunction normalizeChart(data: any, where: string): Chart {\n const fail = (message: string): never => {\n throw new Error(`${where}: ${message}`);\n };\n if (!isObject(data)) {\n fail(\"not an object\");\n }\n if (typeof data.version === \"number\" && data.version > CHART_MODEL_VERSION) {\n fail(`created with a newer version of the adapter (chart version ${data.version})`);\n }\n for (const list of [\"states\", \"transitions\", \"symbols\"]) {\n if (!Array.isArray(data[list])) {\n fail(`\"${list}\" is missing or no list`);\n }\n }\n for (const list of [\"functions\", \"notes\"]) {\n if (data[list] !== undefined && !Array.isArray(data[list])) {\n fail(`\"${list}\" is no list`);\n }\n }\n const functions: any[] = data.functions || [];\n const notes: any[] = data.notes || [];\n\n // states, function blocks and notes are all nodes in the editor, so their IDs must be unique together\n const nodeIds = new Set<string>();\n const checkId = (item: any, kind: string, index: number): string => {\n if (!isObject(item) || typeof item.id !== \"string\" || !item.id) {\n fail(`${kind} ${index + 1} has no ID`);\n }\n if (nodeIds.has(item.id)) {\n fail(`${kind} ${item.id}: the ID is used more than once`);\n }\n nodeIds.add(item.id);\n return item.id;\n };\n const optionalString = (value: any, message: string): void => {\n if (value !== undefined && value !== null && typeof value !== \"string\") {\n fail(message);\n }\n };\n\n data.states.forEach((state: any, i: number) => checkId(state, \"state\", i));\n functions.forEach((fn, i) => checkId(fn, \"function block\", i));\n notes.forEach((note, i) => checkId(note, \"note\", i));\n const stateIds = new Set(data.states.map((s: any) => s.id));\n optionalString(data.comment, '\"comment\" is no text');\n\n const states: ChartState[] = data.states.map((state: any) => {\n const at = `state ${state.id}`;\n if (state.parent && !stateIds.has(state.parent)) {\n fail(`${at}: unknown parent state \"${state.parent}\"`);\n }\n for (const field of [\"entry\", \"during\", \"exit\", \"initial\", \"comment\"]) {\n optionalString(state[field], `${at}: \"${field}\" is no text`);\n }\n if (state.order !== undefined && !Number.isFinite(state.order)) {\n fail(`${at}: \"order\" is no number`);\n }\n if (state.color !== undefined && !(typeof state.color === \"string\" && COLOR_PATTERN.test(state.color))) {\n fail(`${at}: \"color\" is no color like \"#d6eaf8\"`);\n }\n const { parallel, history, ...rest } = state;\n return {\n ...rest,\n // the defaults (exclusive, no history) are not stored, like in the editor\n ...(parallel === true ? { parallel } : {}),\n ...(history === true ? { history } : {}),\n name: typeof state.name === \"string\" && state.name ? state.name : state.id,\n parent: state.parent || null,\n x: Number.isFinite(state.x) ? state.x : 0,\n y: Number.isFinite(state.y) ? state.y : 0,\n };\n });\n\n // a parent must not be its own (indirect) child\n const parentOf = new Map(states.map(s => [s.id, s.parent]));\n for (const state of states) {\n let parent = state.parent;\n for (let i = 0; parent; i++) {\n if (parent === state.id || i > states.length) {\n fail(`state ${state.id}: the parent states form a cycle`);\n }\n parent = parentOf.get(parent) ?? null;\n }\n }\n\n const transitionIds = new Set<string>();\n const transitions: ChartTransition[] = data.transitions.map((transition: any, i: number) => {\n if (!isObject(transition) || typeof transition.id !== \"string\" || !transition.id) {\n fail(`transition ${i + 1} has no ID`);\n }\n const at = `transition ${transition.id}`;\n if (transitionIds.has(transition.id)) {\n fail(`${at}: the ID is used more than once`);\n }\n transitionIds.add(transition.id);\n for (const end of [\"source\", \"target\"]) {\n if (!stateIds.has(transition[end])) {\n fail(`${at}: unknown ${end} state \"${transition[end]}\"`);\n }\n }\n optionalString(transition.label, `${at}: \"label\" is no text`);\n optionalString(transition.comment, `${at}: \"comment\" is no text`);\n if (transition.priority !== undefined && !Number.isFinite(transition.priority)) {\n fail(`${at}: \"priority\" is no number`);\n }\n const { labelOffset, ...rest } = transition;\n // only the position of the label, an invalid one is dropped instead of rejecting the chart\n const validOffset = isObject(labelOffset) && Number.isFinite(labelOffset.x) && Number.isFinite(labelOffset.y);\n return { ...rest, ...(validOffset ? { labelOffset: { x: labelOffset.x, y: labelOffset.y } } : {}) };\n });\n\n const symbolNames = new Set<string>();\n const symbols: ChartSymbol[] = data.symbols.map((symbol: any, i: number) => {\n if (!isObject(symbol) || typeof symbol.name !== \"string\" || !IDENTIFIER.test(symbol.name)) {\n fail(`variable ${i + 1}: invalid name`);\n }\n if (symbolNames.has(symbol.name)) {\n fail(`variable ${symbol.name}: the name is used more than once`);\n }\n symbolNames.add(symbol.name);\n if (!SCOPES.includes(symbol.scope)) {\n fail(`variable ${symbol.name}: invalid kind \"${symbol.scope}\"`);\n }\n optionalString(symbol.stateId, `variable ${symbol.name}: \"stateId\" is no text`);\n if (symbol.trigger !== undefined && ![\"update\", \"change\"].includes(symbol.trigger)) {\n fail(`variable ${symbol.name}: invalid trigger \"${symbol.trigger}\"`);\n }\n if (symbol.ack !== undefined && ![\"any\", \"ack\", \"command\"].includes(symbol.ack)) {\n fail(`variable ${symbol.name}: invalid ack filter \"${symbol.ack}\"`);\n }\n if (symbol.debounceMs !== undefined && !(Number.isFinite(symbol.debounceMs) && symbol.debounceMs >= 0)) {\n fail(`variable ${symbol.name}: \"debounceMs\" is no number of 0 or more`);\n }\n return { ...symbol };\n });\n\n const normalizedFunctions: ChartFunction[] = functions.map(fn => {\n if (typeof fn.code !== \"string\") {\n fail(`function block ${fn.id}: \"code\" is no text`);\n }\n optionalString(fn.comment, `function block ${fn.id}: \"comment\" is no text`);\n return { ...fn, x: Number.isFinite(fn.x) ? fn.x : 0, y: Number.isFinite(fn.y) ? fn.y : 0 };\n });\n\n const normalizedNotes: ChartNote[] = notes.map(note => {\n optionalString(note.text, `note ${note.id}: \"text\" is no text`);\n if (note.parent && !stateIds.has(note.parent)) {\n fail(`note ${note.id}: unknown parent state \"${note.parent}\"`);\n }\n return {\n ...note,\n text: note.text || \"\",\n parent: note.parent || null,\n x: Number.isFinite(note.x) ? note.x : 0,\n y: Number.isFinite(note.y) ? note.y : 0,\n };\n });\n\n const chart: Chart = {\n ...data,\n version: CHART_MODEL_VERSION,\n name: typeof data.name === \"string\" && data.name.trim() ? data.name.trim() : where,\n initial: typeof data.initial === \"string\" && stateIds.has(data.initial) ? data.initial : undefined,\n enabled: data.enabled !== false,\n symbols,\n states,\n transitions,\n functions: normalizedFunctions,\n notes: normalizedNotes,\n };\n // the default (off) is not stored, like in the editor\n if (chart.superStep !== true) {\n delete chart.superStep;\n }\n if (chart.parallel !== true) {\n delete chart.parallel;\n }\n if (chart.orthogonalTransitions !== true) {\n delete chart.orthogonalTransitions;\n }\n return chart;\n}\n\n/**\n * Reads the charts of an export file. A single chart (without the export wrapper) is accepted as well.\n *\n * @param text Content of the file\n * @throws {Error} if the file is invalid\n */\nexport function parseExport(text: string): Chart[] {\n let data;\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new Error(`No valid JSON: ${err.message}`);\n }\n if (isObject(data) && (data.format === EXPORT_FORMAT || LEGACY_EXPORT_FORMATS.includes(data.format))) {\n if (typeof data.version === \"number\" && data.version > CHART_MODEL_VERSION) {\n throw new Error(`The file was created with a newer version of the adapter (version ${data.version})`);\n }\n if (!Array.isArray(data.charts) || !data.charts.length) {\n throw new Error(\"The file contains no charts\");\n }\n return data.charts.map((chart: any, i: number) => normalizeChart(chart, `Chart ${i + 1}`));\n }\n if (isObject(data) && Array.isArray(data.states)) {\n return [normalizeChart(data, \"Chart\")];\n }\n throw new Error(\"The file contains no charts of the statechart adapter\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|