node-red-contrib-my-tools 1.0.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/README.txt +69 -0
- package/node-red-contrib-mysql-extended-test/mysql-extended.html +443 -0
- package/node-red-contrib-mysql-extended-test/mysql-extended.js +355 -0
- package/node-red-contrib-rfid-helper/rfid-lazy.html +153 -0
- package/node-red-contrib-rfid-helper/rfid-lazy.js +361 -0
- package/node-red-contrib-s7-plus/LICENSE +235 -0
- package/node-red-contrib-s7-plus/README.md +141 -0
- package/node-red-contrib-s7-plus/examples/read-multiple-values-flow.json +346 -0
- package/node-red-contrib-s7-plus/examples/read-write-test-flow.json +172 -0
- package/node-red-contrib-s7-plus/examples/write-single-values-flow.json +5583 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/README.md +72 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/areas.js +36 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/datatypes.js +91 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/flat-browser.js +433 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/index.js +22 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/lazy.js +397 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/node-id.js +22 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/resolve-symbolic.js +181 -0
- package/node-red-contrib-s7-plus/lib/s7plus/browse/vte-helpers.js +49 -0
- package/node-red-contrib-s7-plus/lib/s7plus/buffer-stream.js +96 -0
- package/node-red-contrib-s7-plus/lib/s7plus/client.js +1238 -0
- package/node-red-contrib-s7-plus/lib/s7plus/constants.js +155 -0
- package/node-red-contrib-s7-plus/lib/s7plus/crc/index.js +3 -0
- package/node-red-contrib-s7-plus/lib/s7plus/crc/s7-crc32.js +70 -0
- package/node-red-contrib-s7-plus/lib/s7plus/crc/symbol-crc.js +271 -0
- package/node-red-contrib-s7-plus/lib/s7plus/debug.js +88 -0
- package/node-red-contrib-s7-plus/lib/s7plus/explore-result.js +41 -0
- package/node-red-contrib-s7-plus/lib/s7plus/item-address.js +55 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pdu-explore.js +77 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pdu-messages.js +359 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pobject.js +197 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pvalue-codec.js +435 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pvalue.js +653 -0
- package/node-red-contrib-s7-plus/lib/s7plus/pvar-lists.js +336 -0
- package/node-red-contrib-s7-plus/lib/s7plus/read-result.js +91 -0
- package/node-red-contrib-s7-plus/lib/s7plus/s7p.js +266 -0
- package/node-red-contrib-s7-plus/lib/s7plus/tag-routing.js +30 -0
- package/node-red-contrib-s7-plus/lib/s7plus/transport/cotp-stream.js +335 -0
- package/node-red-contrib-s7-plus/lib/s7plus/transport/s7-transport.js +335 -0
- package/node-red-contrib-s7-plus/nodes/icons/s7complus.png +0 -0
- package/node-red-contrib-s7-plus/nodes/icons/s7complus.svg +17 -0
- package/node-red-contrib-s7-plus/nodes/s7complus-endpoint.js +825 -0
- package/node-red-contrib-s7-plus/nodes/s7complus-explore.js +91 -0
- package/node-red-contrib-s7-plus/nodes/s7complus-in.js +255 -0
- package/node-red-contrib-s7-plus/nodes/s7complus-out.js +182 -0
- package/node-red-contrib-s7-plus/nodes/s7complus.html +1541 -0
- package/node-red-contrib-s7-plus/nodes/s7complus.js +10 -0
- package/node-red-contrib-s7-plus/package.json +50 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_Arrays.db +17 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_Binary.db +16 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_BitStrings.db +36 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_CharacterStrings.db +42 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_DateAndTime.db +70 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_FloatingPoint.db +42 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_Integers.db +72 -0
- package/node-red-contrib-s7-plus/plc/s7-1500/DB_Timers.db +40 -0
- package/node-red-contrib-s7-plus/scripts/example-flow-shared.js +39 -0
- package/node-red-contrib-s7-plus/scripts/generate-read-multiple-flow.js +331 -0
- package/node-red-contrib-s7-plus/scripts/generate-rw-test-flow.js +690 -0
- package/node-red-contrib-s7-plus/scripts/generate-write-flow.js +476 -0
- package/node-red-contrib-s7-plus/scripts/layout-write-flow.js +156 -0
- package/node-red-contrib-s7-plus/scripts/run-tests.js +16 -0
- package/node-red-flowgobal-change/variable-change.html +425 -0
- package/node-red-flowgobal-change/variable-change.js +92 -0
- package/node-red-ui_media_viewer/ui_media_viewer.html +87 -0
- package/node-red-ui_media_viewer/ui_media_viewer.js +136 -0
- package/package.json +12 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Generates examples/read-multiple-values-flow.json: an example that shows how
|
|
5
|
+
// to read MANY symbols at once with a single s7-plus read node (one request to
|
|
6
|
+
// the PLC), in two ways:
|
|
7
|
+
//
|
|
8
|
+
// 1. Static config read - the read node lists multiple symbols (one
|
|
9
|
+
// representative constant per scalar datatype from plc/s7-1500 plus a few
|
|
10
|
+
// sample symbols). One inject triggers a single read of all of them.
|
|
11
|
+
// 2. Dynamic msg.symbols - a function node builds msg.symbols (a string[])
|
|
12
|
+
// at runtime and feeds an unconfigured read node, reading a few selected
|
|
13
|
+
// real symbols from the sample DBs.
|
|
14
|
+
//
|
|
15
|
+
// Regenerate with: node scripts/generate-read-multiple-flow.js
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { EP, DEFAULT_OUTPUT_FORMAT, endpointNode, globalConfigNode } = require('./example-flow-shared');
|
|
21
|
+
|
|
22
|
+
const TAB = 'read_multi_tab';
|
|
23
|
+
|
|
24
|
+
// Maps PLC datatype keywords (as written in the .db source) to the node datatype.
|
|
25
|
+
const PLC_TO_DT = {
|
|
26
|
+
Bool: 'Bool',
|
|
27
|
+
Byte: 'Byte', Word: 'Word', DWord: 'DWord', LWord: 'LWord',
|
|
28
|
+
Char: 'Char', String: 'String', WChar: 'WChar', WString: 'WString',
|
|
29
|
+
SInt: 'SInt', Int: 'Int', DInt: 'DInt',
|
|
30
|
+
USInt: 'USInt', UInt: 'UInt', UDInt: 'UDInt', LInt: 'LInt', ULInt: 'ULInt',
|
|
31
|
+
Real: 'Real', LReal: 'LReal',
|
|
32
|
+
Date: 'Date', Time_Of_Day: 'TimeOfDay', Date_And_Time: 'DateAndTime',
|
|
33
|
+
LTime_Of_Day: 'LTod', LDT: 'Ldt', DTL: 'Dtl',
|
|
34
|
+
Time: 'Time', S5Time: 'S5Time', LTime: 'LTime'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Scalar datatype sections, mirroring scripts/generate-write-flow.js. For the
|
|
38
|
+
// "read all" block we pick ONE representative read symbol per datatype: the
|
|
39
|
+
// first non-write constant of that datatype defined in the matching DB.
|
|
40
|
+
const SECTIONS = [
|
|
41
|
+
{ db: 'DB_Binary', datatypes: ['Bool'] },
|
|
42
|
+
{ db: 'DB_BitStrings', datatypes: ['Byte', 'Word', 'DWord', 'LWord'] },
|
|
43
|
+
{ db: 'DB_CharacterStrings', datatypes: ['Char', 'String', 'WChar', 'WString'] },
|
|
44
|
+
{
|
|
45
|
+
db: 'DB_Integers',
|
|
46
|
+
datatypes: ['SInt', 'Int', 'DInt', 'USInt', 'UInt', 'UDInt', 'LInt', 'ULInt']
|
|
47
|
+
},
|
|
48
|
+
{ db: 'DB_FloatingPoint', datatypes: ['Real', 'LReal'] },
|
|
49
|
+
{
|
|
50
|
+
db: 'DB_DateAndTime',
|
|
51
|
+
datatypes: ['Date', 'TimeOfDay', 'DateAndTime', 'LTod', 'Ldt', 'Dtl']
|
|
52
|
+
},
|
|
53
|
+
{ db: 'DB_Timers', datatypes: ['Time', 'S5Time', 'LTime'] }
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
// A few selected, real symbols from the sample DBs (plc/s7-1500). These are
|
|
57
|
+
// constants, but they are real readable variables, so the dynamic msg.symbols
|
|
58
|
+
// read returns actual values. Existence is validated below against the .db
|
|
59
|
+
// sources so the example never references a non-existent symbol.
|
|
60
|
+
const LIVE_SIGNALS = [
|
|
61
|
+
{ db: 'DB_FloatingPoint', name: 'Real_987d125', datatype: 'Real' },
|
|
62
|
+
{ db: 'DB_FloatingPoint', name: 'LReal_987d125', datatype: 'LReal' },
|
|
63
|
+
{ db: 'DB_Integers', name: 'Int_12345', datatype: 'Int' }
|
|
64
|
+
].map((s) => ({ symbol: `${s.db}.${s.name}`, datatype: s.datatype, db: s.db, name: s.name }));
|
|
65
|
+
|
|
66
|
+
// Reads a .db source and returns its non-write variables as { name, dt } in
|
|
67
|
+
// source order (the *_write test tags are skipped).
|
|
68
|
+
function parseVariables(db) {
|
|
69
|
+
const file = path.join(__dirname, '..', 'plc', 's7-1500', `${db}.db`);
|
|
70
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
71
|
+
|
|
72
|
+
const varStart = text.search(/\n\s*VAR\b/);
|
|
73
|
+
const varEnd = text.indexOf('END_VAR');
|
|
74
|
+
if (varStart === -1 || varEnd === -1) {
|
|
75
|
+
throw new Error(`Cannot locate VAR block in ${db}.db`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const out = [];
|
|
79
|
+
for (const line of text.slice(varStart, varEnd).split(/\r?\n/)) {
|
|
80
|
+
const m = line.match(/^\s*([A-Za-z_]\w*)\s*(?:\{[^}]*\})?\s*:\s*([A-Za-z_]\w*)/);
|
|
81
|
+
if (!m) continue;
|
|
82
|
+
const name = m[1];
|
|
83
|
+
const plcType = m[2];
|
|
84
|
+
if (name === 'VAR' || /_write$/i.test(name)) continue;
|
|
85
|
+
const dt = PLC_TO_DT[plcType];
|
|
86
|
+
if (!dt) continue;
|
|
87
|
+
out.push({ name, dt });
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Picks the first variable matching each requested datatype, in the order the
|
|
93
|
+
// datatypes are listed for the section.
|
|
94
|
+
function representativeSymbols(section) {
|
|
95
|
+
const variables = parseVariables(section.db);
|
|
96
|
+
return section.datatypes.map((dt) => {
|
|
97
|
+
const hit = variables.find((v) => v.dt === dt);
|
|
98
|
+
if (!hit) throw new Error(`No read symbol for ${section.db} datatype ${dt}`);
|
|
99
|
+
const symbol = `${section.db}.${hit.name}`;
|
|
100
|
+
return { name: symbol, address: symbol, datatype: dt };
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Fail loudly if a selected sample symbol does not exist in its .db source.
|
|
105
|
+
for (const sig of LIVE_SIGNALS) {
|
|
106
|
+
const exists = parseVariables(sig.db).some((v) => v.name === sig.name);
|
|
107
|
+
if (!exists) {
|
|
108
|
+
throw new Error(`Selected symbol ${sig.symbol} does not exist in ${sig.db}.db`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Build the full multi-symbol list for the "read all" node: every
|
|
113
|
+
// representative scalar plus the selected sample signals.
|
|
114
|
+
const ALL_SYMBOLS = [];
|
|
115
|
+
for (const signal of LIVE_SIGNALS) {
|
|
116
|
+
ALL_SYMBOLS.push({ name: signal.symbol, address: signal.symbol, datatype: signal.datatype });
|
|
117
|
+
}
|
|
118
|
+
for (const section of SECTIONS) {
|
|
119
|
+
for (const s of representativeSymbols(section)) ALL_SYMBOLS.push(s);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Dynamic msg.symbols function-node body. Same symbol list as the static
|
|
124
|
+
// "read all symbols" node (ALL_SYMBOLS). msg.symbols must be a string[].
|
|
125
|
+
// (Uses only string concatenation, never template literals.)
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
const BUILD_SYMBOLS_FUNC =
|
|
129
|
+
'msg.symbols = ' + JSON.stringify(
|
|
130
|
+
ALL_SYMBOLS.map((s) => s.name),
|
|
131
|
+
null,
|
|
132
|
+
4
|
|
133
|
+
) + ';\n' +
|
|
134
|
+
'msg.payload = \'\';\n' +
|
|
135
|
+
'return msg;\n';
|
|
136
|
+
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Assemble the flow nodes.
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
const HDR_ID = 'rm_hdr';
|
|
142
|
+
const ALL_INJECT_ID = 'rm_inject_all';
|
|
143
|
+
const ALL_READ_ID = 'rm_read_all';
|
|
144
|
+
const ALL_DEBUG_ID = 'rm_debug_all';
|
|
145
|
+
const ALL_COMMENT_ID = 'rm_comment_all';
|
|
146
|
+
const LIVE_COMMENT_ID = 'rm_comment_live';
|
|
147
|
+
const LIVE_INJECT_ID = 'rm_inject_live';
|
|
148
|
+
const LIVE_FN_ID = 'rm_fn_live';
|
|
149
|
+
const LIVE_READ_ID = 'rm_read_live';
|
|
150
|
+
const LIVE_DEBUG_ID = 'rm_debug_live';
|
|
151
|
+
|
|
152
|
+
const nodes = [];
|
|
153
|
+
|
|
154
|
+
nodes.push({
|
|
155
|
+
id: TAB,
|
|
156
|
+
type: 'tab',
|
|
157
|
+
label: 'Read Multiple Values',
|
|
158
|
+
disabled: false,
|
|
159
|
+
info: 'Reads many symbols at once with a single s7-plus read node.\n'
|
|
160
|
+
+ '\n'
|
|
161
|
+
+ '1) "Read all values" triggers one read of one representative constant '
|
|
162
|
+
+ 'per scalar datatype in plc/s7-1500 plus a few selected sample '
|
|
163
|
+
+ 'symbols. The read node lists all symbols in its config, so a single '
|
|
164
|
+
+ 'request returns the whole payload object (keyed by symbol).\n'
|
|
165
|
+
+ '\n'
|
|
166
|
+
+ '2) "Read selected symbols" shows the dynamic variant: a function node '
|
|
167
|
+
+ 'sets msg.symbols (a string[] with the same symbols as block 1) at '
|
|
168
|
+
+ 'runtime and feeds an unconfigured read node.\n'
|
|
169
|
+
+ '\n'
|
|
170
|
+
+ 'Regenerate with: node scripts/generate-read-multiple-flow.js'
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
nodes.push({
|
|
174
|
+
id: HDR_ID,
|
|
175
|
+
type: 'comment',
|
|
176
|
+
z: TAB,
|
|
177
|
+
name: 'Read multiple values — one s7-plus read node, many symbols, one request',
|
|
178
|
+
info: '',
|
|
179
|
+
x: 360,
|
|
180
|
+
y: 40,
|
|
181
|
+
wires: []
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// --- Block 1: static multi-symbol read -------------------------------------
|
|
185
|
+
|
|
186
|
+
nodes.push({
|
|
187
|
+
id: ALL_COMMENT_ID,
|
|
188
|
+
type: 'comment',
|
|
189
|
+
z: TAB,
|
|
190
|
+
name: '1) Static config: all symbols listed in the read node',
|
|
191
|
+
info: '',
|
|
192
|
+
x: 250,
|
|
193
|
+
y: 100,
|
|
194
|
+
wires: []
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
nodes.push({
|
|
198
|
+
id: ALL_INJECT_ID,
|
|
199
|
+
type: 'inject',
|
|
200
|
+
z: TAB,
|
|
201
|
+
name: 'Read all values',
|
|
202
|
+
props: [{ p: 'payload' }],
|
|
203
|
+
repeat: '',
|
|
204
|
+
crontab: '',
|
|
205
|
+
once: false,
|
|
206
|
+
onceDelay: 0.1,
|
|
207
|
+
topic: '',
|
|
208
|
+
payload: '',
|
|
209
|
+
payloadType: 'date',
|
|
210
|
+
x: 150,
|
|
211
|
+
y: 160,
|
|
212
|
+
wires: [[ALL_READ_ID]]
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
nodes.push({
|
|
216
|
+
id: ALL_READ_ID,
|
|
217
|
+
type: 's7-plus read',
|
|
218
|
+
z: TAB,
|
|
219
|
+
name: 'read all symbols',
|
|
220
|
+
endpoint: EP,
|
|
221
|
+
symbols: ALL_SYMBOLS,
|
|
222
|
+
outputFormat: DEFAULT_OUTPUT_FORMAT,
|
|
223
|
+
x: 410,
|
|
224
|
+
y: 160,
|
|
225
|
+
wires: [[ALL_DEBUG_ID]]
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
nodes.push({
|
|
229
|
+
id: ALL_DEBUG_ID,
|
|
230
|
+
type: 'debug',
|
|
231
|
+
z: TAB,
|
|
232
|
+
name: 'All values',
|
|
233
|
+
active: true,
|
|
234
|
+
tosidebar: true,
|
|
235
|
+
console: false,
|
|
236
|
+
tostatus: false,
|
|
237
|
+
complete: 'payload',
|
|
238
|
+
targetType: 'msg',
|
|
239
|
+
statusVal: '',
|
|
240
|
+
statusType: 'auto',
|
|
241
|
+
x: 660,
|
|
242
|
+
y: 160,
|
|
243
|
+
wires: []
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// --- Block 2: dynamic msg.symbols read -------------------------------------
|
|
247
|
+
|
|
248
|
+
nodes.push({
|
|
249
|
+
id: LIVE_COMMENT_ID,
|
|
250
|
+
type: 'comment',
|
|
251
|
+
z: TAB,
|
|
252
|
+
name: '2) Dynamic: msg.symbols set at runtime (same list as read all symbols)',
|
|
253
|
+
info: '',
|
|
254
|
+
x: 280,
|
|
255
|
+
y: 260,
|
|
256
|
+
wires: []
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
nodes.push({
|
|
260
|
+
id: LIVE_INJECT_ID,
|
|
261
|
+
type: 'inject',
|
|
262
|
+
z: TAB,
|
|
263
|
+
name: 'Read selected symbols',
|
|
264
|
+
props: [{ p: 'payload' }],
|
|
265
|
+
repeat: '',
|
|
266
|
+
crontab: '',
|
|
267
|
+
once: false,
|
|
268
|
+
onceDelay: 0.1,
|
|
269
|
+
topic: '',
|
|
270
|
+
payload: '',
|
|
271
|
+
payloadType: 'date',
|
|
272
|
+
x: 150,
|
|
273
|
+
y: 320,
|
|
274
|
+
wires: [[LIVE_FN_ID]]
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
nodes.push({
|
|
278
|
+
id: LIVE_FN_ID,
|
|
279
|
+
type: 'function',
|
|
280
|
+
z: TAB,
|
|
281
|
+
name: 'Build msg.symbols',
|
|
282
|
+
func: BUILD_SYMBOLS_FUNC,
|
|
283
|
+
outputs: 1,
|
|
284
|
+
timeout: 0,
|
|
285
|
+
noerr: 0,
|
|
286
|
+
initialize: '',
|
|
287
|
+
finalize: '',
|
|
288
|
+
libs: [],
|
|
289
|
+
x: 360,
|
|
290
|
+
y: 320,
|
|
291
|
+
wires: [[LIVE_READ_ID]]
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
nodes.push({
|
|
295
|
+
id: LIVE_READ_ID,
|
|
296
|
+
type: 's7-plus read',
|
|
297
|
+
z: TAB,
|
|
298
|
+
name: 'read (msg.symbols)',
|
|
299
|
+
endpoint: EP,
|
|
300
|
+
symbols: [],
|
|
301
|
+
outputFormat: DEFAULT_OUTPUT_FORMAT,
|
|
302
|
+
x: 600,
|
|
303
|
+
y: 320,
|
|
304
|
+
wires: [[LIVE_DEBUG_ID]]
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
nodes.push({
|
|
308
|
+
id: LIVE_DEBUG_ID,
|
|
309
|
+
type: 'debug',
|
|
310
|
+
z: TAB,
|
|
311
|
+
name: 'Selected symbols',
|
|
312
|
+
active: true,
|
|
313
|
+
tosidebar: true,
|
|
314
|
+
console: false,
|
|
315
|
+
tostatus: false,
|
|
316
|
+
complete: 'payload',
|
|
317
|
+
targetType: 'msg',
|
|
318
|
+
statusVal: '',
|
|
319
|
+
statusType: 'auto',
|
|
320
|
+
x: 840,
|
|
321
|
+
y: 320,
|
|
322
|
+
wires: []
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
nodes.push(endpointNode());
|
|
326
|
+
nodes.push(globalConfigNode('0.0.1'));
|
|
327
|
+
|
|
328
|
+
const out = path.join(__dirname, '..', 'examples', 'read-multiple-values-flow.json');
|
|
329
|
+
fs.writeFileSync(out, JSON.stringify(nodes, null, 4) + '\n');
|
|
330
|
+
|
|
331
|
+
console.log(`Wrote ${nodes.length} nodes (${ALL_SYMBOLS.length} symbols in the static read) to ${out}`);
|