@flowfuse/nr-launcher 2.32.0 → 2.32.1-5ce7a18-202607101343.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.
@@ -1,4 +1,4 @@
1
- const util = require('@node-red/util').util
1
+ const util = require('./red_util.js')
2
2
 
3
3
  function Memory (config) {
4
4
  this.data = config.data || {}
@@ -0,0 +1,322 @@
1
+ /* eslint-disable no-useless-escape */
2
+
3
+ // Extracted from @node-red/util/util.js to avoid dependency on @node-red/util package
4
+
5
+ function createError (code, message) {
6
+ const e = new Error(message)
7
+ e.code = code
8
+ return e
9
+ }
10
+
11
+ /**
12
+ * Parses a property expression, such as `msg.foo.bar[3]` to validate it
13
+ * and convert it to a canonical version expressed as an Array of property
14
+ * names.
15
+ *
16
+ * For example, `a["b"].c` returns `['a','b','c']`
17
+ *
18
+ * If `msg` is provided, any internal cross-references will be evaluated against that
19
+ * object. Otherwise, it will return a nested set of properties
20
+ *
21
+ * For example, without msg set, 'a[msg.foo]' returns `['a', [ 'msg', 'foo'] ]`
22
+ * But if msg is set to '{"foo": "bar"}', 'a[msg.foo]' returns `['a', 'bar' ]`
23
+ *
24
+ * @param {String} str - the property expression
25
+ * @return {Array} the normalised expression
26
+ * @memberof @node-red/util_util
27
+ */
28
+ function normalisePropertyExpression (str, msg, toString) {
29
+ // This must be kept in sync with validatePropertyExpression
30
+ // in editor/js/ui/utils.js
31
+
32
+ const length = str.length
33
+ if (length === 0) {
34
+ throw createError('INVALID_EXPR', 'Invalid property expression: zero-length')
35
+ }
36
+ const parts = []
37
+ let start = 0
38
+ let inString = false
39
+ let inBox = false
40
+ let quoteChar
41
+ let v
42
+ for (let i = 0; i < length; i++) {
43
+ const c = str[i]
44
+ if (!inString) {
45
+ if (c === "'" || c === '"') {
46
+ if (i !== start) {
47
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + c + ' at position ' + i)
48
+ }
49
+ inString = true
50
+ quoteChar = c
51
+ start = i + 1
52
+ } else if (c === '.') {
53
+ if (i === 0) {
54
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected . at position 0')
55
+ }
56
+ if (start !== i) {
57
+ v = str.substring(start, i)
58
+ if (/^\d+$/.test(v)) {
59
+ parts.push(parseInt(v))
60
+ } else {
61
+ parts.push(v)
62
+ }
63
+ }
64
+ if (i === length - 1) {
65
+ throw createError('INVALID_EXPR', 'Invalid property expression: unterminated expression')
66
+ }
67
+ // Next char is first char of an identifier: a-z 0-9 $ _
68
+ if (!/[a-z0-9\$\_]/i.test(str[i + 1])) {
69
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + str[i + 1] + ' at position ' + (i + 1))
70
+ }
71
+ start = i + 1
72
+ } else if (c === '[') {
73
+ if (i === 0) {
74
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + c + ' at position ' + i)
75
+ }
76
+ if (start !== i) {
77
+ parts.push(str.substring(start, i))
78
+ }
79
+ if (i === length - 1) {
80
+ throw createError('INVALID_EXPR', 'Invalid property expression: unterminated expression')
81
+ }
82
+ // Start of a new expression. If it starts with msg it is a nested expression
83
+ // Need to scan ahead to find the closing bracket
84
+ if (/^msg[.\[]/.test(str.substring(i + 1))) {
85
+ let depth = 1
86
+ let inLocalString = false
87
+ let localStringQuote
88
+ for (let j = i + 1; j < length; j++) {
89
+ if (/["']/.test(str[j])) {
90
+ if (inLocalString) {
91
+ if (str[j] === localStringQuote) {
92
+ inLocalString = false
93
+ }
94
+ } else {
95
+ inLocalString = true
96
+ localStringQuote = str[j]
97
+ }
98
+ }
99
+ if (str[j] === '[') {
100
+ depth++
101
+ } else if (str[j] === ']') {
102
+ depth--
103
+ }
104
+ if (depth === 0) {
105
+ try {
106
+ if (msg) {
107
+ const crossRefProp = getMessageProperty(msg, str.substring(i + 1, j))
108
+ if (crossRefProp === undefined) {
109
+ throw createError('INVALID_EXPR', 'Invalid expression: undefined reference at position ' + (i + 1) + ' : ' + str.substring(i + 1, j))
110
+ }
111
+ parts.push(crossRefProp)
112
+ } else {
113
+ parts.push(normalisePropertyExpression(str.substring(i + 1, j), msg))
114
+ }
115
+ inBox = false
116
+ i = j
117
+ start = j + 1
118
+ break
119
+ } catch (err) {
120
+ throw createError('INVALID_EXPR', 'Invalid expression started at position ' + (i + 1))
121
+ }
122
+ }
123
+ }
124
+ if (depth > 0) {
125
+ throw createError('INVALID_EXPR', "Invalid property expression: unmatched '[' at position " + i)
126
+ }
127
+ continue
128
+ } else if (!/["'\d]/.test(str[i + 1])) {
129
+ // Next char is either a quote or a number
130
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + str[i + 1] + ' at position ' + (i + 1))
131
+ }
132
+ start = i + 1
133
+ inBox = true
134
+ } else if (c === ']') {
135
+ if (!inBox) {
136
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + c + ' at position ' + i)
137
+ }
138
+ if (start !== i) {
139
+ v = str.substring(start, i)
140
+ if (/^\d+$/.test(v)) {
141
+ parts.push(parseInt(v))
142
+ } else {
143
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected array expression at position ' + start)
144
+ }
145
+ }
146
+ start = i + 1
147
+ inBox = false
148
+ } else if (c === ' ') {
149
+ throw createError('INVALID_EXPR', "Invalid property expression: unexpected ' ' at position " + i)
150
+ }
151
+ } else {
152
+ if (c === quoteChar) {
153
+ if (i - start === 0) {
154
+ throw createError('INVALID_EXPR', 'Invalid property expression: zero-length string at position ' + start)
155
+ }
156
+ parts.push(str.substring(start, i))
157
+ // If inBox, next char must be a ]. Otherwise it may be [ or .
158
+ if (inBox && !/\]/.test(str[i + 1])) {
159
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected array expression at position ' + start)
160
+ } else if (!inBox && i + 1 !== length && !/[\[\.]/.test(str[i + 1])) {
161
+ throw createError('INVALID_EXPR', 'Invalid property expression: unexpected ' + str[i + 1] + ' expression at position ' + (i + 1))
162
+ }
163
+ start = i + 1
164
+ inString = false
165
+ }
166
+ }
167
+ }
168
+ if (inBox || inString) {
169
+ // eslint-disable-next-line new-cap
170
+ throw new createError('INVALID_EXPR', 'Invalid property expression: unterminated expression')
171
+ }
172
+ if (start < length) {
173
+ parts.push(str.substring(start))
174
+ }
175
+
176
+ if (toString) {
177
+ let result = parts.shift()
178
+ while (parts.length > 0) {
179
+ let p = parts.shift()
180
+ if (typeof p === 'string') {
181
+ if (/"/.test(p)) {
182
+ p = "'" + p + "'"
183
+ } else {
184
+ p = '"' + p + '"'
185
+ }
186
+ }
187
+ result = result + '[' + p + ']'
188
+ }
189
+ return result
190
+ }
191
+
192
+ return parts
193
+ }
194
+
195
+ /**
196
+ * Gets a property of a message object.
197
+ *
198
+ * Unlike {@link @node-red/util-util.getObjectProperty}, this function will strip `msg.` from the
199
+ * front of the property expression if present.
200
+ *
201
+ * @param {Object} msg - the message object
202
+ * @param {String} expr - the property expression
203
+ * @return {any} the message property, or undefined if it does not exist
204
+ * @throws Will throw an error if the *parent* of the property does not exist
205
+ * @memberof @node-red/util_util
206
+ */
207
+ function getMessageProperty (msg, expr) {
208
+ if (expr.indexOf('msg.') === 0) {
209
+ expr = expr.substring(4)
210
+ }
211
+ return getObjectProperty(msg, expr)
212
+ }
213
+
214
+ /**
215
+ * Gets a property of an object.
216
+ *
217
+ * Given the object:
218
+ *
219
+ * {
220
+ * "pet": {
221
+ * "type": "cat"
222
+ * }
223
+ * }
224
+ *
225
+ * - `pet.type` will return `"cat"`.
226
+ * - `pet.name` will return `undefined`
227
+ * - `car` will return `undefined`
228
+ * - `car.type` will throw an Error (as `car` does not exist)
229
+ *
230
+ * @param {Object} msg - the object
231
+ * @param {String} expr - the property expression
232
+ * @return {any} the object property, or undefined if it does not exist
233
+ * @throws Will throw an error if the *parent* of the property does not exist
234
+ * @memberof @node-red/util_util
235
+ */
236
+ function getObjectProperty (msg, expr) {
237
+ let result = null
238
+ const msgPropParts = normalisePropertyExpression(expr, msg)
239
+ msgPropParts.reduce(function (obj, key) {
240
+ result = (typeof obj[key] !== 'undefined' ? obj[key] : undefined)
241
+ return result
242
+ }, msg)
243
+ return result
244
+ }
245
+
246
+ /**
247
+ * Sets a property of an object.
248
+ *
249
+ * @param {Object} msg - the object
250
+ * @param {String} prop - the property expression
251
+ * @param {any} value - the value to set
252
+ * @param {boolean} createMissing - whether to create missing parent properties
253
+ * @memberof @node-red/util_util
254
+ */
255
+ function setObjectProperty (msg, prop, value, createMissing) {
256
+ if (typeof createMissing === 'undefined') {
257
+ createMissing = (typeof value !== 'undefined')
258
+ }
259
+ const msgPropParts = normalisePropertyExpression(prop, msg)
260
+ const length = msgPropParts.length
261
+ let obj = msg
262
+ let key
263
+ for (let i = 0; i < length - 1; i++) {
264
+ key = msgPropParts[i]
265
+ if (typeof key === 'string' || (typeof key === 'number' && !Array.isArray(obj))) {
266
+ if (hasOwnProperty.call(obj, key)) {
267
+ if (length > 1 && ((typeof obj[key] !== 'object' && typeof obj[key] !== 'function') || obj[key] === null)) {
268
+ // Break out early as we cannot create a property beneath
269
+ // this type of value
270
+ return false
271
+ }
272
+ obj = obj[key]
273
+ } else if (createMissing) {
274
+ if (typeof msgPropParts[i + 1] === 'string') {
275
+ obj[key] = {}
276
+ } else {
277
+ obj[key] = []
278
+ }
279
+ obj = obj[key]
280
+ } else {
281
+ return false
282
+ }
283
+ } else if (typeof key === 'number') {
284
+ // obj is an array
285
+ if (obj[key] === undefined) {
286
+ if (createMissing) {
287
+ if (typeof msgPropParts[i + 1] === 'string') {
288
+ obj[key] = {}
289
+ } else {
290
+ obj[key] = []
291
+ }
292
+ obj = obj[key]
293
+ } else {
294
+ return false
295
+ }
296
+ } else {
297
+ obj = obj[key]
298
+ }
299
+ }
300
+ }
301
+ key = msgPropParts[length - 1]
302
+ if (typeof value === 'undefined') {
303
+ if (typeof key === 'number' && Array.isArray(obj)) {
304
+ obj.splice(key, 1)
305
+ } else {
306
+ delete obj[key]
307
+ }
308
+ } else {
309
+ if (typeof obj === 'object' && obj !== null) {
310
+ obj[key] = value
311
+ } else {
312
+ // Cannot set a property of a non-object/array
313
+ return false
314
+ }
315
+ }
316
+ return true
317
+ }
318
+
319
+ module.exports = {
320
+ getObjectProperty,
321
+ setObjectProperty
322
+ }