node-red-contrib-config-files 0.2.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/CHANGELOG.md +5 -0
- package/HELP.md +7 -0
- package/README.md +6 -2
- package/package.json +1 -1
- package/subflow.json +90 -42
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-01-31
|
|
4
|
+
### Changed
|
|
5
|
+
- New configuration property `concatArrays`: true -> array elements of corresponding arrays are concatenated, otherwise merged, default: `true`. Input message `msg.concatArrays` overwrites the node property.
|
|
6
|
+
- Properties: The allowed data types for the input fields are now more restricted.
|
|
7
|
+
|
|
3
8
|
## [0.2.1] - 2026-01-31
|
|
4
9
|
### Changed
|
|
5
10
|
- If directory `configDir` doesn't exist or is not accessible: Instead of throwing a node error, a node warning is created. This warning may appear in the “Debug Messages” sidebar.
|
package/HELP.md
CHANGED
|
@@ -8,6 +8,7 @@ input message.
|
|
|
8
8
|
|
|
9
9
|
: configDir (string) : Directory with config files. Absolute or relative path, default: `/config`. Input message `msg.configDir` overwrites the node property.
|
|
10
10
|
: configFileExt (string) : Filename extension for config files, default: `.json`. Input message `msg.configFileExt` overwrites the node property.
|
|
11
|
+
: concatArrays (boolean) : true -> array elements of corresponding arrays are concatenated, otherwise merged, default: `true`. Input message `msg.concatArrays` overwrites the node property.
|
|
11
12
|
|
|
12
13
|
### Outputs
|
|
13
14
|
|
|
@@ -25,6 +26,12 @@ The files are sorted by their file names and merged in this order.
|
|
|
25
26
|
The content of the `defaultConfig` property and the configuration files
|
|
26
27
|
must by valid JSON.
|
|
27
28
|
|
|
29
|
+
The property `concatArrays` defines how to merge corresponding arrays defined in more
|
|
30
|
+
than one config file and/or `defaultConfig`:
|
|
31
|
+
- `true` Concatenate the array elements of corresponding arrays.
|
|
32
|
+
- `false` Array elements in corresponding arrays with the same index overwrite each
|
|
33
|
+
other, with the overwrite order depending on the order of the sorted files (see above).
|
|
34
|
+
|
|
28
35
|
### References
|
|
29
36
|
|
|
30
37
|
- [GitHub](https://github.com/schaeren/node-red-contrib-config-files) - source code
|
package/README.md
CHANGED
|
@@ -14,8 +14,12 @@ The node status displays one of the following two messages:
|
|
|
14
14
|
- Found {count} config files in '{configDir}' with extension '{configFileExt}'
|
|
15
15
|
- No config files found in '{configDir}' with extension '{configFileExt}' -> using default config
|
|
16
16
|
|
|
17
|
-
If directory `configDir` doesn't exist or is not accessible or if no file was found with `configFileExt`,
|
|
18
|
-
|
|
17
|
+
If directory `configDir` doesn't exist or is not accessible or if no file was found with `configFileExt`, node warnings
|
|
18
|
+
are created. These warnings may appear in the “Debug Messages” sidebar.
|
|
19
|
+
|
|
20
|
+
Special care is required when using config files containing arrays with objects: The `concatArray` property can be used
|
|
21
|
+
to define whether the array elements should be concatenated or merged. In the latter case, array elements with the same
|
|
22
|
+
array index are merged, i.e., element properties with identical names overwrite each other.
|
|
19
23
|
|
|
20
24
|
## Internals
|
|
21
25
|
- This custom node was created from a subflow.
|
package/package.json
CHANGED
package/subflow.json
CHANGED
|
@@ -21,37 +21,79 @@
|
|
|
21
21
|
"y": 400,
|
|
22
22
|
"wires": [
|
|
23
23
|
{
|
|
24
|
-
"id": "
|
|
24
|
+
"id": "efa7ea24e8224b84",
|
|
25
25
|
"port": 0
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"id": "
|
|
28
|
+
"id": "86c429715975c781",
|
|
29
29
|
"port": 0
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
|
-
}
|
|
32
|
+
}
|
|
33
|
+
],
|
|
33
34
|
"env": [
|
|
34
35
|
{
|
|
35
36
|
"name": "configDir",
|
|
36
37
|
"type": "str",
|
|
37
|
-
"value": "/config"
|
|
38
|
+
"value": "/config",
|
|
39
|
+
"ui": {
|
|
40
|
+
"type": "input",
|
|
41
|
+
"opts": {
|
|
42
|
+
"types": [
|
|
43
|
+
"str",
|
|
44
|
+
"env"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
38
48
|
},
|
|
39
49
|
{
|
|
40
50
|
"name": "configFileExt",
|
|
41
51
|
"type": "str",
|
|
42
|
-
"value": ".json"
|
|
52
|
+
"value": ".json",
|
|
53
|
+
"ui": {
|
|
54
|
+
"type": "input",
|
|
55
|
+
"opts": {
|
|
56
|
+
"types": [
|
|
57
|
+
"str",
|
|
58
|
+
"env"
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "concatArrays",
|
|
65
|
+
"type": "bool",
|
|
66
|
+
"value": "true",
|
|
67
|
+
"ui": {
|
|
68
|
+
"type": "input",
|
|
69
|
+
"opts": {
|
|
70
|
+
"types": [
|
|
71
|
+
"bool",
|
|
72
|
+
"env"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
43
76
|
},
|
|
44
77
|
{
|
|
45
78
|
"name": "defaultConfig",
|
|
46
79
|
"type": "json",
|
|
47
|
-
"value": "{}"
|
|
80
|
+
"value": "{}",
|
|
81
|
+
"ui": {
|
|
82
|
+
"type": "input",
|
|
83
|
+
"opts": {
|
|
84
|
+
"types": [
|
|
85
|
+
"json",
|
|
86
|
+
"env"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
48
90
|
}
|
|
49
91
|
],
|
|
50
92
|
"meta": {
|
|
51
93
|
"module": "node-red-contrib-config-files",
|
|
52
94
|
"type": "config-files",
|
|
53
95
|
"desc": "Read and merge configuration files (JSON).",
|
|
54
|
-
"version": "0.
|
|
96
|
+
"version": "0.3.0",
|
|
55
97
|
"author": "Peter Schären <peter.schaeren@gmail.com>",
|
|
56
98
|
"keywords": "node-red,config-files,config,json",
|
|
57
99
|
"license": "MIT"
|
|
@@ -105,8 +147,7 @@
|
|
|
105
147
|
"y": 240,
|
|
106
148
|
"wires": [
|
|
107
149
|
[
|
|
108
|
-
"7f1816d008fa2b70"
|
|
109
|
-
"b46481b92cb28e07"
|
|
150
|
+
"7f1816d008fa2b70"
|
|
110
151
|
]
|
|
111
152
|
]
|
|
112
153
|
},
|
|
@@ -122,7 +163,6 @@
|
|
|
122
163
|
"y": 320,
|
|
123
164
|
"wires": [
|
|
124
165
|
[
|
|
125
|
-
"86c429715975c781",
|
|
126
166
|
"8639805af947d0c3"
|
|
127
167
|
]
|
|
128
168
|
]
|
|
@@ -153,7 +193,7 @@
|
|
|
153
193
|
"type": "function",
|
|
154
194
|
"z": "ec796389903c1d0f",
|
|
155
195
|
"name": "get config dir and filename extension",
|
|
156
|
-
"func": "const configDir = msg.configDir ?? null;\nif (typeof configDir === 'string' && configDir.trim().length > 0) {\n msg.configDir = configDir;\n}\nelse {\n msg.configDir = env.get('configDir');\n}\n\nconst configFileExt = msg.configFileExt ?? null;\nif (typeof configFileExt === 'string' && configFileExt.trim().length > 0) {\n msg.configFileExt = configFileExt;\n}\nelse {\n msg.configFileExt = env.get('configFileExt');\n}\n\nmsg.topic = 'configFiles';\nreturn msg;",
|
|
196
|
+
"func": "const configDir = msg.configDir ?? null;\nif (typeof configDir === 'string' && configDir.trim().length > 0) {\n msg.configDir = configDir;\n}\nelse {\n msg.configDir = env.get('configDir');\n}\n\nconst configFileExt = msg.configFileExt ?? null;\nif (typeof configFileExt === 'string' && configFileExt.trim().length > 0) {\n msg.configFileExt = configFileExt;\n}\nelse {\n msg.configFileExt = env.get('configFileExt');\n}\n\nconst concatArrays = msg.concatArrays ?? null;\nif (typeof concatArrays === 'boolean') {\n msg.concatArrays = concatArrays;\n}\nelse {\n msg.concatArrays = env.get('concatArrays');\n}\n\nmsg.topic = 'configFiles';\nreturn msg;",
|
|
157
197
|
"outputs": 1,
|
|
158
198
|
"timeout": 0,
|
|
159
199
|
"noerr": 0,
|
|
@@ -218,36 +258,13 @@
|
|
|
218
258
|
]
|
|
219
259
|
]
|
|
220
260
|
},
|
|
221
|
-
{
|
|
222
|
-
"id": "86c429715975c781",
|
|
223
|
-
"type": "function",
|
|
224
|
-
"z": "ec796389903c1d0f",
|
|
225
|
-
"name": "merge configs",
|
|
226
|
-
"func": "// const _t = global.get('libTracer');\n// _t.init(node, msg, flow.get('enableTracer')); \n\nlet config = flow.get('mergedConfig');\n\nconfig = lodash.merge(config, msg.payload);\n// _t.trace(node, msg, 'config', lodash.cloneDeep(config));\n\n\n// Last config file read?\nif (msg.parts.index == msg.parts.count - 1) {\n msg.topic = 'config';\n msg.payload = config;\n delete msg.parts;\n delete msg.filename;\n\n node.debug(`Merged ALL configs:\\n ${JSON.stringify(msg.payload, null, 2)}`);\n return msg;\n}\n",
|
|
227
|
-
"outputs": 1,
|
|
228
|
-
"timeout": 0,
|
|
229
|
-
"noerr": 0,
|
|
230
|
-
"initialize": "// Code added here will be run once\n// whenever the node is started.\n\nconst defaultConfig = env.get('defaultConfig') ?? {};\n\nflow.set('mergedConfig', defaultConfig);\n",
|
|
231
|
-
"finalize": "",
|
|
232
|
-
"libs": [
|
|
233
|
-
{
|
|
234
|
-
"var": "lodash",
|
|
235
|
-
"module": "lodash"
|
|
236
|
-
}
|
|
237
|
-
],
|
|
238
|
-
"x": 220,
|
|
239
|
-
"y": 400,
|
|
240
|
-
"wires": [
|
|
241
|
-
[]
|
|
242
|
-
]
|
|
243
|
-
},
|
|
244
261
|
{
|
|
245
262
|
"id": "7f1816d008fa2b70",
|
|
246
263
|
"type": "function",
|
|
247
264
|
"z": "ec796389903c1d0f",
|
|
248
265
|
"name": "log",
|
|
249
266
|
"func": "node.debug(`Reading file '${msg.payload}' ...`)\nreturn msg;",
|
|
250
|
-
"outputs":
|
|
267
|
+
"outputs": 1,
|
|
251
268
|
"timeout": 0,
|
|
252
269
|
"noerr": 0,
|
|
253
270
|
"initialize": "",
|
|
@@ -255,7 +272,11 @@
|
|
|
255
272
|
"libs": [],
|
|
256
273
|
"x": 650,
|
|
257
274
|
"y": 240,
|
|
258
|
-
"wires": [
|
|
275
|
+
"wires": [
|
|
276
|
+
[
|
|
277
|
+
"b46481b92cb28e07"
|
|
278
|
+
]
|
|
279
|
+
]
|
|
259
280
|
},
|
|
260
281
|
{
|
|
261
282
|
"id": "8639805af947d0c3",
|
|
@@ -263,7 +284,7 @@
|
|
|
263
284
|
"z": "ec796389903c1d0f",
|
|
264
285
|
"name": "log",
|
|
265
286
|
"func": "node.debug(`Config read from '${msg.filename}':\\n${JSON.stringify(msg.payload, null, 2)}`)\nreturn msg;",
|
|
266
|
-
"outputs":
|
|
287
|
+
"outputs": 1,
|
|
267
288
|
"timeout": 0,
|
|
268
289
|
"noerr": 0,
|
|
269
290
|
"initialize": "",
|
|
@@ -271,7 +292,11 @@
|
|
|
271
292
|
"libs": [],
|
|
272
293
|
"x": 650,
|
|
273
294
|
"y": 320,
|
|
274
|
-
"wires": [
|
|
295
|
+
"wires": [
|
|
296
|
+
[
|
|
297
|
+
"86c429715975c781"
|
|
298
|
+
]
|
|
299
|
+
]
|
|
275
300
|
},
|
|
276
301
|
{
|
|
277
302
|
"id": "6a7545e5271cd1fa",
|
|
@@ -308,19 +333,42 @@
|
|
|
308
333
|
"id": "efa7ea24e8224b84",
|
|
309
334
|
"type": "function",
|
|
310
335
|
"z": "ec796389903c1d0f",
|
|
311
|
-
"name": "defaultConfig",
|
|
312
|
-
"func": "
|
|
336
|
+
"name": "use defaultConfig only",
|
|
337
|
+
"func": "let defaultConfig = env.get('defaultConfig');\n// defaultConfig may be null or '' (value can be '' if an undefined environment variable is used)\nif (!defaultConfig) {\n defaultConfig = {};\n}\n\n\nmsg.payload = defaultConfig;\nreturn msg;\n",
|
|
313
338
|
"outputs": 1,
|
|
314
339
|
"timeout": 0,
|
|
315
340
|
"noerr": 0,
|
|
316
341
|
"initialize": "",
|
|
317
342
|
"finalize": "",
|
|
318
343
|
"libs": [],
|
|
319
|
-
"x":
|
|
344
|
+
"x": 560,
|
|
320
345
|
"y": 380,
|
|
321
346
|
"wires": [
|
|
322
347
|
[]
|
|
323
348
|
]
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"id": "86c429715975c781",
|
|
352
|
+
"type": "function",
|
|
353
|
+
"z": "ec796389903c1d0f",
|
|
354
|
+
"name": "merge configs",
|
|
355
|
+
"func": "// -----------------------------------------------------------------------\nconst merge_customizer = (objValue, srcValue) => {\n if (Array.isArray(objValue) && Array.isArray(srcValue)) {\n return objValue.concat(srcValue);\n }\n return undefined;\n};\n// -----------------------------------------------------------------------\n\nlet config = flow.get('mergedConfig');\nconst concatArrays = env.get('concatArrays');\n\nif (concatArrays) {\n config = lodash.mergeWith(config, msg.payload, merge_customizer);\n}\nelse {\n config = lodash.merge(config, msg.payload);\n}\nnode.trace(`Merged config after merging file #${msg.parts.index + 1} '${msg.configFiles[msg.parts.index]}':\\n${JSON.stringify(config, null, 2)}`);\n\n\n// Last config file read?\nif (msg.parts.index == msg.parts.count - 1) {\n msg.topic = 'config';\n msg.payload = config;\n delete msg.parts;\n delete msg.filename;\n\n node.debug(`Merged ALL configs (concatArraays: ${concatArrays}):\\n ${JSON.stringify(msg.payload, null, 2)}`);\n return msg;\n}\n",
|
|
356
|
+
"outputs": 1,
|
|
357
|
+
"timeout": 0,
|
|
358
|
+
"noerr": 0,
|
|
359
|
+
"initialize": "let defaultConfig = env.get('defaultConfig');\n// defaultConfig may be null or '' (value can be '' if an undefined environment variable is used)\nif (!defaultConfig) {\n defaultConfig = {};\n}\n\nflow.set('mergedConfig', defaultConfig);\n",
|
|
360
|
+
"finalize": "",
|
|
361
|
+
"libs": [
|
|
362
|
+
{
|
|
363
|
+
"var": "lodash",
|
|
364
|
+
"module": "lodash"
|
|
365
|
+
}
|
|
366
|
+
],
|
|
367
|
+
"x": 220,
|
|
368
|
+
"y": 400,
|
|
369
|
+
"wires": [
|
|
370
|
+
[]
|
|
371
|
+
]
|
|
324
372
|
}
|
|
325
|
-
|
|
373
|
+
]
|
|
326
374
|
}
|