iobroker.statechart 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +59 -438
- package/admin/build/tab.js +133 -130
- package/admin/statechart.png +0 -0
- package/admin/{style.css → tab.css} +0 -2
- package/admin/tab_m.html +1 -1
- package/build/lib/chart-analysis.js +367 -0
- package/build/lib/chart-analysis.js.map +7 -0
- package/build/lib/chart-codegen.js +405 -0
- package/build/lib/chart-codegen.js.map +7 -0
- package/build/lib/chart-helpers.js +102 -0
- package/build/lib/chart-helpers.js.map +7 -0
- package/build/lib/chart-model.js +477 -0
- package/build/lib/chart-model.js.map +7 -0
- package/build/lib/chart-runtime.js +1521 -0
- package/build/lib/chart-runtime.js.map +7 -0
- package/build/lib/chart-structure.js +172 -0
- package/build/lib/chart-structure.js.map +7 -0
- package/build/lib/chart-validation.js +372 -0
- package/build/lib/chart-validation.js.map +7 -0
- package/build/main.js +638 -0
- package/build/main.js.map +7 -0
- package/io-package.json +31 -34
- package/package.json +21 -17
- package/admin/i18n/de.json +0 -4
- package/admin/i18n/en.json +0 -4
- package/admin/i18n/es.json +0 -4
- package/admin/i18n/fr.json +0 -4
- package/admin/i18n/it.json +0 -4
- package/admin/i18n/nl.json +0 -4
- package/admin/i18n/pl.json +0 -4
- package/admin/i18n/pt.json +0 -4
- package/admin/i18n/ru.json +0 -4
- package/admin/i18n/uk.json +0 -4
- package/admin/i18n/zh-cn.json +0 -4
- package/admin/jsonConfig.json +0 -19
- package/admin/statechart.svg +0 -38
- package/lib/adapter-config.d.ts +0 -19
- package/lib/chart-codegen.js +0 -436
- package/lib/chart-codegen.test.js +0 -132
- package/lib/chart-helpers.js +0 -74
- package/lib/chart-helpers.test.js +0 -38
- package/lib/chart-model.js +0 -577
- package/lib/chart-model.test.js +0 -189
- package/lib/chart-runtime.js +0 -797
- package/lib/chart-runtime.test.js +0 -699
- package/lib/chart-structure.js +0 -106
- package/lib/chart-validation.js +0 -328
- package/lib/chart-validation.test.js +0 -149
- package/main.js +0 -279
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var chart_codegen_exports = {};
|
|
20
|
+
__export(chart_codegen_exports, {
|
|
21
|
+
generateChartCode: () => generateChartCode
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(chart_codegen_exports);
|
|
24
|
+
var import_chart_helpers = require("./chart-helpers");
|
|
25
|
+
var import_chart_model = require("./chart-model");
|
|
26
|
+
var import_chart_structure = require("./chart-structure");
|
|
27
|
+
const INDENT = " ";
|
|
28
|
+
function indent(text, level) {
|
|
29
|
+
const prefix = INDENT.repeat(level);
|
|
30
|
+
return text.split("\n").map((line) => line.trim() ? prefix + line : "").join("\n");
|
|
31
|
+
}
|
|
32
|
+
function oneLine(text) {
|
|
33
|
+
return (text || "").replace(/\s+/g, " ").trim();
|
|
34
|
+
}
|
|
35
|
+
function commentLines(text, prefix = "", indentation = "") {
|
|
36
|
+
if (!text?.trim()) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
return text.trim().split("\n").map((line, i) => `${indentation}// ${i ? " ".repeat(prefix.length) : prefix}${line.trimEnd()}`.trimEnd());
|
|
40
|
+
}
|
|
41
|
+
function identifier(id) {
|
|
42
|
+
const name = id.replace(/[^\w$]/g, "_");
|
|
43
|
+
return /^\d/.test(name) ? `_${name}` : name;
|
|
44
|
+
}
|
|
45
|
+
function propertyKey(key) {
|
|
46
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
47
|
+
}
|
|
48
|
+
function dedent(code) {
|
|
49
|
+
const lines = code.replace(/\s+$/, "").replace(/^\s*\n/, "").split("\n");
|
|
50
|
+
const common = Math.min(...lines.filter((l) => l.trim()).map((l) => /^\s*/.exec(l)?.[0].length ?? 0));
|
|
51
|
+
return lines.map((l) => l.substring(Number.isFinite(common) ? common : 0)).join("\n");
|
|
52
|
+
}
|
|
53
|
+
function actionFunction(code, level) {
|
|
54
|
+
if (!code?.trim()) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return `() => {
|
|
58
|
+
${indent(dedent(code), level + 1)}
|
|
59
|
+
${INDENT.repeat(level)}}`;
|
|
60
|
+
}
|
|
61
|
+
function generateChartCode(chart, chartId) {
|
|
62
|
+
const structure = new import_chart_structure.ChartStructure(chart);
|
|
63
|
+
const stateName = (id) => structure.statesById.get(id)?.name ?? id;
|
|
64
|
+
const parse = (transition) => {
|
|
65
|
+
if (!structure.statesById.has(transition.target)) {
|
|
66
|
+
return { error: "unknown target" };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return { label: (0, import_chart_model.parseTransitionLabel)(transition.label) };
|
|
70
|
+
} catch (err) {
|
|
71
|
+
return { error: err.message };
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const describe = (transition) => `${stateName(transition.source)} -> ${stateName(transition.target)}${transition.label?.trim() ? `: ${oneLine(transition.label)}` : ""}`;
|
|
75
|
+
const lines = [
|
|
76
|
+
`// Code generated from the chart "${oneLine(chart.name)}" by the statechart adapter.`,
|
|
77
|
+
"// It shows how the adapter executes the chart. It is not executed itself, changes here have no effect.",
|
|
78
|
+
"",
|
|
79
|
+
...chart.comment?.trim() ? [...commentLines(chart.comment), ""] : [],
|
|
80
|
+
...(chart.notes || []).flatMap((note) => [...commentLines(note.text, "Note: "), ""]),
|
|
81
|
+
'const { createActor, createMachine } = require("xstate");',
|
|
82
|
+
""
|
|
83
|
+
];
|
|
84
|
+
lines.push("// ---------- Variables ----------", "");
|
|
85
|
+
const outputs = chart.symbols.filter((s) => s.scope === "output" && s.stateId);
|
|
86
|
+
if (!chart.symbols.length) {
|
|
87
|
+
lines.push("// no variables");
|
|
88
|
+
}
|
|
89
|
+
for (const symbol of chart.symbols) {
|
|
90
|
+
if (symbol.scope === "local") {
|
|
91
|
+
lines.push(`let ${symbol.name} = ${JSON.stringify(symbol.initial) ?? "undefined"}; // local`);
|
|
92
|
+
} else if (!symbol.stateId) {
|
|
93
|
+
lines.push(`let ${symbol.name}; // ${symbol.scope} without state`);
|
|
94
|
+
} else if (symbol.scope === "input") {
|
|
95
|
+
const trigger = [
|
|
96
|
+
symbol.trigger === "change" ? "on value changes" : "on every update",
|
|
97
|
+
symbol.ack === "ack" ? "only confirmed values (ack = true)" : "",
|
|
98
|
+
symbol.ack === "command" ? "only commands (ack = false)" : "",
|
|
99
|
+
symbol.debounceMs ? `after ${symbol.debounceMs} ms without updates` : ""
|
|
100
|
+
].filter(Boolean).join(", ");
|
|
101
|
+
lines.push(
|
|
102
|
+
`let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)})?.val; // input, wakes up the chart ${trigger}`
|
|
103
|
+
);
|
|
104
|
+
} else {
|
|
105
|
+
lines.push(
|
|
106
|
+
`let ${symbol.name} = getState(${JSON.stringify(symbol.stateId)})?.val; // output, see writeChangedOutputs()`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (outputs.length) {
|
|
111
|
+
lines.push("", "// the last written value of each output");
|
|
112
|
+
lines.push(`const written = { ${outputs.map((s) => s.name).join(", ")} };`);
|
|
113
|
+
}
|
|
114
|
+
lines.push("");
|
|
115
|
+
for (const fn of chart.functions || []) {
|
|
116
|
+
if (fn.code.trim()) {
|
|
117
|
+
lines.push("// ---------- Function block ----------", "", ...commentLines(fn.comment), dedent(fn.code), "");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
lines.push(
|
|
121
|
+
"// ---------- State machine ----------",
|
|
122
|
+
"",
|
|
123
|
+
"// The transitions are selected by the process functions below (Stateflow order),",
|
|
124
|
+
"// XState only executes them: exit actions, transition action, entry actions.",
|
|
125
|
+
"const machine = createMachine({",
|
|
126
|
+
`${INDENT}id: ${JSON.stringify(`chart_${chartId}`)},`
|
|
127
|
+
);
|
|
128
|
+
const transitionConfig = (transition, kind, label, level) => {
|
|
129
|
+
const parts = [`target: ${JSON.stringify(`#${structure.getTargetId(transition)}`)}`];
|
|
130
|
+
if (kind.reenter) {
|
|
131
|
+
parts.push("reenter: true");
|
|
132
|
+
}
|
|
133
|
+
const action = actionFunction(label.action, level);
|
|
134
|
+
if (action) {
|
|
135
|
+
parts.push(`actions: ${action}`);
|
|
136
|
+
}
|
|
137
|
+
return `{ ${parts.join(", ")} }`;
|
|
138
|
+
};
|
|
139
|
+
const buildState = (state, level) => {
|
|
140
|
+
const i1 = INDENT.repeat(level);
|
|
141
|
+
const i2 = INDENT.repeat(level + 1);
|
|
142
|
+
const i3 = INDENT.repeat(level + 2);
|
|
143
|
+
lines.push(
|
|
144
|
+
`${i1}// ${oneLine(state.name)}`,
|
|
145
|
+
...commentLines(state.comment, "", i1),
|
|
146
|
+
`${i1}${propertyKey(state.id)}: {`
|
|
147
|
+
);
|
|
148
|
+
lines.push(`${i2}id: ${JSON.stringify(state.id)},`);
|
|
149
|
+
for (const field of ["entry", "exit"]) {
|
|
150
|
+
const action = actionFunction(state[field], level + 1);
|
|
151
|
+
if (action) {
|
|
152
|
+
lines.push(`${i2}${field}: ${action},`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const on = [];
|
|
156
|
+
for (const transition of structure.getTransitions(state.id)) {
|
|
157
|
+
const parsed = parse(transition);
|
|
158
|
+
if ("error" in parsed) {
|
|
159
|
+
on.push(`${i3}// ${describe(transition)}: ignored, ${parsed.error}`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const config = transitionConfig(
|
|
163
|
+
transition,
|
|
164
|
+
structure.getTransitionKind(transition),
|
|
165
|
+
parsed.label,
|
|
166
|
+
level + 2
|
|
167
|
+
);
|
|
168
|
+
on.push(
|
|
169
|
+
`${i3}// ${describe(transition)}`,
|
|
170
|
+
...commentLines(transition.comment, "", i3),
|
|
171
|
+
`${i3}${JSON.stringify(`T.${transition.id}`)}: ${config},`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
if (on.length) {
|
|
175
|
+
lines.push(`${i2}on: {`, ...on, `${i2}},`);
|
|
176
|
+
}
|
|
177
|
+
const children = structure.getChildren(state.id);
|
|
178
|
+
if (children.length) {
|
|
179
|
+
lines.push(
|
|
180
|
+
structure.isParallel(state.id) ? `${i2}type: "parallel", // all sub states are active, entered in their execution order` : `${i2}initial: ${JSON.stringify(structure.getInitialChild(state.id))},`,
|
|
181
|
+
`${i2}states: {`
|
|
182
|
+
);
|
|
183
|
+
for (const child of children) {
|
|
184
|
+
buildState(child, level + 2);
|
|
185
|
+
}
|
|
186
|
+
if (structure.hasHistory(state.id)) {
|
|
187
|
+
const id = `${state.id}${import_chart_structure.HISTORY_SUFFIX}`;
|
|
188
|
+
lines.push(
|
|
189
|
+
`${i3}// history junction: returns to the last active sub state, the first time to the initial one`,
|
|
190
|
+
`${i3}${JSON.stringify(import_chart_structure.HISTORY_SUFFIX)}: { id: ${JSON.stringify(id)}, type: "history" },`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
lines.push(`${i2}},`);
|
|
194
|
+
}
|
|
195
|
+
lines.push(`${i1}},`);
|
|
196
|
+
};
|
|
197
|
+
const topLevel = structure.getChildren(null);
|
|
198
|
+
if (topLevel.length) {
|
|
199
|
+
lines.push(
|
|
200
|
+
structure.isParallel(null) ? `${INDENT}type: "parallel", // all top level states are active, entered in their execution order` : `${INDENT}initial: ${JSON.stringify(structure.getInitialChild(null))},`,
|
|
201
|
+
`${INDENT}states: {`
|
|
202
|
+
);
|
|
203
|
+
for (const state of topLevel) {
|
|
204
|
+
buildState(state, 2);
|
|
205
|
+
}
|
|
206
|
+
lines.push(`${INDENT}},`);
|
|
207
|
+
}
|
|
208
|
+
lines.push(
|
|
209
|
+
"});",
|
|
210
|
+
"",
|
|
211
|
+
"const actor = createActor(machine);",
|
|
212
|
+
"actor.start();",
|
|
213
|
+
"// once right after the start, so transitions without event are taken without waiting for an input",
|
|
214
|
+
"wakeup(null);",
|
|
215
|
+
""
|
|
216
|
+
);
|
|
217
|
+
const callActive = (states, level, prefix) => states.map(
|
|
218
|
+
(s) => `${INDENT.repeat(level)}if (isActive(${JSON.stringify(s.id)})) {
|
|
219
|
+
${INDENT.repeat(level + 1)}${prefix}process_${identifier(s.id)}(input);
|
|
220
|
+
${INDENT.repeat(level)}}`
|
|
221
|
+
);
|
|
222
|
+
const processChildren = (parent, children) => {
|
|
223
|
+
if (!structure.isParallel(parent)) {
|
|
224
|
+
return [...callActive(children, 1, "return "), `${INDENT}return false;`];
|
|
225
|
+
}
|
|
226
|
+
const lines2 = [
|
|
227
|
+
`${INDENT}// all sub states are active (parallel), they are processed in their execution order.`,
|
|
228
|
+
`${INDENT}// A transition in one of them does not stop the others, unless it left this state.`,
|
|
229
|
+
...parent ? [`${INDENT}const entries = entryCount(${JSON.stringify(parent)});`] : [],
|
|
230
|
+
`${INDENT}let taken = false;`
|
|
231
|
+
];
|
|
232
|
+
children.forEach((child, i) => {
|
|
233
|
+
if (i && parent) {
|
|
234
|
+
lines2.push(
|
|
235
|
+
`${INDENT}if (!isActive(${JSON.stringify(parent)}) || entryCount(${JSON.stringify(parent)}) !== entries) {`,
|
|
236
|
+
`${INDENT}${INDENT}return true; // left (and maybe entered again) by the transition`,
|
|
237
|
+
`${INDENT}}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
lines2.push(`${INDENT}taken = process_${identifier(child.id)}(input) || taken;`);
|
|
241
|
+
});
|
|
242
|
+
lines2.push(`${INDENT}return taken;`);
|
|
243
|
+
return lines2;
|
|
244
|
+
};
|
|
245
|
+
lines.push(
|
|
246
|
+
"// ---------- Wakeup ----------",
|
|
247
|
+
"",
|
|
248
|
+
"/**",
|
|
249
|
+
" * Called once for every change of an input, after its variable got the new value,",
|
|
250
|
+
" * when the time of an after(...) of an active state has come, and once after the start",
|
|
251
|
+
" * (input is null for the last two).",
|
|
252
|
+
" * Starting with the outermost active state, each active state is processed, see process_...().",
|
|
253
|
+
" *",
|
|
254
|
+
" * @param {string | null} input name of the changed input",
|
|
255
|
+
" */",
|
|
256
|
+
"function wakeup(input) {",
|
|
257
|
+
...chart.superStep ? [
|
|
258
|
+
`${INDENT}// super step: take transitions until none is valid anymore, at most ${import_chart_model.MAX_SUPER_STEPS}.`,
|
|
259
|
+
`${INDENT}// The event of the input is only present in the first step.`,
|
|
260
|
+
`${INDENT}for (let steps = 0; steps < ${import_chart_model.MAX_SUPER_STEPS} && step(input); steps++) {`,
|
|
261
|
+
`${INDENT}${INDENT}input = null;`,
|
|
262
|
+
`${INDENT}}`
|
|
263
|
+
] : [`${INDENT}step(input);`],
|
|
264
|
+
`${INDENT}writeChangedOutputs();`,
|
|
265
|
+
"}",
|
|
266
|
+
"",
|
|
267
|
+
"/**",
|
|
268
|
+
" * Processes the active states once",
|
|
269
|
+
" *",
|
|
270
|
+
" * @param {string | null} input name of the changed input, null if the step has no event",
|
|
271
|
+
" * @returns {boolean} true if a transition was taken",
|
|
272
|
+
" */",
|
|
273
|
+
"function step(input) {",
|
|
274
|
+
...processChildren(null, topLevel),
|
|
275
|
+
"}",
|
|
276
|
+
""
|
|
277
|
+
);
|
|
278
|
+
const temporalCheck = (transition, temporal) => {
|
|
279
|
+
const id = JSON.stringify(transition.id);
|
|
280
|
+
const source = JSON.stringify(transition.source);
|
|
281
|
+
if (temporal.event !== void 0) {
|
|
282
|
+
const event = JSON.stringify(temporal.event);
|
|
283
|
+
const count = `inputCount(${source}, ${event})`;
|
|
284
|
+
const checks = {
|
|
285
|
+
after: `${count} >= ${temporal.count}`,
|
|
286
|
+
before: `${count} < ${temporal.count}`,
|
|
287
|
+
at: `${count} === ${temporal.count}`,
|
|
288
|
+
every: `${count} % ${temporal.count} === 0`
|
|
289
|
+
};
|
|
290
|
+
return `input === ${event} && ${checks[temporal.operator]}`;
|
|
291
|
+
}
|
|
292
|
+
if (temporal.condition !== void 0) {
|
|
293
|
+
return `trueFor(${id}) >= ${temporal.ms}`;
|
|
294
|
+
}
|
|
295
|
+
switch (temporal.operator) {
|
|
296
|
+
case "after":
|
|
297
|
+
return `timeInState(${source}) >= ${temporal.ms}`;
|
|
298
|
+
case "before":
|
|
299
|
+
return `timeInState(${source}) < ${temporal.ms}`;
|
|
300
|
+
default:
|
|
301
|
+
return `timerFired(${id})`;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
const check = (transition, label) => {
|
|
305
|
+
const conditions = [];
|
|
306
|
+
if (label.event) {
|
|
307
|
+
conditions.push(`input === ${JSON.stringify(label.event)}`);
|
|
308
|
+
}
|
|
309
|
+
if (label.temporal) {
|
|
310
|
+
conditions.push(temporalCheck(transition, label.temporal));
|
|
311
|
+
}
|
|
312
|
+
if (label.condition) {
|
|
313
|
+
conditions.push(`(${label.condition})`);
|
|
314
|
+
}
|
|
315
|
+
return [
|
|
316
|
+
`${INDENT}// ${describe(transition)}`,
|
|
317
|
+
...commentLines(transition.comment, "", INDENT),
|
|
318
|
+
`${INDENT}if (${conditions.join(" && ") || "true"}) {`,
|
|
319
|
+
`${INDENT}${INDENT}actor.send({ type: ${JSON.stringify(`T.${transition.id}`)} });`,
|
|
320
|
+
`${INDENT}${INDENT}return true;`,
|
|
321
|
+
`${INDENT}}`
|
|
322
|
+
];
|
|
323
|
+
};
|
|
324
|
+
for (const state of chart.states) {
|
|
325
|
+
const outer = [];
|
|
326
|
+
const inner = [];
|
|
327
|
+
for (const transition of structure.getTransitions(state.id)) {
|
|
328
|
+
const parsed = parse(transition);
|
|
329
|
+
if ("error" in parsed) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
(structure.getTransitionKind(transition).inner ? inner : outer).push(...check(transition, parsed.label));
|
|
333
|
+
}
|
|
334
|
+
const children = structure.getChildren(state.id);
|
|
335
|
+
lines.push(
|
|
336
|
+
"/**",
|
|
337
|
+
` * ${oneLine(state.name)}`,
|
|
338
|
+
...state.comment?.trim() ? [
|
|
339
|
+
" *",
|
|
340
|
+
// "*/" would end the comment
|
|
341
|
+
...state.comment.trim().split("\n").map((line) => ` * ${line.trimEnd().replace(/\*\//g, "* /")}`.trimEnd())
|
|
342
|
+
] : [],
|
|
343
|
+
" *",
|
|
344
|
+
" * @param {string | null} input name of the changed input, null for timers",
|
|
345
|
+
" * @returns {boolean} true if a transition was taken",
|
|
346
|
+
" */",
|
|
347
|
+
`function process_${identifier(state.id)}(input) {`,
|
|
348
|
+
`${INDENT}// 1. transitions leaving the state`,
|
|
349
|
+
...outer.length ? outer : [`${INDENT}// none`],
|
|
350
|
+
`${INDENT}// 2. during action`,
|
|
351
|
+
state.during?.trim() ? `${INDENT}{
|
|
352
|
+
${indent(dedent(state.during), 2)}
|
|
353
|
+
${INDENT}}` : `${INDENT}// none`,
|
|
354
|
+
`${INDENT}// 3. inner transitions (to own sub states, the state stays active)`,
|
|
355
|
+
...inner.length ? inner : [`${INDENT}// none`],
|
|
356
|
+
`${INDENT}// 4. ${structure.isParallel(state.id) && children.length ? "all sub states" : "active sub state"}`,
|
|
357
|
+
...children.length ? processChildren(state.id, children) : [`${INDENT}// none`, `${INDENT}return false;`],
|
|
358
|
+
"}",
|
|
359
|
+
""
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
lines.push(
|
|
363
|
+
"// ---------- Helpers ----------",
|
|
364
|
+
"",
|
|
365
|
+
"/** Writes every output whose value was changed by an action */",
|
|
366
|
+
"function writeChangedOutputs() {",
|
|
367
|
+
...outputs.map(
|
|
368
|
+
(s) => `${INDENT}if (${s.name} !== written.${s.name}) {
|
|
369
|
+
${INDENT}${INDENT}written.${s.name} = ${s.name};
|
|
370
|
+
${INDENT}${INDENT}setState(${JSON.stringify(s.stateId)}, ${s.name});
|
|
371
|
+
${INDENT}}`
|
|
372
|
+
),
|
|
373
|
+
"}",
|
|
374
|
+
"",
|
|
375
|
+
"// Provided by the adapter:",
|
|
376
|
+
"// isActive(stateId) true if the state of the chart is active",
|
|
377
|
+
"// entryCount(stateId) how often the state was entered",
|
|
378
|
+
"// timeInState(stateId) milliseconds since the state was entered; when it reaches the delay of an",
|
|
379
|
+
"// after(n, unit) or at(n, unit) of the state, a timer calls wakeup(null)",
|
|
380
|
+
'// timerFired(id) true in the wakeup(null) of the timer of at(n, unit), every(n, unit) or at("sunset")',
|
|
381
|
+
'// of the transition; at("sunset", offset) and at("22:30") have a timer for every day',
|
|
382
|
+
"// inputCount(stateId, input)",
|
|
383
|
+
"// the wakeups by the input since the state was entered, for e.g. after(3, button)",
|
|
384
|
+
"// trueFor(id) milliseconds the condition of after(n, unit, condition) of the transition has been true,",
|
|
385
|
+
"// checked at the start and at the end of every wakeup; a timer calls wakeup(null) when",
|
|
386
|
+
"// it reaches the delay",
|
|
387
|
+
"// At the start of each wakeup, the adapter stores the values of the variables used in hasChanged(),",
|
|
388
|
+
"// hasChangedFrom() and hasChangedTo(), these compare them with the values of the previous wakeup.",
|
|
389
|
+
"//",
|
|
390
|
+
"// Helper functions for conditions, actions and function blocks:",
|
|
391
|
+
...Object.values(import_chart_helpers.HELPERS).map((helper) => `// ${helper.signature}
|
|
392
|
+
// ${helper.description}`),
|
|
393
|
+
"//",
|
|
394
|
+
"// The adapter stores the active states, the times they were entered and the locals in the state",
|
|
395
|
+
"// charts.<chart>.snapshot. After a restart of the adapter it continues with them, without executing the",
|
|
396
|
+
"// entry actions again, if the chart was not changed meanwhile. Then it wakes up once, like after a start.",
|
|
397
|
+
""
|
|
398
|
+
);
|
|
399
|
+
return lines.join("\n");
|
|
400
|
+
}
|
|
401
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
402
|
+
0 && (module.exports = {
|
|
403
|
+
generateChartCode
|
|
404
|
+
});
|
|
405
|
+
//# sourceMappingURL=chart-codegen.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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, 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
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var chart_helpers_exports = {};
|
|
20
|
+
__export(chart_helpers_exports, {
|
|
21
|
+
CHANGE_HELPERS: () => CHANGE_HELPERS,
|
|
22
|
+
HELPERS: () => HELPERS,
|
|
23
|
+
isTimeBetween: () => isTimeBetween,
|
|
24
|
+
parseTime: () => parseTime
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(chart_helpers_exports);
|
|
27
|
+
const HELPERS = {
|
|
28
|
+
log: {
|
|
29
|
+
signature: 'log(message, level = "info")',
|
|
30
|
+
description: 'Writes a message to the ioBroker log, level "debug", "info", "warn" or "error"'
|
|
31
|
+
},
|
|
32
|
+
setState: {
|
|
33
|
+
signature: "setState(id, value, ack = false)",
|
|
34
|
+
description: "Writes a value to any ioBroker state"
|
|
35
|
+
},
|
|
36
|
+
setStateDelayed: {
|
|
37
|
+
signature: "setStateDelayed(id, value, delayMs, ack = false)",
|
|
38
|
+
description: "Writes a value after a delay, cancelled when the chart stops"
|
|
39
|
+
},
|
|
40
|
+
sendTo: {
|
|
41
|
+
signature: "sendTo(instance, command, message)",
|
|
42
|
+
description: 'Sends a message to an adapter, e.g. sendTo("telegram.0", "send", { text: "Hello" })'
|
|
43
|
+
},
|
|
44
|
+
isTimeBetween: {
|
|
45
|
+
signature: 'isTimeBetween("22:00", "06:00")',
|
|
46
|
+
description: "true if the current time is in the range, also over midnight"
|
|
47
|
+
},
|
|
48
|
+
isDaytime: {
|
|
49
|
+
signature: "isDaytime()",
|
|
50
|
+
description: "true between sunrise and sunset, at the location of the ioBroker system settings"
|
|
51
|
+
},
|
|
52
|
+
astroTime: {
|
|
53
|
+
signature: 'astroTime("sunset", offsetMinutes = 0)',
|
|
54
|
+
description: "Time of an astro event today: sunrise, sunset, dawn, dusk, solarNoon, nauticalDawn, nauticalDusk, goldenHour, goldenHourEnd, night, nightEnd"
|
|
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
|
+
},
|
|
68
|
+
hasChanged: {
|
|
69
|
+
signature: "hasChanged(variable)",
|
|
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"
|
|
71
|
+
},
|
|
72
|
+
hasChangedFrom: {
|
|
73
|
+
signature: "hasChangedFrom(variable, value)",
|
|
74
|
+
description: "true if the variable has changed (see hasChanged) and its previous value was the given value"
|
|
75
|
+
},
|
|
76
|
+
hasChangedTo: {
|
|
77
|
+
signature: "hasChangedTo(variable, value)",
|
|
78
|
+
description: "true if the variable has changed (see hasChanged) to the given value, e.g. hasChangedTo(button, true)"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const CHANGE_HELPERS = /* @__PURE__ */ new Set(["hasChanged", "hasChangedFrom", "hasChangedTo"]);
|
|
82
|
+
function parseTime(time) {
|
|
83
|
+
const match = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/.exec(String(time).trim());
|
|
84
|
+
if (!match || Number(match[1]) > 23 || Number(match[2]) > 59 || Number(match[3] ?? 0) > 59) {
|
|
85
|
+
throw new Error(`Invalid time "${time}", expected e.g. "22:30"`);
|
|
86
|
+
}
|
|
87
|
+
return Number(match[1]) * 3600 + Number(match[2]) * 60 + Number(match[3] ?? 0);
|
|
88
|
+
}
|
|
89
|
+
function isTimeBetween(start, end, now = /* @__PURE__ */ new Date()) {
|
|
90
|
+
const from = parseTime(start);
|
|
91
|
+
const to = parseTime(end);
|
|
92
|
+
const current = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
|
|
93
|
+
return from <= to ? current >= from && current < to : current >= from || current < to;
|
|
94
|
+
}
|
|
95
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
96
|
+
0 && (module.exports = {
|
|
97
|
+
CHANGE_HELPERS,
|
|
98
|
+
HELPERS,
|
|
99
|
+
isTimeBetween,
|
|
100
|
+
parseTime
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=chart-helpers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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\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
|
+
"names": []
|
|
7
|
+
}
|