node-opcua-address-space 2.87.0 → 2.89.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 (61) hide show
  1. package/LICENSE +1 -1
  2. package/dist/source/address_space_ts.d.ts +4 -4
  3. package/dist/source/address_space_ts.js +3 -3
  4. package/dist/source/address_space_ts.js.map +1 -1
  5. package/dist/source/helpers/argument_list.js +8 -12
  6. package/dist/source/helpers/argument_list.js.map +1 -1
  7. package/dist/source/helpers/call_helpers.d.ts +1 -1
  8. package/dist/source/helpers/multiform_func.d.ts +8 -8
  9. package/dist/source/interfaces/alarms_and_conditions/ua_condition_ex.d.ts +1 -1
  10. package/dist/source/interfaces/extension_object_constructor.d.ts +1 -1
  11. package/dist/source/interfaces/state_machine/ua_state_machine_type.d.ts +2 -2
  12. package/dist/source/loader/generateAddressSpaceRaw.d.ts +2 -2
  13. package/dist/source/loader/make_xml_extension_object_parser.d.ts +1 -1
  14. package/dist/source/loader/namespace_post_step.d.ts +1 -1
  15. package/dist/source/session_context.d.ts +1 -1
  16. package/dist/src/address_space.js +11 -11
  17. package/dist/src/address_space.js.map +1 -1
  18. package/dist/src/apply_condition_refresh.d.ts +1 -1
  19. package/dist/src/base_node_impl.js +44 -44
  20. package/dist/src/base_node_impl.js.map +1 -1
  21. package/dist/src/event_data.d.ts +2 -2
  22. package/dist/src/extension_object_array_node.d.ts +3 -41
  23. package/dist/src/extension_object_array_node.js +20 -54
  24. package/dist/src/extension_object_array_node.js.map +1 -1
  25. package/dist/src/idx_iterator.d.ts +8 -0
  26. package/dist/src/idx_iterator.js +51 -0
  27. package/dist/src/idx_iterator.js.map +1 -0
  28. package/dist/src/nodeid_manager.d.ts +3 -3
  29. package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +1 -1
  30. package/dist/src/reference_impl.js +6 -6
  31. package/dist/src/reference_impl.js.map +1 -1
  32. package/dist/src/tool_isSupertypeOf.d.ts +4 -4
  33. package/dist/src/ua_data_type_impl.js +12 -12
  34. package/dist/src/ua_data_type_impl.js.map +1 -1
  35. package/dist/src/ua_method_impl.js +6 -6
  36. package/dist/src/ua_method_impl.js.map +1 -1
  37. package/dist/src/ua_object_impl.js +7 -7
  38. package/dist/src/ua_object_impl.js.map +1 -1
  39. package/dist/src/ua_object_type_impl.js +6 -6
  40. package/dist/src/ua_object_type_impl.js.map +1 -1
  41. package/dist/src/ua_reference_type_impl.d.ts +1 -1
  42. package/dist/src/ua_reference_type_impl.js +6 -6
  43. package/dist/src/ua_reference_type_impl.js.map +1 -1
  44. package/dist/src/ua_variable_impl.d.ts +15 -9
  45. package/dist/src/ua_variable_impl.js +57 -50
  46. package/dist/src/ua_variable_impl.js.map +1 -1
  47. package/dist/src/ua_variable_impl_ext_obj.d.ts +10 -6
  48. package/dist/src/ua_variable_impl_ext_obj.js +368 -189
  49. package/dist/src/ua_variable_impl_ext_obj.js.map +1 -1
  50. package/dist/src/ua_variable_type_impl.js +7 -7
  51. package/dist/src/ua_variable_type_impl.js.map +1 -1
  52. package/dist/src/ua_view_impl.js +3 -3
  53. package/dist/src/ua_view_impl.js.map +1 -1
  54. package/package.json +40 -40
  55. package/source/address_space_ts.ts +1 -1
  56. package/source/helpers/argument_list.ts +26 -26
  57. package/src/extension_object_array_node.ts +25 -63
  58. package/src/idx_iterator.ts +52 -0
  59. package/src/ua_variable_impl.ts +65 -55
  60. package/src/ua_variable_impl_ext_obj.ts +429 -231
  61. package/src/ua_variable_type_impl.ts +4 -4
@@ -1,18 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extractPartialData = exports._bindExtensionObject = exports._installExtensionObjectBindingOnProperties = exports.setExtensionObjectValue = exports._setExtensionObject = exports.propagateTouchValueUpward = exports._touchValue = void 0;
4
- const chalk = require("chalk");
3
+ exports.extractPartialData = exports.incrementElement = exports.setElement = exports.getElement = exports._bindExtensionObjectArrayOrMatrix = exports._bindExtensionObject = exports._installExtensionObjectBindingOnProperties = exports.setExtensionObjectPartialValue = exports.propagateTouchValueUpward = exports._touchValue = exports.getProxyTarget = void 0;
5
4
  const node_opcua_assert_1 = require("node-opcua-assert");
6
5
  const node_opcua_data_model_1 = require("node-opcua-data-model");
7
6
  const node_opcua_date_time_1 = require("node-opcua-date-time");
8
- const node_opcua_data_value_1 = require("node-opcua-data-value");
9
7
  const node_opcua_debug_1 = require("node-opcua-debug");
8
+ const node_opcua_extension_object_1 = require("node-opcua-extension-object");
10
9
  const node_opcua_nodeid_1 = require("node-opcua-nodeid");
11
10
  const node_opcua_status_code_1 = require("node-opcua-status-code");
12
11
  const node_opcua_utils_1 = require("node-opcua-utils");
13
12
  const node_opcua_variant_1 = require("node-opcua-variant");
14
- const base_node_private_1 = require("./base_node_private");
15
13
  const ua_variable_impl_1 = require("./ua_variable_impl");
14
+ const idx_iterator_1 = require("./idx_iterator");
16
15
  const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
17
16
  const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
18
17
  // const doDebug = true; // checkDebugFlag(__filename);
@@ -25,37 +24,61 @@ function w(str, n) {
25
24
  function isProxy(ext) {
26
25
  return ext.$isProxy ? true : false;
27
26
  }
27
+ function getProxyVariable(ext) {
28
+ (0, node_opcua_assert_1.default)(isProxy(ext));
29
+ return ext.$variable;
30
+ }
31
+ function getProxyVariableForProp(ext, prop) {
32
+ const uaVariable = getProxyVariable(ext);
33
+ if (!uaVariable)
34
+ return undefined;
35
+ return uaVariable[prop];
36
+ }
28
37
  function getProxyTarget(ext) {
29
38
  (0, node_opcua_assert_1.default)(isProxy(ext));
30
- return ext.$proxyTarget;
39
+ const target = ext.$proxyTarget;
40
+ if (target && isProxy(target)) {
41
+ return getProxyTarget(target);
42
+ }
43
+ return target;
31
44
  }
45
+ exports.getProxyTarget = getProxyTarget;
32
46
  function unProxy(ext) {
33
47
  return isProxy(ext) ? getProxyTarget(ext) : ext;
34
48
  }
35
- function _extensionObjectFieldGetter(target, key /*, receiver*/) {
49
+ function _extensionObjectFieldGetter(getVariable, target, key /*, receiver*/) {
36
50
  if (key === "$isProxy") {
37
51
  return true;
38
52
  }
39
53
  if (key === "$proxyTarget") {
40
54
  return target;
41
55
  }
56
+ if (key === "$variable") {
57
+ return getVariable();
58
+ }
42
59
  if (target[key] === undefined) {
43
60
  return undefined;
44
61
  }
45
62
  return target[key];
46
63
  }
47
- function _extensionObjectFieldSetter(variable, target, key, value /*, receiver*/) {
64
+ function _extensionObjectFieldSetter(getVariable, target, key, value /*, receiver*/) {
48
65
  target[key] = value;
49
- const child = variable[key];
66
+ if (isProxy(target)) {
67
+ return true;
68
+ }
69
+ const uaVariable = getVariable();
70
+ if (!uaVariable)
71
+ return true;
72
+ const child = uaVariable[key];
50
73
  if (child && child.touchValue) {
51
74
  child.touchValue();
52
75
  }
53
76
  return true; // true means the set operation has succeeded
54
77
  }
55
- function makeHandler(variable) {
78
+ function makeHandler(getVariable) {
56
79
  const handler = {
57
- get: _extensionObjectFieldGetter,
58
- set: _extensionObjectFieldSetter.bind(null, variable)
80
+ get: _extensionObjectFieldGetter.bind(null, getVariable),
81
+ set: _extensionObjectFieldSetter.bind(null, getVariable)
59
82
  };
60
83
  return handler;
61
84
  }
@@ -79,17 +102,22 @@ function _touchValue(property, now) {
79
102
  }
80
103
  }
81
104
  exports._touchValue = _touchValue;
82
- function propagateTouchValueUpward(self, now) {
105
+ function propagateTouchValueUpward(self, now, cache) {
83
106
  _touchValue(self, now);
84
107
  if (self.parent && self.parent.nodeClass === node_opcua_data_model_1.NodeClass.Variable) {
85
108
  const parentVar = self.parent;
86
109
  if (!parentVar.isExtensionObject())
87
110
  return;
88
- propagateTouchValueUpward(parentVar, now);
111
+ if (cache) {
112
+ if (cache.has(parentVar))
113
+ return;
114
+ cache.add(parentVar);
115
+ }
116
+ propagateTouchValueUpward(parentVar, now, cache);
89
117
  }
90
118
  }
91
119
  exports.propagateTouchValueUpward = propagateTouchValueUpward;
92
- function propagateTouchValueDownward(self, now) {
120
+ function propagateTouchValueDownward(self, now, cache) {
93
121
  if (!self.isExtensionObject())
94
122
  return;
95
123
  // also propagate changes to embeded variables
@@ -98,36 +126,19 @@ function propagateTouchValueDownward(self, now) {
98
126
  for (const field of definition.fields || []) {
99
127
  const property = self.getChildByName(field.name);
100
128
  if (property) {
129
+ if (cache) {
130
+ if (cache.has(property)) {
131
+ continue;
132
+ }
133
+ cache.add(property);
134
+ }
101
135
  _touchValue(property, now);
102
136
  // to do cascade recursivelly ?
103
137
  }
104
138
  }
105
139
  }
106
- function _setExtensionObject(self, ext) {
107
- // assert(!(ext as any).$isProxy, "internal error ! ExtensionObject has already been proxied !");
108
- if (Array.isArray(ext)) {
109
- (0, node_opcua_assert_1.default)(self.valueRank === 1, "Only Array is supported for the time being");
110
- ext = ext.map((e) => unProxy(e));
111
- self.$dataValue.value.arrayType = node_opcua_variant_1.VariantArrayType.Array;
112
- self.$extensionObject = ext.map((e) => new Proxy(e, makeHandler(self)));
113
- self.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
114
- self.$dataValue.value.value = self.$extensionObject;
115
- self.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
116
- return;
117
- }
118
- else {
119
- ext = unProxy(ext);
120
- self.$extensionObject = new Proxy(ext, makeHandler(self));
121
- self.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
122
- self.$dataValue.value.value = self.$extensionObject;
123
- self.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
124
- }
125
- const now = (0, node_opcua_date_time_1.getCurrentClock)();
126
- propagateTouchValueUpward(self, now);
127
- propagateTouchValueDownward(self, now);
128
- }
129
- exports._setExtensionObject = _setExtensionObject;
130
- function setExtensionObjectValue(node, partialObject) {
140
+ function setExtensionObjectPartialValue(node, partialObject, sourceTimestamp) {
141
+ const variablesToUpdate = new Set();
131
142
  const extensionObject = node.$extensionObject;
132
143
  if (!extensionObject) {
133
144
  throw new Error("setExtensionObjectValue node has no extension object " + node.browseName.toString());
@@ -139,13 +150,32 @@ function setExtensionObjectValue(node, partialObject) {
139
150
  _update_extension_object(extObject[prop], partialObject1[prop]);
140
151
  }
141
152
  else {
142
- extObject[prop] = partialObject1[prop];
153
+ if (isProxy(extObject)) {
154
+ // collect element we have to update
155
+ const target = getProxyTarget(extObject);
156
+ (0, node_opcua_assert_1.default)(!isProxy(target), "something wierd!");
157
+ target[prop] = partialObject1[prop];
158
+ const variable = getProxyVariableForProp(extObject, prop);
159
+ variable && variablesToUpdate.add(variable);
160
+ }
161
+ else {
162
+ extObject[prop] = partialObject1[prop];
163
+ }
143
164
  }
144
165
  }
145
166
  }
146
167
  _update_extension_object(extensionObject, partialObject);
168
+ const now = sourceTimestamp || (0, node_opcua_date_time_1.getCurrentClock)();
169
+ const cache = new Set();
170
+ for (const c of variablesToUpdate) {
171
+ if (cache.has(c))
172
+ continue;
173
+ propagateTouchValueUpward(c, now, cache);
174
+ propagateTouchValueDownward(c, now, cache);
175
+ cache.add(c);
176
+ }
147
177
  }
148
- exports.setExtensionObjectValue = setExtensionObjectValue;
178
+ exports.setExtensionObjectPartialValue = setExtensionObjectPartialValue;
149
179
  function getOrCreateProperty(variableNode, field, options) {
150
180
  const dt = variableNode.getDataTypeNode();
151
181
  // the namespace for the structure browse name elements
@@ -173,7 +203,10 @@ function getOrCreateProperty(variableNode, field, options) {
173
203
  browseName: { namespaceIndex: structureNamespace, name: field.name.toString() },
174
204
  componentOf: variableNode,
175
205
  dataType: field.dataType,
176
- minimumSamplingInterval: variableNode.minimumSamplingInterval
206
+ minimumSamplingInterval: variableNode.minimumSamplingInterval,
207
+ accessLevel: variableNode.accessLevel,
208
+ accessRestrictions: variableNode.accessRestrictions,
209
+ rolePermissions: variableNode.rolePermissions
177
210
  });
178
211
  (0, node_opcua_assert_1.default)(property.minimumSamplingInterval === variableNode.minimumSamplingInterval);
179
212
  }
@@ -185,121 +218,184 @@ function prepareVariantValue(dataType, value) {
185
218
  }
186
219
  return value;
187
220
  }
188
- function bindProperty(variableNode, propertyNode, name, dataType) {
189
- // eslint-disable-next-line @typescript-eslint/no-this-alias
190
- propertyNode.bindVariable({
191
- timestamped_get: () => {
192
- const propertyValue = variableNode.$extensionObject[name];
193
- if (propertyValue === undefined) {
194
- propertyNode.$dataValue.value.dataType = node_opcua_variant_1.DataType.Null;
195
- propertyNode.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
196
- propertyNode.$dataValue.value.value = null;
197
- return new node_opcua_data_value_1.DataValue(propertyNode.$dataValue);
221
+ function installExt(uaVariable, ext) {
222
+ ext = unProxy(ext);
223
+ uaVariable.$extensionObject = new Proxy(ext, makeHandler(() => uaVariable));
224
+ const addressSpace = uaVariable.addressSpace;
225
+ const definition = uaVariable.dataTypeObj.getStructureDefinition();
226
+ const structure = addressSpace.findDataType("Structure");
227
+ for (const field of definition.fields || []) {
228
+ if (field.dataType) {
229
+ const dataTypeNode = addressSpace.findDataType(field.dataType);
230
+ // istanbul ignore next
231
+ if (dataTypeNode && dataTypeNode.isSupertypeOf(structure)) {
232
+ // sub structure .. let make an handler too
233
+ const camelCaseName = (0, node_opcua_utils_1.lowerFirstLetter)(field.name);
234
+ const subExtObj = uaVariable.$extensionObject[camelCaseName];
235
+ if (subExtObj) {
236
+ uaVariable.$extensionObject[camelCaseName] = new Proxy(subExtObj, makeHandler(() => {
237
+ return uaVariable.getComponentByName(field.name);
238
+ }));
239
+ }
240
+ else {
241
+ warningLog("extension object is null");
242
+ }
198
243
  }
199
- const value = prepareVariantValue(dataType, propertyValue);
200
- propertyNode.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
201
- propertyNode.$dataValue.value.dataType = dataType;
202
- propertyNode.$dataValue.value.value = value;
203
- return new node_opcua_data_value_1.DataValue(propertyNode.$dataValue);
204
- },
205
- timestamped_set: (_dataValue, callback) => {
206
- callback(null, node_opcua_status_code_1.StatusCodes.BadNotWritable);
207
244
  }
208
- }, true);
245
+ }
209
246
  }
210
- function _installExtensionObjectBindingOnProperties(variableNode, options) {
211
- const addressSpace = variableNode.addressSpace;
212
- const dt = variableNode.getDataTypeNode();
247
+ function _installExtensionObjectBindingOnProperties(uaVariable, options) {
248
+ // may be extension object mechanism has alreday been install
249
+ // in this case we just need to rebind the properties...
250
+ if (uaVariable.$extensionObject) {
251
+ const extObj = uaVariable.$extensionObject;
252
+ uaVariable.bindExtensionObject(extObj, { createMissingProp: true, force: true });
253
+ return;
254
+ }
255
+ if (uaVariable.$$extensionObjectArray) {
256
+ const extObj = uaVariable.$$extensionObjectArray;
257
+ _bindExtensionObjectArrayOrMatrix(uaVariable, extObj, { createMissingProp: true, force: true });
258
+ return;
259
+ }
260
+ const dataValue = uaVariable.readValue();
261
+ const extObj = dataValue.value.value;
262
+ if (extObj instanceof node_opcua_extension_object_1.ExtensionObject) {
263
+ uaVariable.bindExtensionObject(extObj, { createMissingProp: true, force: true });
264
+ }
265
+ else if (extObj instanceof Array) {
266
+ // istanbul ignore else
267
+ if (dataValue.value.arrayType === node_opcua_variant_1.VariantArrayType.Array || dataValue.value.arrayType === node_opcua_variant_1.VariantArrayType.Matrix) {
268
+ _bindExtensionObjectArrayOrMatrix(uaVariable, extObj, { createMissingProp: true, force: true });
269
+ }
270
+ else {
271
+ throw new Error("Internal Error, unexpected case");
272
+ }
273
+ }
274
+ }
275
+ exports._installExtensionObjectBindingOnProperties = _installExtensionObjectBindingOnProperties;
276
+ function _installFields2(uaVariable, { get, set }, options) {
277
+ options = options || { createMissingProp: false };
278
+ const dt = uaVariable.getDataTypeNode();
213
279
  const definition = dt.getStructureDefinition();
214
280
  for (const field of definition.fields || []) {
215
- // istanbul ignore next
216
281
  if (node_opcua_nodeid_1.NodeId.sameNodeId(node_opcua_nodeid_1.NodeId.nullNodeId, field.dataType)) {
217
282
  warningLog("field.dataType is null ! ", field.name, node_opcua_nodeid_1.NodeId.nullNodeId.toString());
218
283
  warningLog(field.toString());
219
284
  warningLog(" dataType replaced with BaseDataType ");
220
285
  warningLog(definition.toString());
221
- field.dataType = variableNode.resolveNodeId("BaseDataType");
286
+ field.dataType = uaVariable.resolveNodeId("BaseDataType");
222
287
  }
223
- const propertyNode = getOrCreateProperty(variableNode, field, options);
288
+ const propertyNode = getOrCreateProperty(uaVariable, field, options);
224
289
  if (!propertyNode) {
225
290
  continue;
226
291
  }
227
292
  propertyNode.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
228
- propertyNode.touchValue();
229
- const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
230
- // istanbul ignore next
231
- if (doDebug) {
232
- const x = addressSpace.findNode(field.dataType).browseName.toString();
233
- debugLog(chalk.cyan("xxx"), " dataType", w(field.dataType.toString(), 8), w(field.name, 25), "valueRank", chalk.cyan(w((0, base_node_private_1.valueRankToString)(field.valueRank), 10)), chalk.green(w(x, 15)), "basicType = ", chalk.yellow(w(basicDataType.toString(), 20)), propertyNode.nodeId.toString(), propertyNode.readValue().statusCode.toString());
293
+ propertyNode.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
294
+ propertyNode.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
295
+ propertyNode.$dataValue.serverTimestamp = uaVariable.$dataValue.serverTimestamp;
296
+ propertyNode.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
297
+ propertyNode.$dataValue.value.dataType = propertyNode.dataTypeObj.basicDataType;
298
+ propertyNode.$dataValue.value.arrayType = propertyNode.valueRank === -1 ? node_opcua_variant_1.VariantArrayType.Scalar : (propertyNode.valueRank === 1 ? node_opcua_variant_1.VariantArrayType.Array : node_opcua_variant_1.VariantArrayType.Matrix);
299
+ propertyNode.$dataValue.value.dimensions = propertyNode.valueRank > 1 ? propertyNode.arrayDimensions : null;
300
+ const fieldName = field.name;
301
+ installDataValueGetter(propertyNode, () => get(fieldName));
302
+ (0, node_opcua_assert_1.default)(propertyNode._inner_replace_dataValue);
303
+ propertyNode._inner_replace_dataValue = (dataValue, indexRange) => {
304
+ /** */
305
+ const sourceTime = (0, node_opcua_date_time_1.coerceClock)(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
306
+ const value = dataValue.value.value;
307
+ set(field.name, value, sourceTime);
308
+ };
309
+ if (propertyNode.dataTypeObj.basicDataType === node_opcua_variant_1.DataType.ExtensionObject) {
310
+ _installFields2(propertyNode, {
311
+ get: (fieldName) => {
312
+ const mainFieldName = field.name;
313
+ return get(mainFieldName)[(0, node_opcua_utils_1.lowerFirstLetter)(fieldName)];
314
+ },
315
+ set: (fieldName, value, sourceTime) => {
316
+ const mainFieldName = field.name;
317
+ get(mainFieldName)[(0, node_opcua_utils_1.lowerFirstLetter)(fieldName)] = value;
318
+ }
319
+ }, options);
234
320
  }
235
- const camelCaseName = (0, node_opcua_utils_1.lowerFirstLetter)(field.name);
236
- // assert(Object.prototype.hasOwnProperty.call(variableNode.$extensionObject, camelCaseName));
237
- if (variableNode.$extensionObject[camelCaseName] !== undefined && basicDataType === node_opcua_variant_1.DataType.ExtensionObject) {
238
- propertyNode.bindExtensionObject(variableNode.$extensionObject[camelCaseName], Object.assign(Object.assign({}, options), { force: true }));
239
- // replace upwards
240
- variableNode.$extensionObject[camelCaseName] = propertyNode.$extensionObject;
241
- }
242
- else {
243
- const prop = variableNode.$extensionObject[camelCaseName];
244
- if (prop === undefined) {
245
- propertyNode._internal_set_value(new node_opcua_variant_1.Variant({
246
- dataType: node_opcua_variant_1.DataType.Null
247
- }));
248
- }
249
- else {
250
- const preparedValue = prepareVariantValue(basicDataType, prop);
251
- propertyNode._internal_set_value(new node_opcua_variant_1.Variant({
252
- dataType: basicDataType,
253
- value: preparedValue
254
- }));
255
- }
256
- // eslint-disable-next-line @typescript-eslint/no-this-alias
257
- // property.camelCaseName = camelCaseName;
258
- propertyNode.setValueFromSource = function (variant) {
259
- // eslint-disable-next-line @typescript-eslint/no-this-alias
260
- const inner_this = this;
261
- const variant1 = node_opcua_variant_1.Variant.coerce(variant);
262
- inner_this.verifyVariantCompatibility(variant1);
263
- // because self.$extensionObject is a Proxy with handlers that
264
- // cascade the chagne we do not need to call touchValue() here
265
- variableNode.$extensionObject[camelCaseName] = variant1.value;
266
- };
267
- }
268
- (0, node_opcua_assert_1.default)(propertyNode.readValue().statusCode.equals(node_opcua_status_code_1.StatusCodes.Good));
269
- bindProperty(variableNode, propertyNode, camelCaseName, basicDataType);
270
321
  }
271
322
  }
272
- exports._installExtensionObjectBindingOnProperties = _installExtensionObjectBindingOnProperties;
273
- // eslint-disable-next-line complexity
274
- function _bindExtensionObject(self, optionalExtensionObject, options) {
275
- var _a, _b;
276
- options = options || { createMissingProp: false };
277
- const addressSpace = self.addressSpace;
323
+ function installDataValueGetter(propertyNode, get) {
324
+ Object.defineProperty(propertyNode.$dataValue.value, "value", { get });
325
+ const $ = propertyNode.$dataValue;
326
+ Object.defineProperty(propertyNode, "$dataValue", {
327
+ get() {
328
+ return $;
329
+ },
330
+ set: (value) => {
331
+ throw new Error("$dataValue is now frozen and should not be modified this way !\n contact sterfive.com");
332
+ }
333
+ });
334
+ }
335
+ function isVariableContainingExtensionObject(uaVariable) {
336
+ const addressSpace = uaVariable.addressSpace;
278
337
  const structure = addressSpace.findDataType("Structure");
279
- let extensionObject_;
280
338
  if (!structure) {
281
339
  // the addressSpace is limited and doesn't provide extension object
282
340
  // bindExtensionObject cannot be performed and shall finish here.
283
- return null;
341
+ return false;
284
342
  }
285
343
  (0, node_opcua_assert_1.default)(structure.browseName.toString() === "Structure", "expecting DataType Structure to be in IAddressSpace");
286
- const dt = self.getDataTypeNode();
344
+ const dt = uaVariable.getDataTypeNode();
287
345
  if (!dt.isSupertypeOf(structure)) {
346
+ return false;
347
+ }
348
+ return true;
349
+ }
350
+ function _innerBindExtensionObjectScalar(uaVariable, { get, set }, options) {
351
+ uaVariable.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
352
+ uaVariable.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
353
+ uaVariable.$dataValue.value.arrayType = node_opcua_variant_1.VariantArrayType.Scalar;
354
+ uaVariable.setValueFromSource = function (variant) {
355
+ setExtensionObjectPartialValue(this, variant.value);
356
+ };
357
+ installDataValueGetter(uaVariable, get);
358
+ (0, node_opcua_assert_1.default)(uaVariable._inner_replace_dataValue);
359
+ uaVariable._inner_replace_dataValue = (dataValue, indexRange) => {
360
+ /** */
361
+ const ext = dataValue.value.value;
362
+ const sourceTime = (0, node_opcua_date_time_1.coerceClock)(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
363
+ set(ext, sourceTime);
364
+ };
365
+ _installFields2(uaVariable, {
366
+ get: (fieldName) => {
367
+ const extObj = get();
368
+ return extObj[(0, node_opcua_utils_1.lowerFirstLetter)(fieldName)];
369
+ },
370
+ set: (fieldName, value, sourceTime) => {
371
+ const extObj = get();
372
+ extObj[(0, node_opcua_utils_1.lowerFirstLetter)(fieldName)] = value;
373
+ //1 propagateTouchValueDownward(uaVariable, sourceTime);
374
+ //1 propagateTouchValueUpward(uaVariable, sourceTime);
375
+ }
376
+ }, options);
377
+ }
378
+ function _bindExtensionObject(uaVariable, optionalExtensionObject, options) {
379
+ var _a, _b;
380
+ options = options || { createMissingProp: false };
381
+ if (!isVariableContainingExtensionObject(uaVariable)) {
288
382
  return null;
289
383
  }
290
- if (self.valueRank !== -1 && self.valueRank !== 1) {
384
+ const addressSpace = uaVariable.addressSpace;
385
+ let extensionObject_;
386
+ // istanbul ignore next
387
+ if (uaVariable.valueRank !== -1 && uaVariable.valueRank !== 1) {
291
388
  throw new Error("Cannot bind an extension object here, valueRank must be scalar (-1) or one-dimensional (1)");
292
389
  }
293
390
  // istanbul ignore next
294
- if (doDebug) {
295
- debugLog(" ------------------------------ binding ", self.browseName.toString(), self.nodeId.toString());
296
- }
391
+ doDebug && debugLog(" ------------------------------ binding ", uaVariable.browseName.toString(), uaVariable.nodeId.toString());
297
392
  // ignore bindExtensionObject on sub extension object, bindExtensionObject has to be called from the top most object
298
393
  if (!options.force &&
299
- self.parent &&
300
- (self.parent.nodeClass === node_opcua_data_model_1.NodeClass.Variable || self.parent.nodeClass === node_opcua_data_model_1.NodeClass.VariableType)) {
301
- const parentDataType = self.parent.dataType;
394
+ uaVariable.parent &&
395
+ (uaVariable.parent.nodeClass === node_opcua_data_model_1.NodeClass.Variable || uaVariable.parent.nodeClass === node_opcua_data_model_1.NodeClass.VariableType)) {
396
+ const parentDataType = uaVariable.parent.dataType;
302
397
  const dataTypeNode = addressSpace.findNode(parentDataType);
398
+ const structure = addressSpace.findDataType("Structure");
303
399
  // istanbul ignore next
304
400
  if (dataTypeNode && dataTypeNode.isSupertypeOf(structure)) {
305
401
  // warningLog(
@@ -313,98 +409,182 @@ function _bindExtensionObject(self, optionalExtensionObject, options) {
313
409
  }
314
410
  }
315
411
  // -------------------- make sure we do not bind a variable twice ....
316
- if (self.$extensionObject && !optionalExtensionObject) {
412
+ if (uaVariable.$extensionObject && !optionalExtensionObject) {
317
413
  // istanbul ignore next
318
- if (!self.checkExtensionObjectIsCorrect(self.$extensionObject)) {
319
- warningLog("on node : ", self.browseName.toString(), self.nodeId.toString(), "dataType=", self.dataType.toString({ addressSpace: self.addressSpace }));
320
- warningLog((_a = self.$extensionObject) === null || _a === void 0 ? void 0 : _a.toString());
414
+ if (!uaVariable.checkExtensionObjectIsCorrect(uaVariable.$extensionObject)) {
415
+ warningLog("on node : ", uaVariable.browseName.toString(), uaVariable.nodeId.toString(), "dataType=", uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace }));
416
+ warningLog((_a = uaVariable.$extensionObject) === null || _a === void 0 ? void 0 : _a.toString());
321
417
  throw new Error("bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
322
- self.dataType.toString({ addressSpace: self.addressSpace }) +
418
+ uaVariable.dataType.toString({ addressSpace: uaVariable.addressSpace }) +
323
419
  " but we got a " +
324
- ((_b = self.$extensionObject) === null || _b === void 0 ? void 0 : _b.constructor.name));
420
+ ((_b = uaVariable.$extensionObject) === null || _b === void 0 ? void 0 : _b.constructor.name));
325
421
  }
326
- return self.$extensionObject;
327
- // throw new Error("Variable already bound");
422
+ return uaVariable.$extensionObject;
328
423
  }
329
- // ------------------------------------------------------
330
- // make sure we have a structure
331
- // ------------------------------------------------------
332
- const s = self.readValue();
333
424
  // istanbul ignore next
334
- if (self.dataTypeObj.isAbstract) {
335
- warningLog("Warning the DataType associated with this Variable is abstract ", self.dataTypeObj.browseName.toString());
425
+ if (uaVariable.dataTypeObj.isAbstract) {
426
+ warningLog("Warning the DataType associated with this Variable is abstract ", uaVariable.dataTypeObj.browseName.toString());
336
427
  warningLog("You need to provide a extension object yourself ");
337
428
  throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
338
429
  }
430
+ const s = uaVariable.readValue();
339
431
  if (s.value && s.value.dataType === node_opcua_variant_1.DataType.ExtensionObject && s.value.value && optionalExtensionObject) {
340
432
  // we want to replace the extension object
341
433
  s.value.value = null;
342
434
  }
343
435
  innerBindExtensionObject();
344
- (0, node_opcua_assert_1.default)(self.$extensionObject instanceof Object);
345
- return self.$extensionObject;
436
+ (0, node_opcua_assert_1.default)(uaVariable.$extensionObject instanceof Object);
437
+ return uaVariable.$extensionObject;
346
438
  function innerBindExtensionObject() {
347
439
  if (s.value && (s.value.dataType === node_opcua_variant_1.DataType.Null || (s.value.dataType === node_opcua_variant_1.DataType.ExtensionObject && !s.value.value))) {
348
- if (self.valueRank === -1 /** Scalar */) {
349
- // create a structure and bind it
350
- extensionObject_ = optionalExtensionObject || addressSpace.constructExtensionObject(self.dataType, {});
351
- // eslint-disable-next-line @typescript-eslint/no-this-alias
352
- self.bindVariable({
353
- timestamped_get() {
354
- const d = new node_opcua_data_value_1.DataValue(self.$dataValue);
355
- d.value.value = self.$extensionObject ? self.$extensionObject.clone() : null;
356
- return d;
357
- },
358
- timestamped_set(dataValue, callback) {
359
- const ext = dataValue.value.value;
360
- if (!self.checkExtensionObjectIsCorrect(ext)) {
361
- return callback(null, node_opcua_status_code_1.StatusCodes.BadInvalidArgument);
362
- }
363
- _setExtensionObject(self, ext);
364
- callback(null, node_opcua_status_code_1.StatusCodes.Good);
365
- }
366
- }, true);
367
- _setExtensionObject(self, extensionObject_);
440
+ if (uaVariable.valueRank === -1 /** Scalar */) {
441
+ extensionObject_ = optionalExtensionObject || addressSpace.constructExtensionObject(uaVariable.dataType, {});
442
+ installExt(uaVariable, extensionObject_);
443
+ _innerBindExtensionObjectScalar(uaVariable, {
444
+ get: () => uaVariable.$extensionObject,
445
+ set: (value) => installExt(uaVariable, value)
446
+ }, options);
447
+ return;
368
448
  }
369
- else if (self.valueRank === 1 /** Array */) {
370
- // create a structure and bind it
371
- extensionObject_ = optionalExtensionObject || [];
372
- // eslint-disable-next-line @typescript-eslint/no-this-alias
373
- self.bindVariable({
374
- timestamped_get() {
375
- const d = new node_opcua_data_value_1.DataValue(self.$dataValue);
376
- d.value.value = self.$extensionObject
377
- ? self.$extensionObject.map((e) => e.clone())
378
- : null;
379
- return d;
380
- },
381
- timestamped_set(dataValue, callback) {
382
- const ext = dataValue.value.value;
383
- if (!self.checkExtensionObjectIsCorrect(ext)) {
384
- return callback(null, node_opcua_status_code_1.StatusCodes.BadInvalidArgument);
385
- }
386
- _setExtensionObject(self, ext);
387
- callback(null, node_opcua_status_code_1.StatusCodes.Good);
388
- }
389
- }, true);
390
- _setExtensionObject(self, extensionObject_);
449
+ else if (uaVariable.valueRank === 1 /** Array */) {
450
+ throw new Error("Should not get there ! Please fix me");
391
451
  }
392
452
  else {
393
- errorLog(self.toString());
394
- errorLog("Unsupported case ! valueRank= ", self.valueRank);
453
+ errorLog(uaVariable.toString());
454
+ errorLog("Unsupported case ! valueRank= ", uaVariable.valueRank);
395
455
  }
396
456
  }
397
457
  else {
398
458
  // verify that variant has the correct type
399
459
  (0, node_opcua_assert_1.default)(s.value.dataType === node_opcua_variant_1.DataType.ExtensionObject);
400
- self.$extensionObject = s.value.value;
401
- (0, node_opcua_assert_1.default)(self.checkExtensionObjectIsCorrect(self.$extensionObject));
402
- (0, node_opcua_assert_1.default)(s.statusCode.equals(node_opcua_status_code_1.StatusCodes.Good));
460
+ installExt(uaVariable, s.value.value);
461
+ _innerBindExtensionObjectScalar(uaVariable, {
462
+ get: () => uaVariable.$extensionObject,
463
+ set: (value) => installExt(uaVariable, value)
464
+ }, options);
403
465
  }
404
- _installExtensionObjectBindingOnProperties(self, options);
405
466
  }
406
467
  }
407
468
  exports._bindExtensionObject = _bindExtensionObject;
469
+ const getIndexAsText = (index) => {
470
+ if (typeof index === "number")
471
+ return `${index}`;
472
+ return `${index.map((a) => a.toString()).join(",")}`;
473
+ };
474
+ const composeBrowseNameAndNodeId = (uaVariable, indexes) => {
475
+ const iAsText = getIndexAsText(indexes);
476
+ const browseName = (0, node_opcua_data_model_1.coerceQualifiedName)(iAsText);
477
+ let nodeId;
478
+ if (uaVariable.nodeId.identifierType === node_opcua_nodeid_1.NodeIdType.STRING) {
479
+ nodeId = new node_opcua_nodeid_1.NodeId(node_opcua_nodeid_1.NodeIdType.STRING, uaVariable.nodeId.value + `[${iAsText}]`, uaVariable.nodeId.namespace);
480
+ }
481
+ return { browseName, nodeId };
482
+ };
483
+ // eslint-disable-next-line max-statements
484
+ function _bindExtensionObjectArrayOrMatrix(uaVariable, optionalExtensionObjectArray, options) {
485
+ // istanbul ignore next
486
+ if (uaVariable.valueRank < 1) {
487
+ throw new Error("Variable must be a MultiDimensional array");
488
+ }
489
+ const arrayDimensions = uaVariable.arrayDimensions || [];
490
+ // istanbul ignore next
491
+ if (!isVariableContainingExtensionObject(uaVariable)) {
492
+ return [];
493
+ }
494
+ if ((arrayDimensions.length === 0 || arrayDimensions.length === 1 && arrayDimensions[0] === 0) && optionalExtensionObjectArray) {
495
+ arrayDimensions[0] = optionalExtensionObjectArray.length;
496
+ }
497
+ const totalLength = arrayDimensions.reduce((p, c) => p * c, 1);
498
+ /** */
499
+ const addressSpace = uaVariable.addressSpace;
500
+ if (optionalExtensionObjectArray) {
501
+ if (optionalExtensionObjectArray.length !== totalLength) {
502
+ throw new Error(`optionalExtensionObjectArray must have the expected number of element matching ${arrayDimensions}`);
503
+ }
504
+ }
505
+ if (!optionalExtensionObjectArray) {
506
+ optionalExtensionObjectArray = [];
507
+ for (let i = 0; i < totalLength; i++) {
508
+ optionalExtensionObjectArray[i] = addressSpace.constructExtensionObject(uaVariable.dataType, {});
509
+ ;
510
+ }
511
+ }
512
+ uaVariable.$$extensionObjectArray = optionalExtensionObjectArray;
513
+ uaVariable.$dataValue.value.arrayType = uaVariable.valueRank === 1 ? node_opcua_variant_1.VariantArrayType.Array : node_opcua_variant_1.VariantArrayType.Matrix;
514
+ uaVariable.$dataValue.value.dimensions = uaVariable.valueRank === 1 ? null : (uaVariable.arrayDimensions || []);
515
+ uaVariable.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
516
+ uaVariable.$dataValue.value.value = uaVariable.$$extensionObjectArray;
517
+ uaVariable.bindVariable({
518
+ get: () => uaVariable.$dataValue.value
519
+ }, true);
520
+ const namespace = uaVariable.namespace;
521
+ const indexIterator = new idx_iterator_1.IndexIterator(arrayDimensions);
522
+ for (let i = 0; i < totalLength; i++) {
523
+ const index = indexIterator.next();
524
+ const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
525
+ let uaElement = uaVariable.getComponentByName(browseName);
526
+ if (!uaElement) {
527
+ uaElement = namespace.addVariable({
528
+ browseName,
529
+ nodeId,
530
+ componentOf: uaVariable,
531
+ dataType: uaVariable.dataType,
532
+ valueRank: -1,
533
+ accessLevel: uaVariable.accessLevel
534
+ });
535
+ }
536
+ uaElement.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
537
+ uaElement.$dataValue.statusCode = node_opcua_status_code_1.StatusCodes.Good;
538
+ uaElement.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
539
+ uaElement.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
540
+ uaElement.$dataValue.serverTimestamp = uaVariable.$dataValue.serverTimestamp;
541
+ uaElement.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
542
+ uaElement.$dataValue.value.dataType = node_opcua_variant_1.DataType.ExtensionObject;
543
+ uaElement.$dataValue.value.arrayType = node_opcua_variant_1.VariantArrayType.Scalar;
544
+ {
545
+ const capturedIndex = i;
546
+ _innerBindExtensionObjectScalar(uaElement, {
547
+ get: () => uaVariable.$$extensionObjectArray[capturedIndex],
548
+ set: (newValue, sourceTimestamp) => {
549
+ uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
550
+ uaVariable.touchValue();
551
+ propagateTouchValueDownward(uaVariable, sourceTimestamp);
552
+ propagateTouchValueUpward(uaVariable, sourceTimestamp);
553
+ },
554
+ }, Object.assign(Object.assign({}, options), { force: true }));
555
+ }
556
+ }
557
+ return uaVariable.$$extensionObjectArray;
558
+ }
559
+ exports._bindExtensionObjectArrayOrMatrix = _bindExtensionObjectArrayOrMatrix;
560
+ function getElement(path, data) {
561
+ if (typeof path === "string") {
562
+ path = path.split(".");
563
+ }
564
+ let a = data;
565
+ for (const e of path) {
566
+ a = a[e];
567
+ }
568
+ return a;
569
+ }
570
+ exports.getElement = getElement;
571
+ function setElement(path, data, value) {
572
+ if (typeof path === "string") {
573
+ path = path.split(".");
574
+ }
575
+ const last = path.pop();
576
+ let a = data;
577
+ for (const e of path) {
578
+ a = a[e];
579
+ }
580
+ a[last] = value;
581
+ }
582
+ exports.setElement = setElement;
583
+ function incrementElement(path, data) {
584
+ const value = getElement(path, data);
585
+ setElement(path, data, value + 1);
586
+ }
587
+ exports.incrementElement = incrementElement;
408
588
  function extractPartialData(path, extensionObject) {
409
589
  let name;
410
590
  if (typeof path === "string") {
@@ -431,7 +611,6 @@ function extractPartialData(path, extensionObject) {
431
611
  }
432
612
  name = path[path.length - 1];
433
613
  c1[name] = c2[name];
434
- c1[name] += 1;
435
614
  return partialData;
436
615
  }
437
616
  exports.extractPartialData = extractPartialData;