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