node-opcua-address-space 2.89.0 → 2.90.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 (57) hide show
  1. package/dist/source/address_space_ts.d.ts +3 -3
  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/call_helpers.d.ts +1 -1
  5. package/dist/source/helpers/multiform_func.d.ts +8 -8
  6. package/dist/source/interfaces/alarms_and_conditions/ua_condition_ex.d.ts +1 -1
  7. package/dist/source/interfaces/extension_object_constructor.d.ts +1 -1
  8. package/dist/source/interfaces/state_machine/ua_state_machine_type.d.ts +2 -2
  9. package/dist/source/loader/generateAddressSpaceRaw.d.ts +2 -2
  10. package/dist/source/loader/make_xml_extension_object_parser.d.ts +1 -1
  11. package/dist/source/loader/namespace_post_step.d.ts +1 -1
  12. package/dist/source/session_context.d.ts +1 -1
  13. package/dist/src/address_space.js +11 -11
  14. package/dist/src/address_space.js.map +1 -1
  15. package/dist/src/apply_condition_refresh.d.ts +1 -1
  16. package/dist/src/base_node_impl.js +44 -44
  17. package/dist/src/base_node_impl.js.map +1 -1
  18. package/dist/src/base_node_private.js +6 -6
  19. package/dist/src/base_node_private.js.map +1 -1
  20. package/dist/src/event_data.d.ts +2 -2
  21. package/dist/src/extension_object_array_node.js +11 -0
  22. package/dist/src/extension_object_array_node.js.map +1 -1
  23. package/dist/src/namespace_impl.js +2 -1
  24. package/dist/src/namespace_impl.js.map +1 -1
  25. package/dist/src/nodeid_manager.d.ts +3 -3
  26. package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +1 -1
  27. package/dist/src/nodeset_tools/nodeset_to_xml.js +6 -1
  28. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  29. package/dist/src/reference_impl.js +6 -6
  30. package/dist/src/reference_impl.js.map +1 -1
  31. package/dist/src/tool_isSupertypeOf.d.ts +4 -4
  32. package/dist/src/ua_data_type_impl.js +12 -12
  33. package/dist/src/ua_data_type_impl.js.map +1 -1
  34. package/dist/src/ua_method_impl.js +6 -6
  35. package/dist/src/ua_method_impl.js.map +1 -1
  36. package/dist/src/ua_object_impl.js +7 -7
  37. package/dist/src/ua_object_impl.js.map +1 -1
  38. package/dist/src/ua_object_type_impl.js +6 -6
  39. package/dist/src/ua_object_type_impl.js.map +1 -1
  40. package/dist/src/ua_reference_type_impl.js +6 -6
  41. package/dist/src/ua_reference_type_impl.js.map +1 -1
  42. package/dist/src/ua_variable_impl.js +57 -20
  43. package/dist/src/ua_variable_impl.js.map +1 -1
  44. package/dist/src/ua_variable_impl_ext_obj.d.ts +2 -0
  45. package/dist/src/ua_variable_impl_ext_obj.js +49 -13
  46. package/dist/src/ua_variable_impl_ext_obj.js.map +1 -1
  47. package/dist/src/ua_variable_type_impl.js +6 -6
  48. package/dist/src/ua_variable_type_impl.js.map +1 -1
  49. package/dist/src/ua_view_impl.js +3 -3
  50. package/dist/src/ua_view_impl.js.map +1 -1
  51. package/package.json +29 -29
  52. package/src/base_node_private.ts +7 -7
  53. package/src/extension_object_array_node.ts +11 -2
  54. package/src/namespace_impl.ts +4 -3
  55. package/src/nodeset_tools/nodeset_to_xml.ts +9 -4
  56. package/src/ua_variable_impl.ts +51 -15
  57. package/src/ua_variable_impl_ext_obj.ts +56 -16
@@ -13,15 +13,15 @@ const node_opcua_address_space_base_1 = require("node-opcua-address-space-base")
13
13
  const session_context_1 = require("../source/session_context");
14
14
  const base_node_impl_1 = require("./base_node_impl");
15
15
  class UAViewImpl extends base_node_impl_1.BaseNodeImpl {
16
- get eventNotifier() {
17
- return this._eventNotifier;
18
- }
19
16
  constructor(options) {
20
17
  super(options);
21
18
  this.nodeClass = node_opcua_data_model_1.NodeClass.View;
22
19
  this.containsNoLoops = !!options.containsNoLoops;
23
20
  this._eventNotifier = node_opcua_address_space_base_1.EventNotifierFlags.None;
24
21
  }
22
+ get eventNotifier() {
23
+ return this._eventNotifier;
24
+ }
25
25
  readAttribute(context, attributeId) {
26
26
  context = context || session_context_1.SessionContext.defaultContext;
27
27
  const options = {};
@@ -1 +1 @@
1
- {"version":3,"file":"ua_view_impl.js","sourceRoot":"","sources":["../../src/ua_view_impl.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,iEAAkD;AAClD,iEAAqD;AACrD,iEAAiE;AACjE,mEAAqD;AACrD,2DAA8C;AAC9C,iFAA4F;AAE5F,+DAA2D;AAC3D,qDAAyE;AAMzE,MAAa,UAAW,SAAQ,6BAAY;IAIxC,IAAW,aAAa;QACpB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAED,YAAY,OAA4B;QACpC,KAAK,CAAC,OAAO,CAAC,CAAC;QARH,cAAS,GAAG,iCAAS,CAAC,IAAI,CAAC;QASvC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;QACjD,IAAI,CAAC,cAAc,GAAG,kDAAkB,CAAC,IAAI,CAAC;IAClD,CAAC;IAEM,aAAa,CAAC,OAA+B,EAAE,WAAyB;QAC3E,OAAO,GAAG,OAAO,IAAI,gCAAc,CAAC,cAAc,CAAC;QAEnD,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,QAAQ,WAAW,EAAE;YACjB,KAAK,oCAAY,CAAC,aAAa;gBAC3B,OAAO,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,6BAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvE,OAAO,CAAC,UAAU,GAAG,oCAAW,CAAC,IAAI,CAAC;gBACtC,MAAM;YAEV,KAAK,oCAAY,CAAC,eAAe;gBAC7B,OAAO,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,6BAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC5E,OAAO,CAAC,UAAU,GAAG,oCAAW,CAAC,IAAI,CAAC;gBACtC,MAAM;YAEV;gBACI,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;SACxD;QACD,OAAO,IAAI,iCAAS,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;CACJ;AAnCD,gCAmCC"}
1
+ {"version":3,"file":"ua_view_impl.js","sourceRoot":"","sources":["../../src/ua_view_impl.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,iEAAkD;AAClD,iEAAqD;AACrD,iEAAiE;AACjE,mEAAqD;AACrD,2DAA8C;AAC9C,iFAA4F;AAE5F,+DAA2D;AAC3D,qDAAyE;AAMzE,MAAa,UAAW,SAAQ,6BAAY;IAQxC,YAAY,OAA4B;QACpC,KAAK,CAAC,OAAO,CAAC,CAAC;QARH,cAAS,GAAG,iCAAS,CAAC,IAAI,CAAC;QASvC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;QACjD,IAAI,CAAC,cAAc,GAAG,kDAAkB,CAAC,IAAI,CAAC;IAClD,CAAC;IARD,IAAW,aAAa;QACpB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAQM,aAAa,CAAC,OAA+B,EAAE,WAAyB;QAC3E,OAAO,GAAG,OAAO,IAAI,gCAAc,CAAC,cAAc,CAAC;QAEnD,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,QAAQ,WAAW,EAAE;YACjB,KAAK,oCAAY,CAAC,aAAa;gBAC3B,OAAO,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,6BAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvE,OAAO,CAAC,UAAU,GAAG,oCAAW,CAAC,IAAI,CAAC;gBACtC,MAAM;YAEV,KAAK,oCAAY,CAAC,eAAe;gBAC7B,OAAO,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,6BAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC5E,OAAO,CAAC,UAAU,GAAG,oCAAW,CAAC,IAAI,CAAC;gBACtC,MAAM;YAEV;gBACI,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;SACxD;QACD,OAAO,IAAI,iCAAS,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;CACJ;AAnCD,gCAmCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space",
3
- "version": "2.89.0",
3
+ "version": "2.90.0",
4
4
  "description": "pure nodejs OPCUA SDK - module -address-space",
5
5
  "main": "./dist/src/index_current.js",
6
6
  "types": "./dist/source/index.d.ts",
@@ -22,36 +22,36 @@
22
22
  "chalk": "4.1.2",
23
23
  "dequeue": "^1.0.5",
24
24
  "lodash": "4.17.21",
25
- "node-opcua-address-space-base": "2.89.0",
25
+ "node-opcua-address-space-base": "2.90.0",
26
26
  "node-opcua-assert": "2.88.0",
27
- "node-opcua-basic-types": "2.89.0",
27
+ "node-opcua-basic-types": "2.90.0",
28
28
  "node-opcua-binary-stream": "2.89.0",
29
- "node-opcua-client-dynamic-extension-object": "2.89.0",
29
+ "node-opcua-client-dynamic-extension-object": "2.90.0",
30
30
  "node-opcua-constants": "2.88.0",
31
31
  "node-opcua-crypto": "^2.1.2",
32
- "node-opcua-data-access": "2.89.0",
33
- "node-opcua-data-model": "2.89.0",
34
- "node-opcua-data-value": "2.89.0",
35
- "node-opcua-date-time": "2.89.0",
36
- "node-opcua-debug": "2.88.0",
32
+ "node-opcua-data-access": "2.90.0",
33
+ "node-opcua-data-model": "2.90.0",
34
+ "node-opcua-data-value": "2.90.0",
35
+ "node-opcua-date-time": "2.90.0",
36
+ "node-opcua-debug": "2.90.0",
37
37
  "node-opcua-enum": "2.88.0",
38
- "node-opcua-extension-object": "2.89.0",
39
- "node-opcua-factory": "2.89.0",
40
- "node-opcua-nodeid": "2.88.0",
41
- "node-opcua-nodeset-ua": "2.89.0",
42
- "node-opcua-numeric-range": "2.89.0",
43
- "node-opcua-object-registry": "2.88.0",
44
- "node-opcua-pseudo-session": "2.89.0",
45
- "node-opcua-service-browse": "2.89.0",
46
- "node-opcua-service-call": "2.89.0",
47
- "node-opcua-service-history": "2.89.0",
48
- "node-opcua-service-translate-browse-path": "2.89.0",
49
- "node-opcua-service-write": "2.89.0",
38
+ "node-opcua-extension-object": "2.90.0",
39
+ "node-opcua-factory": "2.90.0",
40
+ "node-opcua-nodeid": "2.90.0",
41
+ "node-opcua-nodeset-ua": "2.90.0",
42
+ "node-opcua-numeric-range": "2.90.0",
43
+ "node-opcua-object-registry": "2.90.0",
44
+ "node-opcua-pseudo-session": "2.90.0",
45
+ "node-opcua-service-browse": "2.90.0",
46
+ "node-opcua-service-call": "2.90.0",
47
+ "node-opcua-service-history": "2.90.0",
48
+ "node-opcua-service-translate-browse-path": "2.90.0",
49
+ "node-opcua-service-write": "2.90.0",
50
50
  "node-opcua-status-code": "2.89.0",
51
- "node-opcua-types": "2.89.0",
51
+ "node-opcua-types": "2.90.0",
52
52
  "node-opcua-utils": "2.88.0",
53
- "node-opcua-variant": "2.89.0",
54
- "node-opcua-xml2json": "2.88.0",
53
+ "node-opcua-variant": "2.90.0",
54
+ "node-opcua-xml2json": "2.90.0",
55
55
  "semver": "^7.3.8",
56
56
  "set-prototype-of": "^1.0.0",
57
57
  "thenify": "^3.3.1",
@@ -60,11 +60,11 @@
60
60
  "devDependencies": {
61
61
  "mocha": "^10.2.0",
62
62
  "node-opcua-benchmarker": "2.88.0",
63
- "node-opcua-leak-detector": "2.88.0",
63
+ "node-opcua-leak-detector": "2.90.0",
64
64
  "node-opcua-nodesets": "2.88.0",
65
- "node-opcua-packet-analyzer": "2.89.0",
66
- "node-opcua-service-filter": "2.89.0",
67
- "node-opcua-test-fixtures": "2.89.0",
65
+ "node-opcua-packet-analyzer": "2.90.0",
66
+ "node-opcua-service-filter": "2.90.0",
67
+ "node-opcua-test-fixtures": "2.90.0",
68
68
  "should": "^13.2.3",
69
69
  "sinon": "^15.0.1",
70
70
  "source-map-support": "^0.5.21"
@@ -84,5 +84,5 @@
84
84
  "internet of things"
85
85
  ],
86
86
  "homepage": "http://node-opcua.github.io/",
87
- "gitHead": "93d5502a1b71afbb5e5fa56846615c412b63cc1b"
87
+ "gitHead": "d55f9150c3ffa5b86fbe1a0baba69a2543c3090a"
88
88
  }
@@ -418,7 +418,7 @@ export function VariableOrVariableType_toString(this: UAVariableType | UAVariabl
418
418
  options.add(options.padding + chalk.yellow(" dataType : ") + this.dataType + " " + n);
419
419
  }
420
420
  if (this.nodeClass === NodeClass.Variable) {
421
- const _dataValue = (<WithDataValue>this).$dataValue as DataValue | undefined;
421
+ const _dataValue = (<WithDataValue>this).$dataValue;
422
422
  if (_dataValue) {
423
423
  options.add(
424
424
  options.padding +
@@ -579,9 +579,9 @@ function _extractInterfaces2(typeDefinitionNode: UAObjectType | UAVariableType,
579
579
  // MachineToolIdentificationType
580
580
  //
581
581
  //
582
- // IMachineTagNameplateType -subTypeOf-> ITagNameplateType
583
- // IMachineVendorNamePlateType -subTypeOf-> IMachineryItemVendorNamePlateType
584
- // IMachineryItemVendorNamePlateType -subTypeOf-> IVendorNameplateType
582
+ // IMachineTagNameplateType -subtypeOf-> ITagNameplateType
583
+ // IMachineVendorNamePlateType -subtypeOf-> IMachineryItemVendorNamePlateType
584
+ // IMachineryItemVendorNamePlateType -subtypeOf-> IVendorNameplateType
585
585
  const interfacesRef = typeDefinitionNode.findReferencesEx("HasInterface", BrowseDirection.Forward);
586
586
  const interfaces = interfacesRef.map((r) => addressSpace.findNode(r.nodeId) as UAInterface);
587
587
 
@@ -662,9 +662,9 @@ function _crap_extractInterfaces(typeDefinitionNode: UAObjectType | UAVariableTy
662
662
  // MachineToolIdentificationType
663
663
  //
664
664
  //
665
- // IMachineTagNameplateType -subTypeOf-> ITagNameplateType
666
- // IMachineVendorNamePlateType -subTypeOf-> IMachineryItemVendorNamePlateType
667
- // IMachineryItemVendorNamePlateType -subTypeOf-> IVendorNameplateType
665
+ // IMachineTagNameplateType -subtypeOf-> ITagNameplateType
666
+ // IMachineVendorNamePlateType -subtypeOf-> IMachineryItemVendorNamePlateType
667
+ // IMachineryItemVendorNamePlateType -subtypeOf-> IVendorNameplateType
668
668
  const interfacesRef = typeDefinitionNode.findReferencesEx("HasInterface", BrowseDirection.Forward);
669
669
  const interfaces = interfacesRef.map((r) => r.node! as UAInterface);
670
670
  for (const iface of interfaces) {
@@ -43,6 +43,10 @@ function removeElementByIndex<T extends ExtensionObject>(uaArrayVariableNode: UA
43
43
 
44
44
  // remove element from global array (inefficient)
45
45
  uaArrayVariableNode.$$extensionObjectArray.splice(elementIndex, 1);
46
+ if(uaArrayVariableNode.$$extensionObjectArray !== uaArrayVariableNode.$dataValue.value.value) {
47
+ // throw new Error("internal error");
48
+ }
49
+ uaArrayVariableNode.touchValue();
46
50
 
47
51
  // remove matching component
48
52
  const node = uaArrayVariableNode.getComponentByName(browseName);
@@ -170,12 +174,13 @@ export function bindExtObjArrayNode<T extends ExtensionObject>(
170
174
  // verify that an object with same doesn't already exist
171
175
  dataType = addressSpace.findDataType(variableType.dataType)! as UADataType;
172
176
  assert(dataType!.isSupertypeOf(structure), "expecting a structure (= ExtensionObject) here ");
173
-
177
+ assert(!uaArrayVariableNode.$$extensionObjectArray, "UAVariable ExtensionObject array already bounded");
174
178
  uaArrayVariableNode.$$dataType = dataType;
175
179
  uaArrayVariableNode.$$extensionObjectArray = [];
176
180
  uaArrayVariableNode.$$indexPropertyName = indexPropertyName;
177
-
178
181
  uaArrayVariableNode.$$getElementBrowseName = _getElementBrowseName;
182
+ uaArrayVariableNode.$dataValue.value.value = uaArrayVariableNode.$$extensionObjectArray;
183
+ uaArrayVariableNode.$dataValue.value.arrayType = VariantArrayType.Array;
179
184
 
180
185
  const bindOptions: any = {
181
186
  get: getExtObjArrayNodeValue,
@@ -246,8 +251,12 @@ export function addElement<T extends ExtensionObject>(
246
251
  elVar.bindExtensionObject(extensionObject, { force: true });
247
252
  }
248
253
 
254
+ if(uaArrayVariableNode.$$extensionObjectArray !== uaArrayVariableNode.$dataValue.value.value) {
255
+ // throw new Error("internal error");
256
+ }
249
257
  // also add the value inside
250
258
  uaArrayVariableNode.$$extensionObjectArray.push(elVar.$extensionObject);
259
+ uaArrayVariableNode.touchValue();
251
260
 
252
261
  return elVar;
253
262
  }
@@ -579,10 +579,11 @@ export class NamespaceImpl implements NamespacePrivate {
579
579
  public addReferenceType(options: AddReferenceTypeOptions): UAReferenceType {
580
580
  const addressSpace = this.addressSpace;
581
581
 
582
- const options1 = options as any;
582
+ const options1 = options as CreateNodeOptions;
583
583
  options1.nodeClass = NodeClass.ReferenceType;
584
- options1.references = options1.references || [];
585
-
584
+ options1.references = options.references || [];
585
+ options1.nodeId = options.nodeId;
586
+
586
587
  if (options.subtypeOf) {
587
588
  const subtypeOfNodeId = addressSpace._coerceType(options.subtypeOf, "References", NodeClass.ReferenceType);
588
589
 
@@ -1273,9 +1273,14 @@ function dumpReferenceType(xw: XmlWriter, referenceType: UAReferenceType) {
1273
1273
 
1274
1274
  dumpCommonAttributes(xw, referenceType);
1275
1275
 
1276
+ const isSymmetric = (!referenceType.inverseName || referenceType.inverseName?.text === referenceType.browseName?.name);
1277
+ if (isSymmetric) {
1278
+ xw.writeAttribute("Symmetric", "true");
1279
+ }
1280
+
1276
1281
  dumpCommonElements(xw, referenceType);
1277
1282
 
1278
- if (referenceType.inverseName /* LocalizedText*/) {
1283
+ if (!isSymmetric) {
1279
1284
  xw.startElement("InverseName");
1280
1285
  xw.text(referenceType.inverseName!.text || "");
1281
1286
  xw.endElement();
@@ -1389,9 +1394,9 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
1389
1394
  xw.startElement("NamespaceUris");
1390
1395
 
1391
1396
  // let's sort the dependencies in the same order as the translation table
1392
- const sortedDependencies = dependency.sort((a,b)=> translationTable[a.index] > translationTable[b.index] ? 1: -1);
1393
-
1394
- doDebug && console.log(sortedDependencies.map((a)=>a.index + " + "+ a.namespaceUri).join("\n"));
1397
+ const sortedDependencies = dependency.sort((a, b) => translationTable[a.index] > translationTable[b.index] ? 1 : -1);
1398
+
1399
+ doDebug && console.log(sortedDependencies.map((a) => a.index + " + " + a.namespaceUri).join("\n"));
1395
1400
  doDebug && console.log("translation table ", translationTable);
1396
1401
 
1397
1402
  for (const depend of sortedDependencies) {
@@ -86,6 +86,8 @@ import { apply_condition_refresh, ConditionRefreshCache } from "./apply_conditio
86
86
  import {
87
87
  extractPartialData,
88
88
  incrementElement,
89
+ propagateTouchValueDownward,
90
+ propagateTouchValueDownwardArray,
89
91
  propagateTouchValueUpward,
90
92
  setExtensionObjectPartialValue,
91
93
  _bindExtensionObject,
@@ -524,6 +526,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
524
526
 
525
527
  public isExtensionObject(): boolean {
526
528
  // DataType must be one of Structure
529
+ if (this.dataType.isEmpty()) return false;
527
530
  const dataTypeNode = this.addressSpace.findDataType(this.dataType) as UADataType;
528
531
  if (!dataTypeNode) {
529
532
  throw new Error(" Cannot find DataType " + this.dataType.toString() + " in standard address Space");
@@ -572,9 +575,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
572
575
  dataValue.serverPicoseconds = 0;
573
576
  return callback(null, dataValue);
574
577
  }
575
-
576
578
  try {
577
579
  this.refreshFunc.call(this, (err: Error | null, dataValue?: DataValueLike) => {
580
+ // istanbul ignore next
578
581
  if (err || !dataValue) {
579
582
  errorLog(
580
583
  "-------------- refresh call failed",
@@ -819,7 +822,6 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
819
822
  errorLog(dataValue.toString());
820
823
  this.checkExtensionObjectIsCorrect(dataValue.value.value);
821
824
  }
822
- this.$dataValue = dataValue;
823
825
  // ----------------------------------
824
826
  if (this.$extensionObject) {
825
827
  // we have an extension object already bound to this node
@@ -827,6 +829,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
827
829
  // const ext = dataValue.value.value;
828
830
  this._internal_set_dataValue(dataValue);
829
831
  return;
832
+ } else {
833
+ this.$dataValue = dataValue;
830
834
  }
831
835
  } else {
832
836
  this._internal_set_dataValue(dataValue);
@@ -1283,6 +1287,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1283
1287
  const n = callbacks.length;
1284
1288
  for (const callback1 of callbacks) {
1285
1289
  callback1.call(this, err, dataValue);
1290
+
1286
1291
  }
1287
1292
  };
1288
1293
 
@@ -1712,7 +1717,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1712
1717
  throw new Error("Invalid Extension Object on nodeId =" + this.nodeId.toString());
1713
1718
  }
1714
1719
  }
1715
-
1720
+
1716
1721
  this.verifyVariantCompatibility(dataValue.value);
1717
1722
 
1718
1723
  this._inner_replace_dataValue(dataValue, indexRange);
@@ -1722,23 +1727,54 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1722
1727
  * @private
1723
1728
  */
1724
1729
  public _inner_replace_dataValue(dataValue: DataValue, indexRange?: NumericRange | null) {
1725
- const old_dataValue = this.$dataValue;
1726
1730
 
1727
- this.$dataValue = dataValue;
1728
- this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
1731
+ assert(this.$dataValue.value instanceof Variant);
1732
+ const old_dataValue = this.$dataValue.clone();
1733
+
1734
+ if (this.$$extensionObjectArray && dataValue.value.arrayType !== VariantArrayType.Scalar) {
1735
+ // we have a bounded array or matrix
1736
+ assert(Array.isArray(dataValue.value.value));
1737
+ if (this.$$extensionObjectArray !== this.$dataValue.value.value) {
1738
+ throw new Error("internal error");
1739
+ }
1740
+ this.$$extensionObjectArray = dataValue.value.value;
1741
+ this.$dataValue.value.value = dataValue.value.value;
1742
+
1743
+ this.$dataValue.statusCode = dataValue.statusCode || StatusCodes.Good;
1744
+ this.$dataValue.serverTimestamp = dataValue.serverTimestamp;
1745
+ this.$dataValue.serverPicoseconds = dataValue.serverPicoseconds;
1746
+ this.$dataValue.sourceTimestamp = dataValue.sourceTimestamp;
1747
+ this.$dataValue.sourcePicoseconds = dataValue.sourcePicoseconds;
1729
1748
 
1749
+ } else {
1750
+ this.$dataValue = dataValue;
1751
+ this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
1752
+ }
1730
1753
  // repair missing timestamps
1754
+ const now = new Date();
1731
1755
  if (!dataValue.serverTimestamp) {
1732
- this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp;
1733
- this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds;
1756
+ this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp || now;
1757
+ this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds || 0;
1734
1758
  }
1735
1759
  if (!dataValue.sourceTimestamp) {
1736
- this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp;
1737
- this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds;
1760
+ this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp || now;
1761
+ this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds || 0;
1738
1762
  }
1739
1763
 
1740
1764
  if (!sameDataValue(old_dataValue, dataValue)) {
1741
- this.emit("value_changed", this.$dataValue, indexRange);
1765
+ if (this.getBasicDataType() === DataType.ExtensionObject) {
1766
+ const preciseClock = coerceClock(this.$dataValue.sourceTimestamp, this.$dataValue.sourcePicoseconds);
1767
+ const cache: Set<UAVariable> = new Set();
1768
+ if (this.$$extensionObjectArray) {
1769
+ this.touchValue(preciseClock);
1770
+ propagateTouchValueDownwardArray(this, preciseClock, cache);
1771
+ } else {
1772
+ this.touchValue(preciseClock);
1773
+ propagateTouchValueDownward(this, preciseClock, cache);
1774
+ }
1775
+ } else {
1776
+ this.emit("value_changed", this.$dataValue, indexRange);
1777
+ }
1742
1778
  }
1743
1779
  }
1744
1780
 
@@ -2067,7 +2103,7 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOpt
2067
2103
  this._get_func = options.get;
2068
2104
 
2069
2105
  const timestamped_get_func_from__Variable_bind_with_simple_get = () => {
2070
- const value = this._get_func();
2106
+ const value: Variant | StatusCode = this._get_func();
2071
2107
 
2072
2108
  /* istanbul ignore next */
2073
2109
  if (!is_Variant_or_StatusCode(value)) {
@@ -2081,10 +2117,10 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOpt
2081
2117
  );
2082
2118
  }
2083
2119
  if (is_StatusCode(value)) {
2084
- return new DataValue({ statusCode: value });
2120
+ return new DataValue({ statusCode: value as StatusCode });
2085
2121
  } else {
2086
- if (!this.$dataValue || !this.$dataValue.statusCode.isGoodish() || !sameVariant(this.$dataValue.value, value)) {
2087
- this.setValueFromSource(value, StatusCodes.Good);
2122
+ if (!this.$dataValue || !this.$dataValue.statusCode.isGoodish() || !sameVariant(this.$dataValue.value, value as Variant)) {
2123
+ this._inner_replace_dataValue(new DataValue({ value }));
2088
2124
  }
2089
2125
  return this.$dataValue;
2090
2126
  }
@@ -104,12 +104,12 @@ export function _touchValue(property: UAVariableImpl, now: PreciseClock): void {
104
104
  property.$dataValue.serverTimestamp = now.timestamp;
105
105
  property.$dataValue.serverPicoseconds = now.picoseconds;
106
106
  property.$dataValue.statusCode = StatusCodes.Good;
107
- if (property.minimumSamplingInterval === 0) {
108
- if (property.listenerCount("value_changed") > 0) {
109
- const clonedDataValue = property.readValue();
110
- property.emit("value_changed", clonedDataValue);
111
- }
107
+ // if (property.minimumSamplingInterval === 0) {
108
+ if (property.listenerCount("value_changed") > 0) {
109
+ const clonedDataValue = property.readValue();
110
+ property.emit("value_changed", clonedDataValue);
112
111
  }
112
+ // }
113
113
  }
114
114
 
115
115
  export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
@@ -126,7 +126,7 @@ export function propagateTouchValueUpward(self: UAVariableImpl, now: PreciseCloc
126
126
  }
127
127
  }
128
128
 
129
- function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
129
+ export function propagateTouchValueDownward(self: UAVariableImpl, now: PreciseClock, cache?: Set<UAVariable>): void {
130
130
  if (!self.isExtensionObject()) return;
131
131
  // also propagate changes to embeded variables
132
132
  const dataTypeNode = self.getDataTypeNode();
@@ -336,7 +336,7 @@ function _installFields2(uaVariable: UAVariableImpl, { get, set }: {
336
336
  propertyNode.$dataValue.serverPicoseconds = uaVariable.$dataValue.serverPicoseconds;
337
337
  propertyNode.$dataValue.value.dataType = propertyNode.dataTypeObj.basicDataType;
338
338
  propertyNode.$dataValue.value.arrayType = propertyNode.valueRank === -1 ? VariantArrayType.Scalar : (propertyNode.valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix)
339
- propertyNode.$dataValue.value.dimensions =propertyNode.valueRank > 1 ? propertyNode.arrayDimensions : null;
339
+ propertyNode.$dataValue.value.dimensions = propertyNode.valueRank > 1 ? propertyNode.arrayDimensions : null;
340
340
 
341
341
  const fieldName = field.name!;
342
342
  installDataValueGetter(propertyNode, () => get(fieldName));
@@ -398,7 +398,7 @@ function isVariableContainingExtensionObject(uaVariable: UAVariableImpl): boolea
398
398
  function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
399
399
  { get, set }: {
400
400
  get: () => ExtensionObject;
401
- set: (value: ExtensionObject, sourceTimestamp: PreciseClock) => void;
401
+ set: (value: ExtensionObject, sourceTimestamp: PreciseClock, cache: Set<UAVariableImpl>) => void;
402
402
  },
403
403
  options?: BindExtensionObjectOptions
404
404
  ) {
@@ -417,7 +417,8 @@ function _innerBindExtensionObjectScalar(uaVariable: UAVariableImpl,
417
417
  /** */
418
418
  const ext = dataValue.value.value;
419
419
  const sourceTime = coerceClock(dataValue.sourceTimestamp, dataValue.sourcePicoseconds);
420
- set(ext, sourceTime);
420
+ const cache = new Set<UAVariableImpl>();
421
+ set(ext, sourceTime, cache);
421
422
  }
422
423
 
423
424
  _installFields2(uaVariable, {
@@ -607,6 +608,21 @@ export function _bindExtensionObjectArrayOrMatrix(
607
608
  uaVariable.$dataValue.value.dataType = DataType.ExtensionObject;
608
609
  uaVariable.$dataValue.value.value = uaVariable.$$extensionObjectArray;
609
610
 
611
+
612
+ // make sure uaVariable.$dataValue cannot be inadvertantly changed from this point onward
613
+ const $dataValue = uaVariable.$dataValue;
614
+ Object.defineProperty(uaVariable, "$dataValue", {
615
+ get(): DataValue {
616
+ return $dataValue;
617
+ },
618
+ set() {
619
+ throw new Error("$dataValue is now sealed , you should not change internal $dataValue!");
620
+ },
621
+ // writable: true,
622
+ enumerable: true,
623
+ configurable: true,
624
+ });
625
+
610
626
  uaVariable.bindVariable({
611
627
  get: () => uaVariable.$dataValue.value
612
628
  }, true);
@@ -634,7 +650,6 @@ export function _bindExtensionObjectArrayOrMatrix(
634
650
  }) as UAVariableImpl;
635
651
  }
636
652
 
637
- uaElement.$dataValue.value.dataType = DataType.ExtensionObject;
638
653
  uaElement.$dataValue.statusCode = StatusCodes.Good;
639
654
  uaElement.$dataValue.sourceTimestamp = uaVariable.$dataValue.sourceTimestamp;
640
655
  uaElement.$dataValue.sourcePicoseconds = uaVariable.$dataValue.sourcePicoseconds;
@@ -645,16 +660,21 @@ export function _bindExtensionObjectArrayOrMatrix(
645
660
 
646
661
  {
647
662
  const capturedIndex = i;
663
+ const capturedUaElement = uaElement as UAVariableImpl;
648
664
  _innerBindExtensionObjectScalar(uaElement,
649
665
  {
650
666
  get: () => uaVariable.$$extensionObjectArray[capturedIndex],
651
- set: (newValue: ExtensionObject, sourceTimestamp: PreciseClock) => {
652
- uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
653
- uaVariable.touchValue();
654
- propagateTouchValueDownward(uaVariable, sourceTimestamp);
655
- propagateTouchValueUpward(uaVariable, sourceTimestamp);
656
- },
667
+ set: (newValue: ExtensionObject, sourceTimestamp: PreciseClock, cache: Set<UAVariableImpl>) => {
657
668
 
669
+ assert(!isProxy(uaVariable.$$extensionObjectArray[capturedIndex]));
670
+ uaVariable.$$extensionObjectArray[capturedIndex] = newValue;
671
+ if (uaVariable.$$extensionObjectArray !== uaVariable.$dataValue.value.value) {
672
+ console.log("uaVariable", uaVariable.nodeId.toString());
673
+ console.log("Houston! We have a problem ");
674
+ }
675
+ propagateTouchValueDownward(capturedUaElement, sourceTimestamp, cache);
676
+ propagateTouchValueUpward(capturedUaElement, sourceTimestamp, cache);
677
+ }
658
678
  }, { ...options, force: true });
659
679
 
660
680
  }
@@ -717,3 +737,23 @@ export function extractPartialData(path: string | string[], extensionObject: Ext
717
737
  c1[name] = c2[name];
718
738
  return partialData;
719
739
  }
740
+
741
+ export function propagateTouchValueDownwardArray(uaVariable: UAVariableImpl, now: PreciseClock, cache: Set<UAVariable>) {
742
+
743
+ if (!uaVariable.$$extensionObjectArray) return;
744
+ const arrayDimensions = uaVariable.arrayDimensions || [];
745
+ const totalLength = uaVariable.$$extensionObjectArray.length;
746
+
747
+ const indexIterator = new IndexIterator(arrayDimensions);
748
+ for (let i = 0; i < totalLength; i++) {
749
+
750
+ const index = indexIterator.next();
751
+
752
+ const { browseName, nodeId } = composeBrowseNameAndNodeId(uaVariable, index);
753
+ const uaElement = uaVariable.getComponentByName(browseName) as UAVariableImpl | null;
754
+ if (uaElement?.nodeClass === NodeClass.Variable) {
755
+ uaElement.touchValue(now);
756
+ propagateTouchValueDownward(uaElement, now, cache);
757
+ }
758
+ }
759
+ }