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.
Files changed (50) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +59 -438
  3. package/admin/build/tab.js +133 -130
  4. package/admin/statechart.png +0 -0
  5. package/admin/{style.css → tab.css} +0 -2
  6. package/admin/tab_m.html +1 -1
  7. package/build/lib/chart-analysis.js +367 -0
  8. package/build/lib/chart-analysis.js.map +7 -0
  9. package/build/lib/chart-codegen.js +405 -0
  10. package/build/lib/chart-codegen.js.map +7 -0
  11. package/build/lib/chart-helpers.js +102 -0
  12. package/build/lib/chart-helpers.js.map +7 -0
  13. package/build/lib/chart-model.js +477 -0
  14. package/build/lib/chart-model.js.map +7 -0
  15. package/build/lib/chart-runtime.js +1521 -0
  16. package/build/lib/chart-runtime.js.map +7 -0
  17. package/build/lib/chart-structure.js +172 -0
  18. package/build/lib/chart-structure.js.map +7 -0
  19. package/build/lib/chart-validation.js +372 -0
  20. package/build/lib/chart-validation.js.map +7 -0
  21. package/build/main.js +638 -0
  22. package/build/main.js.map +7 -0
  23. package/io-package.json +31 -34
  24. package/package.json +21 -17
  25. package/admin/i18n/de.json +0 -4
  26. package/admin/i18n/en.json +0 -4
  27. package/admin/i18n/es.json +0 -4
  28. package/admin/i18n/fr.json +0 -4
  29. package/admin/i18n/it.json +0 -4
  30. package/admin/i18n/nl.json +0 -4
  31. package/admin/i18n/pl.json +0 -4
  32. package/admin/i18n/pt.json +0 -4
  33. package/admin/i18n/ru.json +0 -4
  34. package/admin/i18n/uk.json +0 -4
  35. package/admin/i18n/zh-cn.json +0 -4
  36. package/admin/jsonConfig.json +0 -19
  37. package/admin/statechart.svg +0 -38
  38. package/lib/adapter-config.d.ts +0 -19
  39. package/lib/chart-codegen.js +0 -436
  40. package/lib/chart-codegen.test.js +0 -132
  41. package/lib/chart-helpers.js +0 -74
  42. package/lib/chart-helpers.test.js +0 -38
  43. package/lib/chart-model.js +0 -577
  44. package/lib/chart-model.test.js +0 -189
  45. package/lib/chart-runtime.js +0 -797
  46. package/lib/chart-runtime.test.js +0 -699
  47. package/lib/chart-structure.js +0 -106
  48. package/lib/chart-validation.js +0 -328
  49. package/lib/chart-validation.test.js +0 -149
  50. package/main.js +0 -279
@@ -0,0 +1,477 @@
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_model_exports = {};
20
+ __export(chart_model_exports, {
21
+ ASTRO_EVENTS: () => ASTRO_EVENTS,
22
+ CHART_MODEL_VERSION: () => CHART_MODEL_VERSION,
23
+ COLOR_PATTERN: () => COLOR_PATTERN,
24
+ EXPORT_FORMAT: () => EXPORT_FORMAT,
25
+ LabelSyntaxError: () => LabelSyntaxError,
26
+ MAX_SUPER_STEPS: () => MAX_SUPER_STEPS,
27
+ TEMPORAL_OPERATORS: () => TEMPORAL_OPERATORS,
28
+ TIME_OF_DAY: () => TIME_OF_DAY,
29
+ TIME_UNITS: () => TIME_UNITS,
30
+ createChart: () => createChart,
31
+ createExport: () => createExport,
32
+ formatMessage: () => formatMessage,
33
+ nameToId: () => nameToId,
34
+ parseExport: () => parseExport,
35
+ parseTransitionLabel: () => parseTransitionLabel,
36
+ parseTransitionLabelWithRanges: () => parseTransitionLabelWithRanges
37
+ });
38
+ module.exports = __toCommonJS(chart_model_exports);
39
+ const CHART_MODEL_VERSION = 1;
40
+ const MAX_SUPER_STEPS = 100;
41
+ const COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
42
+ const TEMPORAL_OPERATORS = ["after", "before", "at", "every"];
43
+ const TIME_UNITS = {
44
+ msec: 1,
45
+ sec: 1e3,
46
+ min: 6e4
47
+ };
48
+ function createChart(name) {
49
+ return {
50
+ version: CHART_MODEL_VERSION,
51
+ name,
52
+ enabled: false,
53
+ symbols: [],
54
+ states: [],
55
+ transitions: [],
56
+ functions: [],
57
+ notes: []
58
+ };
59
+ }
60
+ function nameToId(name) {
61
+ return name.trim().toLowerCase().replace(/ä/g, "ae").replace(/ö/g, "oe").replace(/ü/g, "ue").replace(/ß/g, "ss").replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "") || "chart";
62
+ }
63
+ function formatMessage(key, args) {
64
+ let i = 0;
65
+ return key.replace(/%s/g, () => args[i++] ?? "");
66
+ }
67
+ class LabelSyntaxError extends Error {
68
+ /**
69
+ * @param key Message with %s placeholders, used to translate the message
70
+ * @param args Values for the placeholders
71
+ * @param from Start of the problem in the label
72
+ * @param to End of the problem in the label
73
+ */
74
+ constructor(key, args, from, to) {
75
+ super(formatMessage(key, args));
76
+ this.key = key;
77
+ this.args = args;
78
+ this.from = from;
79
+ this.to = to;
80
+ }
81
+ }
82
+ function readEnclosed(text, start, open, close) {
83
+ let depth = 0;
84
+ for (let i = start; i < text.length; i++) {
85
+ if (text[i] === open) {
86
+ depth++;
87
+ } else if (text[i] === close) {
88
+ depth--;
89
+ if (depth === 0) {
90
+ const raw = text.substring(start + 1, i);
91
+ const content = raw.trim();
92
+ return { content, from: start + 1 + raw.indexOf(content), end: i + 1 };
93
+ }
94
+ }
95
+ }
96
+ throw new LabelSyntaxError('Missing "%s"', [close], start, text.length);
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
+ }
194
+ function parseTransitionLabelWithRanges(label) {
195
+ const result = {};
196
+ const ranges = {};
197
+ const text = label || "";
198
+ let pos = 0;
199
+ const skipSpace = () => {
200
+ while (pos < text.length && /\s/.test(text[pos])) {
201
+ pos++;
202
+ }
203
+ };
204
+ skipSpace();
205
+ const eventMatch = /[A-Za-z_$][\w$]*/y;
206
+ eventMatch.lastIndex = pos;
207
+ const event = eventMatch.exec(text);
208
+ if (event) {
209
+ const from = pos;
210
+ pos += event[0].length;
211
+ skipSpace();
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;
222
+ }
223
+ pos = end;
224
+ } else {
225
+ result.event = event[0];
226
+ ranges.event = { from, to: from + event[0].length };
227
+ }
228
+ }
229
+ skipSpace();
230
+ if (text[pos] === "[") {
231
+ const { content, from, end } = readEnclosed(text, pos, "[", "]");
232
+ result.condition = content;
233
+ ranges.condition = { from, to: from + content.length };
234
+ pos = end;
235
+ }
236
+ skipSpace();
237
+ if (text[pos] === "{") {
238
+ const { content, from, end } = readEnclosed(text, pos, "{", "}");
239
+ result.action = content;
240
+ ranges.action = { from, to: from + content.length };
241
+ pos = end;
242
+ }
243
+ skipSpace();
244
+ if (pos < text.length) {
245
+ throw new LabelSyntaxError(
246
+ 'Unexpected "%s", expected event[condition]{action}',
247
+ [text.substring(pos).trim()],
248
+ pos,
249
+ text.length
250
+ );
251
+ }
252
+ return { label: result, ranges };
253
+ }
254
+ function parseTransitionLabel(label) {
255
+ return parseTransitionLabelWithRanges(label).label;
256
+ }
257
+ const EXPORT_FORMAT = "iobroker.statechart";
258
+ const LEGACY_EXPORT_FORMATS = ["iobroker.state-machine"];
259
+ function createExport(charts) {
260
+ return { format: EXPORT_FORMAT, version: CHART_MODEL_VERSION, exported: (/* @__PURE__ */ new Date()).toISOString(), charts };
261
+ }
262
+ const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
263
+ const SCOPES = ["input", "output", "local"];
264
+ function isObject(value) {
265
+ return typeof value === "object" && value !== null && !Array.isArray(value);
266
+ }
267
+ function normalizeChart(data, where) {
268
+ const fail = (message) => {
269
+ throw new Error(`${where}: ${message}`);
270
+ };
271
+ if (!isObject(data)) {
272
+ fail("not an object");
273
+ }
274
+ if (typeof data.version === "number" && data.version > CHART_MODEL_VERSION) {
275
+ fail(`created with a newer version of the adapter (chart version ${data.version})`);
276
+ }
277
+ for (const list of ["states", "transitions", "symbols"]) {
278
+ if (!Array.isArray(data[list])) {
279
+ fail(`"${list}" is missing or no list`);
280
+ }
281
+ }
282
+ for (const list of ["functions", "notes"]) {
283
+ if (data[list] !== void 0 && !Array.isArray(data[list])) {
284
+ fail(`"${list}" is no list`);
285
+ }
286
+ }
287
+ const functions = data.functions || [];
288
+ const notes = data.notes || [];
289
+ const nodeIds = /* @__PURE__ */ new Set();
290
+ const checkId = (item, kind, index) => {
291
+ if (!isObject(item) || typeof item.id !== "string" || !item.id) {
292
+ fail(`${kind} ${index + 1} has no ID`);
293
+ }
294
+ if (nodeIds.has(item.id)) {
295
+ fail(`${kind} ${item.id}: the ID is used more than once`);
296
+ }
297
+ nodeIds.add(item.id);
298
+ return item.id;
299
+ };
300
+ const optionalString = (value, message) => {
301
+ if (value !== void 0 && value !== null && typeof value !== "string") {
302
+ fail(message);
303
+ }
304
+ };
305
+ data.states.forEach((state, i) => checkId(state, "state", i));
306
+ functions.forEach((fn, i) => checkId(fn, "function block", i));
307
+ notes.forEach((note, i) => checkId(note, "note", i));
308
+ const stateIds = new Set(data.states.map((s) => s.id));
309
+ optionalString(data.comment, '"comment" is no text');
310
+ const states = data.states.map((state) => {
311
+ const at = `state ${state.id}`;
312
+ if (state.parent && !stateIds.has(state.parent)) {
313
+ fail(`${at}: unknown parent state "${state.parent}"`);
314
+ }
315
+ for (const field of ["entry", "during", "exit", "initial", "comment"]) {
316
+ optionalString(state[field], `${at}: "${field}" is no text`);
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;
325
+ return {
326
+ ...rest,
327
+ // the defaults (exclusive, no history) are not stored, like in the editor
328
+ ...parallel === true ? { parallel } : {},
329
+ ...history === true ? { history } : {},
330
+ name: typeof state.name === "string" && state.name ? state.name : state.id,
331
+ parent: state.parent || null,
332
+ x: Number.isFinite(state.x) ? state.x : 0,
333
+ y: Number.isFinite(state.y) ? state.y : 0
334
+ };
335
+ });
336
+ const parentOf = new Map(states.map((s) => [s.id, s.parent]));
337
+ for (const state of states) {
338
+ let parent = state.parent;
339
+ for (let i = 0; parent; i++) {
340
+ if (parent === state.id || i > states.length) {
341
+ fail(`state ${state.id}: the parent states form a cycle`);
342
+ }
343
+ parent = parentOf.get(parent) ?? null;
344
+ }
345
+ }
346
+ const transitionIds = /* @__PURE__ */ new Set();
347
+ const transitions = data.transitions.map((transition, i) => {
348
+ if (!isObject(transition) || typeof transition.id !== "string" || !transition.id) {
349
+ fail(`transition ${i + 1} has no ID`);
350
+ }
351
+ const at = `transition ${transition.id}`;
352
+ if (transitionIds.has(transition.id)) {
353
+ fail(`${at}: the ID is used more than once`);
354
+ }
355
+ transitionIds.add(transition.id);
356
+ for (const end of ["source", "target"]) {
357
+ if (!stateIds.has(transition[end])) {
358
+ fail(`${at}: unknown ${end} state "${transition[end]}"`);
359
+ }
360
+ }
361
+ optionalString(transition.label, `${at}: "label" is no text`);
362
+ optionalString(transition.comment, `${at}: "comment" is no text`);
363
+ if (transition.priority !== void 0 && !Number.isFinite(transition.priority)) {
364
+ fail(`${at}: "priority" is no number`);
365
+ }
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 } } : {} };
369
+ });
370
+ const symbolNames = /* @__PURE__ */ new Set();
371
+ const symbols = data.symbols.map((symbol, i) => {
372
+ if (!isObject(symbol) || typeof symbol.name !== "string" || !IDENTIFIER.test(symbol.name)) {
373
+ fail(`variable ${i + 1}: invalid name`);
374
+ }
375
+ if (symbolNames.has(symbol.name)) {
376
+ fail(`variable ${symbol.name}: the name is used more than once`);
377
+ }
378
+ symbolNames.add(symbol.name);
379
+ if (!SCOPES.includes(symbol.scope)) {
380
+ fail(`variable ${symbol.name}: invalid kind "${symbol.scope}"`);
381
+ }
382
+ optionalString(symbol.stateId, `variable ${symbol.name}: "stateId" is no text`);
383
+ if (symbol.trigger !== void 0 && !["update", "change"].includes(symbol.trigger)) {
384
+ fail(`variable ${symbol.name}: invalid trigger "${symbol.trigger}"`);
385
+ }
386
+ if (symbol.ack !== void 0 && !["any", "ack", "command"].includes(symbol.ack)) {
387
+ fail(`variable ${symbol.name}: invalid ack filter "${symbol.ack}"`);
388
+ }
389
+ if (symbol.debounceMs !== void 0 && !(Number.isFinite(symbol.debounceMs) && symbol.debounceMs >= 0)) {
390
+ fail(`variable ${symbol.name}: "debounceMs" is no number of 0 or more`);
391
+ }
392
+ return { ...symbol };
393
+ });
394
+ const normalizedFunctions = functions.map((fn) => {
395
+ if (typeof fn.code !== "string") {
396
+ fail(`function block ${fn.id}: "code" is no text`);
397
+ }
398
+ optionalString(fn.comment, `function block ${fn.id}: "comment" is no text`);
399
+ return { ...fn, x: Number.isFinite(fn.x) ? fn.x : 0, y: Number.isFinite(fn.y) ? fn.y : 0 };
400
+ });
401
+ const normalizedNotes = notes.map((note) => {
402
+ optionalString(note.text, `note ${note.id}: "text" is no text`);
403
+ if (note.parent && !stateIds.has(note.parent)) {
404
+ fail(`note ${note.id}: unknown parent state "${note.parent}"`);
405
+ }
406
+ return {
407
+ ...note,
408
+ text: note.text || "",
409
+ parent: note.parent || null,
410
+ x: Number.isFinite(note.x) ? note.x : 0,
411
+ y: Number.isFinite(note.y) ? note.y : 0
412
+ };
413
+ });
414
+ const chart = {
415
+ ...data,
416
+ version: CHART_MODEL_VERSION,
417
+ name: typeof data.name === "string" && data.name.trim() ? data.name.trim() : where,
418
+ initial: typeof data.initial === "string" && stateIds.has(data.initial) ? data.initial : void 0,
419
+ enabled: data.enabled !== false,
420
+ symbols,
421
+ states,
422
+ transitions,
423
+ functions: normalizedFunctions,
424
+ notes: normalizedNotes
425
+ };
426
+ if (chart.superStep !== true) {
427
+ delete chart.superStep;
428
+ }
429
+ if (chart.parallel !== true) {
430
+ delete chart.parallel;
431
+ }
432
+ if (chart.orthogonalTransitions !== true) {
433
+ delete chart.orthogonalTransitions;
434
+ }
435
+ return chart;
436
+ }
437
+ function parseExport(text) {
438
+ let data;
439
+ try {
440
+ data = JSON.parse(text);
441
+ } catch (err) {
442
+ throw new Error(`No valid JSON: ${err.message}`);
443
+ }
444
+ if (isObject(data) && (data.format === EXPORT_FORMAT || LEGACY_EXPORT_FORMATS.includes(data.format))) {
445
+ if (typeof data.version === "number" && data.version > CHART_MODEL_VERSION) {
446
+ throw new Error(`The file was created with a newer version of the adapter (version ${data.version})`);
447
+ }
448
+ if (!Array.isArray(data.charts) || !data.charts.length) {
449
+ throw new Error("The file contains no charts");
450
+ }
451
+ return data.charts.map((chart, i) => normalizeChart(chart, `Chart ${i + 1}`));
452
+ }
453
+ if (isObject(data) && Array.isArray(data.states)) {
454
+ return [normalizeChart(data, "Chart")];
455
+ }
456
+ throw new Error("The file contains no charts of the statechart adapter");
457
+ }
458
+ // Annotate the CommonJS export names for ESM import in node:
459
+ 0 && (module.exports = {
460
+ ASTRO_EVENTS,
461
+ CHART_MODEL_VERSION,
462
+ COLOR_PATTERN,
463
+ EXPORT_FORMAT,
464
+ LabelSyntaxError,
465
+ MAX_SUPER_STEPS,
466
+ TEMPORAL_OPERATORS,
467
+ TIME_OF_DAY,
468
+ TIME_UNITS,
469
+ createChart,
470
+ createExport,
471
+ formatMessage,
472
+ nameToId,
473
+ parseExport,
474
+ parseTransitionLabel,
475
+ parseTransitionLabelWithRanges
476
+ });
477
+ //# sourceMappingURL=chart-model.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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\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
+ "names": []
7
+ }