node-opcua-address-space 2.56.2 → 2.60.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 (237) hide show
  1. package/LICENSE +20 -20
  2. package/dist/source/address_space_ts.d.ts +0 -2
  3. package/dist/source/helpers/argument_list.js +12 -1
  4. package/dist/source/helpers/argument_list.js.map +1 -1
  5. package/dist/source/loader/load_nodeset2.js +76 -67
  6. package/dist/source/loader/load_nodeset2.js.map +1 -1
  7. package/dist/source/session_context.js +2 -2
  8. package/dist/source/session_context.js.map +1 -1
  9. package/dist/source/set_namespace_meta_data.js +1 -1
  10. package/dist/src/address_space.d.ts +2 -3
  11. package/dist/src/address_space.js +9 -6
  12. package/dist/src/address_space.js.map +1 -1
  13. package/dist/src/address_space_private.d.ts +2 -3
  14. package/dist/src/alarms_and_conditions/condition_snapshot.js +3 -3
  15. package/dist/src/alarms_and_conditions/condition_snapshot.js.map +1 -1
  16. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.js +2 -1
  17. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.js.map +1 -1
  18. package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js +1 -1
  19. package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
  20. package/dist/src/alarms_and_conditions/ua_condition_impl.js +8 -6
  21. package/dist/src/alarms_and_conditions/ua_condition_impl.js.map +1 -1
  22. package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js +1 -1
  23. package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js.map +1 -1
  24. package/dist/src/base_node_private.js +2 -2
  25. package/dist/src/base_node_private.js.map +1 -1
  26. package/dist/src/event_data.js +1 -1
  27. package/dist/src/event_data.js.map +1 -1
  28. package/dist/src/namespace_impl.d.ts +2 -2
  29. package/dist/src/namespace_impl.js +9 -9
  30. package/dist/src/namespace_impl.js.map +1 -1
  31. package/dist/src/nodeset_tools/nodeset_to_xml.js +16 -10
  32. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  33. package/dist/src/nodeset_tools/typedictionary_to_xml.js +17 -10
  34. package/dist/src/nodeset_tools/typedictionary_to_xml.js.map +1 -1
  35. package/dist/src/reference_impl.js +1 -1
  36. package/dist/src/reference_impl.js.map +1 -1
  37. package/dist/src/state_machine/ua_shelving_state_machine_ex.js +20 -13
  38. package/dist/src/state_machine/ua_shelving_state_machine_ex.js.map +1 -1
  39. package/dist/src/ua_data_type_impl.d.ts +15 -5
  40. package/dist/src/ua_data_type_impl.js +129 -51
  41. package/dist/src/ua_data_type_impl.js.map +1 -1
  42. package/dist/src/ua_method_impl.d.ts +3 -2
  43. package/dist/src/ua_method_impl.js +5 -0
  44. package/dist/src/ua_method_impl.js.map +1 -1
  45. package/dist/src/ua_variable_impl.d.ts +6 -6
  46. package/dist/src/ua_variable_impl.js +236 -188
  47. package/dist/src/ua_variable_impl.js.map +1 -1
  48. package/dist/src/ua_variable_type_impl.d.ts +3 -4
  49. package/dist/src/ua_variable_type_impl.js +13 -18
  50. package/dist/src/ua_variable_type_impl.js.map +1 -1
  51. package/distHelpers/add_event_generator_object.js.map +1 -1
  52. package/distHelpers/mock_session.js +1 -1
  53. package/distHelpers/mock_session.js.map +1 -1
  54. package/generate.js +1 -1
  55. package/nodeJS.d.ts +1 -1
  56. package/package.json +36 -36
  57. package/source/address_space_ts.ts +0 -1
  58. package/source/helpers/argument_list.ts +13 -3
  59. package/source/loader/load_nodeset2.ts +99 -79
  60. package/source/session_context.ts +1 -1
  61. package/source/set_namespace_meta_data.ts +1 -1
  62. package/source_nodejs/index.ts +1 -1
  63. package/src/address_space.ts +21 -14
  64. package/src/address_space_private.ts +3 -3
  65. package/src/alarms_and_conditions/condition_snapshot.ts +4 -4
  66. package/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.ts +7 -6
  67. package/src/alarms_and_conditions/ua_alarm_condition_impl.ts +2 -2
  68. package/src/alarms_and_conditions/ua_condition_impl.ts +29 -15
  69. package/src/alarms_and_conditions/ua_off_normal_alarm_impl.ts +1 -1
  70. package/src/base_node_private.ts +6 -2
  71. package/src/event_data.ts +1 -1
  72. package/src/namespace_impl.ts +9 -9
  73. package/src/nodeset_tools/nodeset_to_xml.ts +22 -12
  74. package/src/nodeset_tools/typedictionary_to_xml.ts +17 -7
  75. package/src/reference_impl.ts +3 -3
  76. package/src/state_machine/ua_shelving_state_machine_ex.ts +32 -19
  77. package/src/ua_data_type_impl.ts +168 -61
  78. package/src/ua_method_impl.ts +11 -5
  79. package/src/ua_variable_impl.ts +290 -218
  80. package/src/ua_variable_type_impl.ts +9 -15
  81. package/testHelpers.d.ts +1 -1
  82. package/test_helpers/add_event_generator_object.ts +4 -3
  83. package/test_helpers/mock_session.ts +1 -1
  84. package/test_helpers/test_fixtures/dataType_in_separateNamespace.xml +150 -150
  85. package/test_helpers/test_fixtures/dataType_in_separateNamespace_basic.xml +57 -57
  86. package/test_helpers/test_fixtures/dataType_in_separateNamespace_mix.xml +135 -135
  87. package/test_helpers/test_fixtures/dataType_withEnumeration.xml +82 -82
  88. package/test_helpers/test_fixtures/dataType_with_isOptionSet.xml +194 -194
  89. package/test_helpers/test_fixtures/dataType_with_union.xml +1 -1
  90. package/test_helpers/test_fixtures/fixture_empty_nodeset2.xml +106 -106
  91. package/test_helpers/test_fixtures/fixture_simple_statemachine_nodeset2.xml +1312 -1303
  92. package/test_helpers/test_fixtures/fixuture_nodeset_objects_with_some_methods.xml +362 -362
  93. package/test_helpers/test_fixtures/issue_846.xml +3172 -3172
  94. package/test_helpers/test_fixtures/issue_899_variable_with_nodeid_value.xml +32 -32
  95. package/test_helpers/test_fixtures/mini.Node.Set2.xml +14 -0
  96. package/test_helpers/test_fixtures/mini.nodeset.withVariousVariables.xml +194 -194
  97. package/test_helpers/test_fixtures/minimalist_nodeset_with_models.xml +8 -8
  98. package/test_helpers/test_fixtures/minimalist_nodeset_with_models_more_complex.xml +16 -16
  99. package/test_helpers/test_fixtures/nodeset_with_analog_items.xml +45 -45
  100. package/dist/source/interfaces/alarms_and_conditions/ua_condition_base_i.d.ts +0 -23
  101. package/dist/source/interfaces/alarms_and_conditions/ua_condition_base_i.js +0 -3
  102. package/dist/source/interfaces/alarms_and_conditions/ua_condition_base_i.js.map +0 -1
  103. package/dist/source/interfaces/data_access/ua_discrete_item.d.ts +0 -6
  104. package/dist/source/interfaces/data_access/ua_discrete_item.js +0 -3
  105. package/dist/source/interfaces/data_access/ua_discrete_item.js.map +0 -1
  106. package/dist/source/interfaces/data_access/ua_multistate_discrete.d.ts +0 -25
  107. package/dist/source/interfaces/data_access/ua_multistate_discrete.js +0 -3
  108. package/dist/source/interfaces/data_access/ua_multistate_discrete.js.map +0 -1
  109. package/dist/source/interfaces/data_access/ua_multistate_value_discrete.d.ts +0 -27
  110. package/dist/source/interfaces/data_access/ua_multistate_value_discrete.js +0 -3
  111. package/dist/source/interfaces/data_access/ua_multistate_value_discrete.js.map +0 -1
  112. package/dist/source/interfaces/data_access/ua_two_state_discrete.d.ts +0 -17
  113. package/dist/source/interfaces/data_access/ua_two_state_discrete.js +0 -3
  114. package/dist/source/interfaces/data_access/ua_two_state_discrete.js.map +0 -1
  115. package/dist/source/interfaces/data_access/ua_y_array_item.d.ts +0 -19
  116. package/dist/source/interfaces/data_access/ua_y_array_item.js +0 -3
  117. package/dist/source/interfaces/data_access/ua_y_array_item.js.map +0 -1
  118. package/dist/source/interfaces/state_machine/exclusive_limit_state_machine.d.ts +0 -11
  119. package/dist/source/interfaces/state_machine/exclusive_limit_state_machine.js +0 -3
  120. package/dist/source/interfaces/state_machine/exclusive_limit_state_machine.js.map +0 -1
  121. package/dist/source/interfaces/state_machine/finite_state_machine.d.ts +0 -70
  122. package/dist/source/interfaces/state_machine/finite_state_machine.js +0 -3
  123. package/dist/source/interfaces/state_machine/finite_state_machine.js.map +0 -1
  124. package/dist/source/interfaces/state_machine/program_finite_state_machine.d.ts +0 -74
  125. package/dist/source/interfaces/state_machine/program_finite_state_machine.js +0 -3
  126. package/dist/source/interfaces/state_machine/program_finite_state_machine.js.map +0 -1
  127. package/dist/source/interfaces/state_machine/state_machine.d.ts +0 -342
  128. package/dist/source/interfaces/state_machine/state_machine.js +0 -3
  129. package/dist/source/interfaces/state_machine/state_machine.js.map +0 -1
  130. package/dist/source/interfaces/state_machine/ua_finite_state_variable.d.ts +0 -18
  131. package/dist/source/interfaces/state_machine/ua_finite_state_variable.js +0 -3
  132. package/dist/source/interfaces/state_machine/ua_finite_state_variable.js.map +0 -1
  133. package/dist/source/interfaces/state_machine/ua_state_variable.d.ts +0 -29
  134. package/dist/source/interfaces/state_machine/ua_state_variable.js +0 -3
  135. package/dist/source/interfaces/state_machine/ua_state_variable.js.map +0 -1
  136. package/dist/source/interfaces/state_machine/ua_two_state_variable.d.ts +0 -26
  137. package/dist/source/interfaces/state_machine/ua_two_state_variable.js +0 -3
  138. package/dist/source/interfaces/state_machine/ua_two_state_variable.js.map +0 -1
  139. package/dist/source/interfaces/subscription_diagnostics_variable.d.ts +0 -41
  140. package/dist/source/interfaces/subscription_diagnostics_variable.js +0 -3
  141. package/dist/source/interfaces/subscription_diagnostics_variable.js.map +0 -1
  142. package/dist/src/alarms_and_conditions/base_event_type.d.ts +0 -26
  143. package/dist/src/alarms_and_conditions/base_event_type.js +0 -41
  144. package/dist/src/alarms_and_conditions/base_event_type.js.map +0 -1
  145. package/dist/src/alarms_and_conditions/shelving_state_machine.d.ts +0 -22
  146. package/dist/src/alarms_and_conditions/shelving_state_machine.js +0 -241
  147. package/dist/src/alarms_and_conditions/shelving_state_machine.js.map +0 -1
  148. package/dist/src/alarms_and_conditions/trip_alarm.d.ts +0 -16
  149. package/dist/src/alarms_and_conditions/trip_alarm.js +0 -21
  150. package/dist/src/alarms_and_conditions/trip_alarm.js.map +0 -1
  151. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_base.d.ts +0 -54
  152. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_base.js +0 -255
  153. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_base.js.map +0 -1
  154. package/dist/src/alarms_and_conditions/ua_alarm_condition_base.d.ts +0 -138
  155. package/dist/src/alarms_and_conditions/ua_alarm_condition_base.js +0 -460
  156. package/dist/src/alarms_and_conditions/ua_alarm_condition_base.js.map +0 -1
  157. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm.d.ts +0 -35
  158. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm.js +0 -32
  159. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm.js.map +0 -1
  160. package/dist/src/alarms_and_conditions/ua_condition_base.d.ts +0 -191
  161. package/dist/src/alarms_and_conditions/ua_condition_base.js +0 -1029
  162. package/dist/src/alarms_and_conditions/ua_condition_base.js.map +0 -1
  163. package/dist/src/alarms_and_conditions/ua_discrete_alarm.d.ts +0 -11
  164. package/dist/src/alarms_and_conditions/ua_discrete_alarm.js +0 -58
  165. package/dist/src/alarms_and_conditions/ua_discrete_alarm.js.map +0 -1
  166. package/dist/src/alarms_and_conditions/ua_exclusive_deviation_alarm.d.ts +0 -24
  167. package/dist/src/alarms_and_conditions/ua_exclusive_deviation_alarm.js +0 -59
  168. package/dist/src/alarms_and_conditions/ua_exclusive_deviation_alarm.js.map +0 -1
  169. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm.d.ts +0 -14
  170. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm.js +0 -17
  171. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm.js.map +0 -1
  172. package/dist/src/alarms_and_conditions/ua_exclusive_limit_alarm.d.ts +0 -22
  173. package/dist/src/alarms_and_conditions/ua_exclusive_limit_alarm.js +0 -87
  174. package/dist/src/alarms_and_conditions/ua_exclusive_limit_alarm.js.map +0 -1
  175. package/dist/src/alarms_and_conditions/ua_exclusive_rate_of_change_alarm.d.ts +0 -6
  176. package/dist/src/alarms_and_conditions/ua_exclusive_rate_of_change_alarm.js +0 -11
  177. package/dist/src/alarms_and_conditions/ua_exclusive_rate_of_change_alarm.js.map +0 -1
  178. package/dist/src/alarms_and_conditions/ua_limit_alarm.d.ts +0 -76
  179. package/dist/src/alarms_and_conditions/ua_limit_alarm.js +0 -237
  180. package/dist/src/alarms_and_conditions/ua_limit_alarm.js.map +0 -1
  181. package/dist/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm.d.ts +0 -27
  182. package/dist/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm.js +0 -62
  183. package/dist/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm.js.map +0 -1
  184. package/dist/src/alarms_and_conditions/ua_non_exclusive_limit_alarm.d.ts +0 -49
  185. package/dist/src/alarms_and_conditions/ua_non_exclusive_limit_alarm.js +0 -176
  186. package/dist/src/alarms_and_conditions/ua_non_exclusive_limit_alarm.js.map +0 -1
  187. package/dist/src/alarms_and_conditions/ua_off_normal_alarm.d.ts +0 -47
  188. package/dist/src/alarms_and_conditions/ua_off_normal_alarm.js +0 -151
  189. package/dist/src/alarms_and_conditions/ua_off_normal_alarm.js.map +0 -1
  190. package/dist/src/alarms_and_conditions/ua_system_off_normal_alarm.d.ts +0 -16
  191. package/dist/src/alarms_and_conditions/ua_system_off_normal_alarm.js +0 -18
  192. package/dist/src/alarms_and_conditions/ua_system_off_normal_alarm.js.map +0 -1
  193. package/dist/src/base_node.d.ts +0 -289
  194. package/dist/src/base_node.js +0 -1345
  195. package/dist/src/base_node.js.map +0 -1
  196. package/dist/src/data_access/ua_analog_item.d.ts +0 -13
  197. package/dist/src/data_access/ua_analog_item.js +0 -37
  198. package/dist/src/data_access/ua_analog_item.js.map +0 -1
  199. package/dist/src/data_access/ua_data_item.d.ts +0 -16
  200. package/dist/src/data_access/ua_data_item.js +0 -66
  201. package/dist/src/data_access/ua_data_item.js.map +0 -1
  202. package/dist/src/data_access/ua_multistate_discrete.d.ts +0 -24
  203. package/dist/src/data_access/ua_multistate_discrete.js +0 -132
  204. package/dist/src/data_access/ua_multistate_discrete.js.map +0 -1
  205. package/dist/src/namespace.d.ts +0 -472
  206. package/dist/src/namespace.js +0 -1751
  207. package/dist/src/namespace.js.map +0 -1
  208. package/dist/src/reference.d.ts +0 -43
  209. package/dist/src/reference.js +0 -138
  210. package/dist/src/reference.js.map +0 -1
  211. package/dist/src/session_context.d.ts +0 -4
  212. package/dist/src/session_context.js +0 -9
  213. package/dist/src/session_context.js.map +0 -1
  214. package/dist/src/ua_data_type.d.ts +0 -83
  215. package/dist/src/ua_data_type.js +0 -289
  216. package/dist/src/ua_data_type.js.map +0 -1
  217. package/dist/src/ua_method.d.ts +0 -41
  218. package/dist/src/ua_method.js +0 -202
  219. package/dist/src/ua_method.js.map +0 -1
  220. package/dist/src/ua_object.d.ts +0 -28
  221. package/dist/src/ua_object.js +0 -153
  222. package/dist/src/ua_object.js.map +0 -1
  223. package/dist/src/ua_object_type.d.ts +0 -49
  224. package/dist/src/ua_object_type.js +0 -123
  225. package/dist/src/ua_object_type.js.map +0 -1
  226. package/dist/src/ua_reference_type.d.ts +0 -42
  227. package/dist/src/ua_reference_type.js +0 -138
  228. package/dist/src/ua_reference_type.js.map +0 -1
  229. package/dist/src/ua_variable.d.ts +0 -339
  230. package/dist/src/ua_variable.js +0 -1706
  231. package/dist/src/ua_variable.js.map +0 -1
  232. package/dist/src/ua_variable_type.d.ts +0 -57
  233. package/dist/src/ua_variable_type.js +0 -530
  234. package/dist/src/ua_variable_type.js.map +0 -1
  235. package/dist/src/ua_view.d.ts +0 -16
  236. package/dist/src/ua_view.js +0 -42
  237. package/dist/src/ua_view.js.map +0 -1
@@ -37,11 +37,20 @@ import {
37
37
  ReadProcessedDetails,
38
38
  ReadRawModifiedDetails,
39
39
  StructureDefinition,
40
+ StructureField,
40
41
  WriteValueOptions
41
42
  } from "node-opcua-types";
42
43
  import * as utils from "node-opcua-utils";
43
44
  import { lowerFirstLetter } from "node-opcua-utils";
44
- import { Variant, VariantLike, DataType, sameVariant, VariantArrayType, adjustVariant } from "node-opcua-variant";
45
+ import {
46
+ Variant,
47
+ VariantLike,
48
+ DataType,
49
+ sameVariant,
50
+ VariantArrayType,
51
+ adjustVariant,
52
+ verifyRankAndDimensions
53
+ } from "node-opcua-variant";
45
54
  import { StatusCodeCallback } from "node-opcua-status-code";
46
55
  import {
47
56
  IAddressSpace,
@@ -162,16 +171,16 @@ function validateDataType(
162
171
  if (variantDataType === DataType.Null && !allowNulls) {
163
172
  return false;
164
173
  }
165
- let builtInType: string;
174
+ let builtInType: DataType;
166
175
  let builtInUADataType: UADataType;
167
176
 
168
- const destUADataType = addressSpace.findNode(dataTypeNodeId) as UADataType;
177
+ const destUADataType = addressSpace.findDataType(dataTypeNodeId)!;
169
178
  assert(destUADataType instanceof UADataTypeImpl);
170
179
 
171
180
  if (destUADataType.isAbstract || destUADataType.nodeId.namespace !== 0) {
172
181
  builtInUADataType = destUADataType;
173
182
  } else {
174
- builtInType = DataType[addressSpace.findCorrespondingBasicDataType(destUADataType)];
183
+ builtInType = addressSpace.findCorrespondingBasicDataType(destUADataType);
175
184
  builtInUADataType = addressSpace.findDataType(builtInType)!;
176
185
  }
177
186
  assert(builtInUADataType instanceof UADataTypeImpl);
@@ -183,8 +192,8 @@ function validateDataType(
183
192
  if (destUADataType.isSupertypeOf(enumerationUADataType)) {
184
193
  // istanbul ignore next
185
194
  if (doDebug) {
186
- console.log("destUADataType.", destUADataType.browseName.toString(), destUADataType.nodeId.toString());
187
- console.log(
195
+ debugLog("destUADataType.", destUADataType.browseName.toString(), destUADataType.nodeId.toString());
196
+ debugLog(
188
197
  "enumerationUADataType.",
189
198
  enumerationUADataType.browseName.toString(),
190
199
  enumerationUADataType.nodeId.toString()
@@ -203,14 +212,14 @@ function validateDataType(
203
212
  if (doDebug) {
204
213
  if (dest_isSuperTypeOf_variant) {
205
214
  /* istanbul ignore next*/
206
- console.log(chalk.green(" ---------- Type match !!! "), " on ", nodeId.toString());
215
+ debugLog(chalk.green(" ---------- Type match !!! "), " on ", nodeId.toString());
207
216
  } else {
208
217
  /* istanbul ignore next*/
209
- console.log(chalk.red(" ---------- Type mismatch "), " on ", nodeId.toString());
218
+ debugLog(chalk.red(" ---------- Type mismatch "), " on ", nodeId.toString());
210
219
  }
211
- console.log(chalk.cyan(" Variable data Type is = "), destUADataType.browseName.toString());
212
- console.log(chalk.cyan(" which matches basic Type = "), builtInUADataType.browseName.toString());
213
- console.log(chalk.yellow(" Actual dataType = "), variantUADataType.browseName.toString());
220
+ debugLog(chalk.cyan(" Variable data Type is = "), destUADataType.browseName.toString());
221
+ debugLog(chalk.cyan(" which matches basic Type = "), builtInUADataType.browseName.toString());
222
+ debugLog(chalk.yellow(" Actual dataType = "), variantUADataType.browseName.toString());
214
223
  }
215
224
 
216
225
  return dest_isSuperTypeOf_variant;
@@ -227,37 +236,6 @@ interface UAVariableOptions extends InternalBaseNodeOptions {
227
236
  historizing?: number;
228
237
  }
229
238
 
230
- export function verifyRankAndDimensions(options: { valueRank?: number; arrayDimensions?: number[] | null }): void {
231
- // evaluate valueRank arrayDimensions is specified but valueRank is null
232
- if (options.arrayDimensions && options.valueRank === undefined) {
233
- options.valueRank = options.arrayDimensions.length;
234
- }
235
- options.valueRank = options.valueRank === undefined ? -1 : options.valueRank || 0; // UInt32
236
- assert(typeof options.valueRank === "number");
237
-
238
- options.arrayDimensions = options.arrayDimensions || null;
239
- assert(options.arrayDimensions === null || Array.isArray(options.arrayDimensions));
240
-
241
- if (options.arrayDimensions && options.valueRank <= 0) {
242
- throw new Error("[CONFORMANCE] arrayDimensions must be null if valueRank <=0");
243
- }
244
- // specify default arrayDimension if not provided
245
- if (options.valueRank > 0 && !options.arrayDimensions) {
246
- options.arrayDimensions = new Array(options.valueRank).fill(0);
247
- }
248
- if (!options.arrayDimensions && options.valueRank > 0) {
249
- throw new Error("[CONFORMANCE] arrayDimension must be specified if valueRank >0 " + options.valueRank);
250
- }
251
- if (options.valueRank > 0 && options.arrayDimensions!.length !== options.valueRank) {
252
- throw new Error(
253
- "[CONFORMANCE] when valueRank> 0, arrayDimensions must have valueRank elements, this.valueRank =" +
254
- options.valueRank +
255
- " whereas arrayDimensions.length =" +
256
- options.arrayDimensions!.length
257
- );
258
- }
259
- }
260
-
261
239
  type TimestampGetFunction1 = () => DataValue | Promise<DataValue>;
262
240
  type TimestampGetFunction2 = (callback: (err: Error | null, dataValue?: DataValue) => void) => void;
263
241
  type TimestampGetFunction = TimestampGetFunction1 | TimestampGetFunction2;
@@ -299,7 +277,9 @@ type TimestampSetFunction = TimestampSetFunction1 | TimestampSetFunction2;
299
277
  */
300
278
  export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
301
279
  public readonly nodeClass = NodeClass.Variable;
280
+
302
281
  public dataType: NodeId;
282
+ private _basicDataType?: DataType;
303
283
 
304
284
  public $extensionObject?: any;
305
285
 
@@ -307,9 +287,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
307
287
  public varHistorian?: IVariableHistorian;
308
288
 
309
289
  /**
310
- * @internal
290
+ * @internal @private
311
291
  */
312
- public _dataValue: DataValue;
292
+ public $dataValue: DataValue;
313
293
  public accessLevel: number;
314
294
  public userAccessLevel?: number;
315
295
  public valueRank: number;
@@ -346,11 +326,9 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
346
326
 
347
327
  this.minimumSamplingInterval = adjust_samplingInterval(options.minimumSamplingInterval || 0);
348
328
 
349
- this.historizing = !!options.historizing; // coerced to boolean
350
-
351
- this._dataValue = new DataValue({ statusCode: StatusCodes.UncertainInitialValue, value: {} });
329
+ this.historizing = !!options.historizing; // coerced to boolean"
352
330
 
353
- // xx options.value = options.value || { dataType: DataType.Null };
331
+ this.$dataValue = new DataValue({ statusCode: StatusCodes.UncertainInitialValue, value: { dataType: DataType.Null } });
354
332
 
355
333
  if (options.value) {
356
334
  this.bindVariable(options.value);
@@ -453,11 +431,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
453
431
 
454
432
  if (this._timestamped_get_func) {
455
433
  if (this._timestamped_get_func.length === 0) {
456
- this._dataValue = (this._timestamped_get_func as TimestampGetFunction1)() as DataValue;
434
+ this.$dataValue = (this._timestamped_get_func as TimestampGetFunction1)() as DataValue;
435
+ this.verifyVariantCompatibility(this.$dataValue.value);
457
436
  }
458
437
  }
459
438
 
460
- let dataValue = this._dataValue;
439
+ let dataValue = this.$dataValue;
461
440
 
462
441
  if (isGoodish(dataValue.statusCode)) {
463
442
  // note : extractRange will clone the dataValue
@@ -507,6 +486,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
507
486
  public asyncRefresh(oldestDate: Date, callback: DataValueCallback): void;
508
487
  public asyncRefresh(oldestDate: Date): Promise<DataValue>;
509
488
  public asyncRefresh(...args: any[]): any {
489
+ this.verifyVariantCompatibility(this.$dataValue.value);
490
+
510
491
  const oldestDate = args[0] as Date;
511
492
  assert(oldestDate instanceof Date);
512
493
  const callback = args[1] as DataValueCallback;
@@ -524,22 +505,36 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
524
505
  }
525
506
  }
526
507
 
527
- if (this._dataValue.serverTimestamp && oldestDate.getTime() <= this._dataValue.serverTimestamp!.getTime()) {
508
+ if (this.$dataValue.serverTimestamp && oldestDate.getTime() <= this.$dataValue.serverTimestamp!.getTime()) {
528
509
  const dataValue = this.readValue();
529
510
  dataValue.serverTimestamp = oldestDate;
530
511
  dataValue.serverPicoseconds = 0;
531
512
  return callback(null, dataValue);
532
513
  }
533
-
534
- this.refreshFunc.call(this, (err: Error | null, dataValue?: DataValueLike) => {
535
- if (err || !dataValue) {
536
- dataValue = { statusCode: StatusCodes.BadNoDataAvailable };
537
- }
538
- if (dataValue !== this._dataValue) {
539
- this._internal_set_dataValue(coerceDataValue(dataValue), null);
540
- }
541
- callback(err, this._dataValue);
542
- });
514
+
515
+ try {
516
+ this.refreshFunc.call(this, (err: Error | null, dataValue?: DataValueLike) => {
517
+ if (err || !dataValue) {
518
+ errorLog(
519
+ "-------------- refresh call failed",
520
+ this.browseName.toString(),
521
+ this.nodeId.toString(),
522
+ err?.message
523
+ );
524
+ dataValue = { statusCode: StatusCodes.BadNoDataAvailable };
525
+ }
526
+ if (dataValue !== this.$dataValue) {
527
+ this._internal_set_dataValue(coerceDataValue(dataValue), null);
528
+ }
529
+ callback(err, this.$dataValue);
530
+ });
531
+ } catch (err) {
532
+ errorLog("-------------- refresh call failed 2", this.browseName.toString(), this.nodeId.toString());
533
+ errorLog(err);
534
+ const dataValue = new DataValue({ statusCode: StatusCodes.BadInternalError });
535
+ this._internal_set_dataValue(dataValue, null);
536
+ callback(err as Error, this.$dataValue);
537
+ }
543
538
  }
544
539
 
545
540
  public readEnumValue(): IEnumItem {
@@ -629,10 +624,76 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
629
624
  }
630
625
  }
631
626
 
632
- public adjustVariant(variant: Variant): Variant {
627
+ public getBasicDataType(): DataType {
628
+ if (this._basicDataType) {
629
+ return this._basicDataType;
630
+ }
631
+ if (this.dataType.namespace === 0 && this.dataType.value === 0) {
632
+ return DataType.Null;
633
+ }
633
634
  const addressSpace = this.addressSpace;
634
- const dataTypeNodeId = addressSpace.findCorrespondingBasicDataType(this.dataType);
635
- return adjustVariant(variant, this.valueRank, dataTypeNodeId);
635
+ const dataTypeNode = addressSpace.findDataType(this.dataType)!;
636
+ const basicDataType = dataTypeNode ? dataTypeNode.getBasicDataType() : DataType.Null;
637
+ // const basicDataType = addressSpace.findCorrespondingBasicDataType(this.dataType);
638
+ this._basicDataType = basicDataType;
639
+ return basicDataType;
640
+ }
641
+ public adjustVariant(variant: Variant): Variant {
642
+ return adjustVariant(variant, this.valueRank, this.getBasicDataType());
643
+ }
644
+ public verifyVariantCompatibility(variant: Variant): void {
645
+ try {
646
+ // istanbul ignore next
647
+ if (Object.prototype.hasOwnProperty.call(variant, "value")) {
648
+ if (variant.dataType === null || variant.dataType === undefined) {
649
+ throw new Error("Variant must provide a valid dataType" + variant.toString());
650
+ }
651
+ if (
652
+ variant.dataType === DataType.Boolean &&
653
+ (this.dataType.namespace !== 0 || this.dataType.value !== DataType.Boolean)
654
+ ) {
655
+ throw new Error("Variant must provide a valid Boolean" + variant.toString());
656
+ }
657
+ if (
658
+ this.dataType.namespace === 0 &&
659
+ this.dataType.value === DataType.LocalizedText &&
660
+ variant.dataType !== DataType.LocalizedText
661
+ ) {
662
+ throw new Error("Variant must provide a valid LocalizedText" + variant.toString());
663
+ }
664
+ }
665
+ const basicType = this.getBasicDataType();
666
+ if (
667
+ basicType !== DataType.Null &&
668
+ basicType !== DataType.Variant &&
669
+ variant.dataType !== DataType.Null &&
670
+ variant.dataType !== basicType
671
+ ) {
672
+ const message =
673
+ "UAVariable.setValueFromSource " +
674
+ this.browseName.toString() +
675
+ " nodeId:" +
676
+ this.nodeId.toString() +
677
+ " dataType:" +
678
+ this.dataType.toString() +
679
+ ":\n" +
680
+ "the provided variant must have the expected dataType!\n" +
681
+ " - the expected dataType is " +
682
+ chalk.cyan(DataType[basicType]) +
683
+ "\n" +
684
+ " - the actual dataType is " +
685
+ chalk.magenta(DataType[variant.dataType]) +
686
+ "\n" +
687
+ " - " +
688
+ variant.toString();
689
+ throw new Error(message);
690
+ }
691
+ } catch (err) {
692
+ errorLog("UAVariable ", (err as Error)?.message, this.browseName.toString(), this.nodeId.toString());
693
+ errorLog((err as Error).message);
694
+ errorLog((err as Error).stack);
695
+ throw err;
696
+ }
636
697
  }
637
698
  /**
638
699
  * setValueFromSource is used to let the device sets the variable values
@@ -646,39 +707,24 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
646
707
  * @param [sourceTimestamp= Now]
647
708
  */
648
709
  public setValueFromSource(variant: VariantLike, statusCode?: StatusCode, sourceTimestamp?: Date): void {
649
- statusCode = statusCode || StatusCodes.Good;
650
- // istanbul ignore next
651
- if (Object.prototype.hasOwnProperty.call(variant, "value")) {
652
- if (variant.dataType === null || variant.dataType === undefined) {
653
- throw new Error("Variant must provide a valid dataType" + variant.toString());
654
- }
655
- if (
656
- variant.dataType === DataType.Boolean &&
657
- (this.dataType.namespace !== 0 || this.dataType.value !== DataType.Boolean)
658
- ) {
659
- throw new Error("Variant must provide a valid Boolean" + variant.toString());
660
- }
661
- if (
662
- this.dataType.namespace === 0 &&
663
- this.dataType.value === DataType.LocalizedText &&
664
- variant.dataType !== DataType.LocalizedText
665
- ) {
666
- throw new Error("Variant must provide a valid LocalizedText" + variant.toString());
667
- }
710
+ try {
711
+ statusCode = statusCode || StatusCodes.Good;
712
+ const variant1 = Variant.coerce(variant);
713
+ this.verifyVariantCompatibility(variant1);
714
+ const now = coerceClock(sourceTimestamp, 0);
715
+
716
+ const dataValue = new DataValue(null);
717
+ dataValue.serverPicoseconds = now.picoseconds;
718
+ dataValue.serverTimestamp = now.timestamp;
719
+ dataValue.sourcePicoseconds = now.picoseconds;
720
+ dataValue.sourceTimestamp = now.timestamp;
721
+ dataValue.statusCode = statusCode;
722
+ dataValue.value = variant1;
723
+ this._internal_set_dataValue(dataValue);
724
+ } catch (err) {
725
+ errorLog("UAVariable#setValueFromString Error : ", this.browseName.toString(), this.nodeId.toString());
726
+ throw err;
668
727
  }
669
-
670
- const variant1 = Variant.coerce(variant);
671
-
672
- const now = coerceClock(sourceTimestamp, 0);
673
-
674
- const dataValue = new DataValue(null);
675
- dataValue.serverPicoseconds = now.picoseconds;
676
- dataValue.serverTimestamp = now.timestamp;
677
- dataValue.sourcePicoseconds = now.picoseconds;
678
- dataValue.sourceTimestamp = now.timestamp;
679
- dataValue.statusCode = statusCode;
680
- dataValue.value = variant1;
681
- this._internal_set_dataValue(dataValue);
682
728
  }
683
729
 
684
730
  public writeValue(
@@ -775,6 +821,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
775
821
  if (!err) {
776
822
  correctedDataValue = correctedDataValue || dataValue;
777
823
  assert(correctedDataValue instanceof DataValue);
824
+ correctedDataValue && this.verifyVariantCompatibility(correctedDataValue.value);
778
825
  // xx assert(correctedDataValue.serverTimestamp);
779
826
 
780
827
  if (indexRange && !indexRange.isEmpty()) {
@@ -785,12 +832,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
785
832
  const newArrayOrMatrix = correctedDataValue.value.value;
786
833
 
787
834
  if (correctedDataValue.value.arrayType === VariantArrayType.Array) {
788
- if (this._dataValue.value.arrayType !== VariantArrayType.Array) {
835
+ if (this.$dataValue.value.arrayType !== VariantArrayType.Array) {
789
836
  return callback(null, StatusCodes.BadTypeMismatch);
790
837
  }
791
838
  // check that destination data is also an array
792
- assert(check_valid_array(this._dataValue.value.dataType, this._dataValue.value.value));
793
- const destArr = this._dataValue.value.value;
839
+ assert(check_valid_array(this.$dataValue.value.dataType, this.$dataValue.value.value));
840
+ const destArr = this.$dataValue.value.value;
794
841
  const result = indexRange.set_values(destArr, newArrayOrMatrix);
795
842
 
796
843
  if (result.statusCode.isNot(StatusCodes.Good)) {
@@ -799,14 +846,14 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
799
846
  correctedDataValue.value.value = result.array;
800
847
 
801
848
  // scrap original array so we detect range
802
- this._dataValue.value.value = null;
849
+ this.$dataValue.value.value = null;
803
850
  } else if (correctedDataValue.value.arrayType === VariantArrayType.Matrix) {
804
- const dimensions = this._dataValue.value.dimensions;
805
- if (this._dataValue.value.arrayType !== VariantArrayType.Matrix || !dimensions) {
851
+ const dimensions = this.$dataValue.value.dimensions;
852
+ if (this.$dataValue.value.arrayType !== VariantArrayType.Matrix || !dimensions) {
806
853
  // not a matrix !
807
854
  return callback!(null, StatusCodes.BadTypeMismatch);
808
855
  }
809
- const matrix = this._dataValue.value.value;
856
+ const matrix = this.$dataValue.value.value;
810
857
  const result = indexRange.set_values_matrix(
811
858
  {
812
859
  matrix,
@@ -817,11 +864,11 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
817
864
  if (result.statusCode.isNot(StatusCodes.Good)) {
818
865
  return callback!(null, result.statusCode);
819
866
  }
820
- correctedDataValue.value.dimensions = this._dataValue.value.dimensions;
867
+ correctedDataValue.value.dimensions = this.$dataValue.value.dimensions;
821
868
  correctedDataValue.value.value = result.matrix;
822
869
 
823
870
  // scrap original array so we detect range
824
- this._dataValue.value.value = null;
871
+ this.$dataValue.value.value = null;
825
872
  } else {
826
873
  return callback!(null, StatusCodes.BadTypeMismatch);
827
874
  }
@@ -903,6 +950,11 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
903
950
  if (!this._validate_DataType(value.dataType)) {
904
951
  return StatusCodes.BadTypeMismatch;
905
952
  }
953
+ try {
954
+ this.verifyVariantCompatibility(value);
955
+ } catch(err) {
956
+ return StatusCodes.BadTypeMismatch;
957
+ }
906
958
  return StatusCodes.Good;
907
959
  }
908
960
 
@@ -917,12 +969,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
917
969
  */
918
970
  public touchValue(optionalNow?: PreciseClock): void {
919
971
  const now = optionalNow || getCurrentClock();
920
- this._dataValue.sourceTimestamp = now.timestamp;
921
- this._dataValue.sourcePicoseconds = now.picoseconds;
922
- this._dataValue.serverTimestamp = now.timestamp;
923
- this._dataValue.serverPicoseconds = now.picoseconds;
972
+ this.$dataValue.sourceTimestamp = now.timestamp;
973
+ this.$dataValue.sourcePicoseconds = now.picoseconds;
974
+ this.$dataValue.serverTimestamp = now.timestamp;
975
+ this.$dataValue.serverPicoseconds = now.picoseconds;
924
976
 
925
- this._dataValue.statusCode = StatusCodes.Good;
977
+ this.$dataValue.statusCode = StatusCodes.Good;
926
978
 
927
979
  if (this.minimumSamplingInterval === 0) {
928
980
  if (this.listenerCount("value_changed") > 0) {
@@ -1106,7 +1158,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1106
1158
  }
1107
1159
 
1108
1160
  const readImmediate = (innerCallback: (err: Error | null, dataValue: DataValue) => void) => {
1109
- assert(this._dataValue instanceof DataValue);
1161
+ assert(this.$dataValue instanceof DataValue);
1110
1162
  const dataValue = this.readValue();
1111
1163
  innerCallback(null, dataValue);
1112
1164
  };
@@ -1181,7 +1233,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1181
1233
  assert(typeof newVariable._timestamped_set_func === "function");
1182
1234
 
1183
1235
  assert(newVariable.dataType === this.dataType);
1184
- newVariable._dataValue = this._dataValue.clone();
1236
+ newVariable.$dataValue = this.$dataValue.clone();
1185
1237
  return newVariable;
1186
1238
  }
1187
1239
 
@@ -1204,8 +1256,10 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1204
1256
  return true;
1205
1257
  }
1206
1258
  const addressSpace = this.addressSpace;
1259
+
1260
+ // istanbul ignore next
1207
1261
  if (!(extObj && extObj.constructor)) {
1208
- console.log(extObj);
1262
+ errorLog(extObj);
1209
1263
  throw new Error("expecting an valid extension object");
1210
1264
  }
1211
1265
  const dataType = addressSpace.findDataType(this.dataType);
@@ -1231,7 +1285,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1231
1285
  return extObj.constructor.name === Constructor.name;
1232
1286
  }
1233
1287
  } catch (err) {
1234
- console.log(err);
1288
+ errorLog(err);
1235
1289
  return false;
1236
1290
  }
1237
1291
  }
@@ -1252,7 +1306,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1252
1306
 
1253
1307
  // istanbul ignore next
1254
1308
  if (doDebug) {
1255
- console.log(" ------------------------------ binding ", this.browseName.toString(), this.nodeId.toString());
1309
+ debugLog(" ------------------------------ binding ", this.browseName.toString(), this.nodeId.toString());
1256
1310
  }
1257
1311
  assert(structure && structure.browseName.toString() === "Structure", "expecting DataType Structure to be in IAddressSpace");
1258
1312
 
@@ -1277,14 +1331,14 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1277
1331
  // }
1278
1332
  // istanbul ignore next
1279
1333
  if (!this.checkExtensionObjectIsCorrect(this.$extensionObject!)) {
1280
- console.log(
1334
+ warningLog(
1281
1335
  "on node : ",
1282
1336
  this.browseName.toString(),
1283
1337
  this.nodeId.toString(),
1284
1338
  "dataType=",
1285
1339
  this.dataType.toString({ addressSpace: this.addressSpace })
1286
1340
  );
1287
- console.log(this.$extensionObject?.toString());
1341
+ warningLog(this.$extensionObject?.toString());
1288
1342
  throw new Error(
1289
1343
  "bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
1290
1344
  this.dataType.toString({ addressSpace: this.addressSpace }) +
@@ -1299,45 +1353,33 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1299
1353
 
1300
1354
  // ------------------------------------------------------------------
1301
1355
 
1302
- function prepareVariantValue(dataType: DataType | string, value: VariantLike): VariantLike {
1303
- if (typeof dataType === "string") {
1304
- dataType = (DataType as any)[dataType];
1305
- }
1356
+ function prepareVariantValue(dataType: DataType, value: VariantLike): VariantLike {
1306
1357
  if ((dataType === DataType.Int32 || dataType === DataType.UInt32) && value && (value as any).key) {
1307
1358
  value = value.value;
1308
1359
  }
1309
1360
  return value;
1310
1361
  }
1311
1362
 
1312
- const bindProperty = (propertyNode: UAVariableImpl, name: any, extensionObject: any, dataTypeNodeId: any) => {
1313
- const dataTypeAsString = DataType[dataTypeNodeId];
1314
-
1315
- /*
1316
- property.setValueFromSource(new Variant({
1317
- dataType: dataType,
1318
- value: prepareVariantValue(dataType, this.$extensionObject[name])
1319
- }));
1320
- */
1321
-
1322
- assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
1363
+ const bindProperty = (propertyNode: UAVariableImpl, name: string, extensionObject: ExtensionObject, dataType: DataType) => {
1323
1364
 
1324
1365
  // eslint-disable-next-line @typescript-eslint/no-this-alias
1325
1366
  const self = this;
1326
1367
  propertyNode.bindVariable(
1327
1368
  {
1328
1369
  timestamped_get: () => {
1329
- const prop = self.$extensionObject[name];
1370
+ const propertyValue = self.$extensionObject[name];
1330
1371
 
1331
- if (prop === undefined) {
1332
- propertyNode._dataValue.value.dataType = DataType.Null;
1333
- propertyNode._dataValue.statusCode = StatusCodes.Good;
1334
- propertyNode._dataValue.value.value = null;
1335
- return new DataValue(propertyNode._dataValue);
1372
+ if (propertyValue === undefined) {
1373
+ propertyNode.$dataValue.value.dataType = DataType.Null;
1374
+ propertyNode.$dataValue.statusCode = StatusCodes.Good;
1375
+ propertyNode.$dataValue.value.value = null;
1376
+ return new DataValue(propertyNode.$dataValue);
1336
1377
  }
1337
- const value = prepareVariantValue(dataTypeNodeId, prop);
1338
- propertyNode._dataValue.statusCode = StatusCodes.Good;
1339
- propertyNode._dataValue.value.value = value;
1340
- return new DataValue(propertyNode._dataValue);
1378
+ const value = prepareVariantValue(dataType, propertyValue);
1379
+ propertyNode.$dataValue.statusCode = StatusCodes.Good;
1380
+ propertyNode.$dataValue.value.dataType = dataType;
1381
+ propertyNode.$dataValue.value.value = value;
1382
+ return new DataValue(propertyNode.$dataValue);
1341
1383
  },
1342
1384
  timestamped_set: (dataValue: DataValue, callback: CallbackT<StatusCode>) => {
1343
1385
  dataValue;
@@ -1355,8 +1397,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1355
1397
  const s = this.readValue();
1356
1398
  // istanbul ignore next
1357
1399
  if (this.dataTypeObj.isAbstract) {
1358
- console.log("Warning the DataType associated with this Variable is abstract ", this.dataTypeObj.browseName.toString());
1359
- console.log("You need to provide a extension object yourself ");
1400
+ warningLog("Warning the DataType associated with this Variable is abstract ", this.dataTypeObj.browseName.toString());
1401
+ warningLog("You need to provide a extension object yourself ");
1360
1402
  throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
1361
1403
  }
1362
1404
  if (s.value && (s.value.dataType === DataType.Null || (s.value.dataType === DataType.ExtensionObject && !s.value.value))) {
@@ -1376,8 +1418,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1376
1418
  this.bindVariable(
1377
1419
  {
1378
1420
  timestamped_get() {
1379
- self._dataValue.value.value = self.$extensionObject;
1380
- const d = new DataValue(self._dataValue);
1421
+ self.$dataValue.value.value = self.$extensionObject;
1422
+ const d = new DataValue(self.$dataValue);
1381
1423
  d.value = new Variant(d.value);
1382
1424
  return d;
1383
1425
  },
@@ -1386,7 +1428,6 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1386
1428
  if (!self.checkExtensionObjectIsCorrect(ext)) {
1387
1429
  return callback(null, StatusCodes.BadInvalidArgument);
1388
1430
  }
1389
-
1390
1431
  self.$extensionObject = new Proxy(ext, makeHandler(self));
1391
1432
  self.touchValue();
1392
1433
  callback(null, StatusCodes.Good);
@@ -1402,51 +1443,66 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1402
1443
  assert(s.statusCode.equals(StatusCodes.Good));
1403
1444
  }
1404
1445
 
1405
- let property: any;
1406
- let camelCaseName: any;
1407
1446
  // ------------------------------------------------------
1408
1447
  // now bind each member
1409
1448
  // ------------------------------------------------------
1410
- const definition = dt._getDefinition(false) as StructureDefinition | null;
1449
+ const definition = dt._getDefinition() as StructureDefinition | null;
1411
1450
 
1412
1451
  // istanbul ignore next
1413
1452
  if (!definition) {
1414
1453
  throw new Error("xx definition missing in " + dt.toString());
1415
1454
  }
1416
- for (const field of definition.fields || []) {
1417
- camelCaseName = lowerFirstLetter(field.name!);
1418
- const component = components.filter((f) => f.browseName.name!.toString() === field.name);
1419
- if (component.length === 1) {
1420
- property = component[0];
1455
+
1456
+ const getOrCreateProperty = (field: StructureField): UAVariableImpl => {
1457
+ let property: UAVariableImpl;
1458
+ const selectedComponents = components.filter(
1459
+ (f) => f instanceof UAVariableImpl && f.browseName.name!.toString() === field.name
1460
+ );
1461
+
1462
+ if (field.dataType.value === DataType.Variant) {
1463
+ warningLog("Warning : variant is not supported in ExtensionObject");
1464
+ }
1465
+ if (selectedComponents.length === 1) {
1466
+ property = selectedComponents[0] as UAVariableImpl;
1421
1467
  /* istanbul ignore next */
1422
1468
  } else {
1469
+ debugLog("adding missing array variable", field.name, this.browseName.toString(), this.nodeId.toString());
1423
1470
  // todo: Handle array appropriately...
1424
- assert(component.length === 0);
1471
+ assert(selectedComponents.length === 0);
1425
1472
  // create a variable (Note we may use ns=1;s=parentName/0:PropertyName)
1426
1473
  property = this.namespace.addVariable({
1427
1474
  browseName: { namespaceIndex: structureNamespace, name: field.name!.toString() },
1428
1475
  componentOf: this,
1429
1476
  dataType: field.dataType,
1430
1477
  minimumSamplingInterval: this.minimumSamplingInterval
1431
- });
1478
+ }) as UAVariableImpl;
1432
1479
  assert(property.minimumSamplingInterval === this.minimumSamplingInterval);
1433
1480
  }
1481
+ return property;
1482
+ };
1434
1483
 
1435
- property._dataValue.statusCode = StatusCodes.Good;
1436
- property.touchValue();
1437
-
1484
+ for (const field of definition.fields || []) {
1485
+
1438
1486
  if (NodeId.sameNodeId(NodeId.nullNodeId, field.dataType)) {
1439
- debugLog("field.dataType is null ! " + field.name + " " + field.description?.text);
1440
- debugLog(" dataType replaced with BaseDataType ");
1487
+ warningLog("field.dataType is null ! ", field.toString(), NodeId.nullNodeId.toString());
1488
+ warningLog(" dataType replaced with BaseDataType ");
1489
+ warningLog(definition.toString());
1441
1490
  field.dataType = this.resolveNodeId("BaseDataType");
1442
1491
  }
1443
- const dataTypeNodeId = addressSpace.findCorrespondingBasicDataType(field.dataType);
1492
+
1493
+ const camelCaseName = lowerFirstLetter(field.name!);
1444
1494
  assert(Object.prototype.hasOwnProperty.call(this.$extensionObject, camelCaseName));
1445
1495
 
1496
+ const propertyNode = getOrCreateProperty(field);
1497
+
1498
+ propertyNode.$dataValue.statusCode = StatusCodes.Good;
1499
+ propertyNode.touchValue();
1500
+
1501
+ const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
1502
+
1446
1503
  // istanbul ignore next
1447
1504
  if (doDebug) {
1448
1505
  const x = addressSpace.findNode(field.dataType)!.browseName.toString();
1449
- const basicType = addressSpace.findCorrespondingBasicDataType(field.dataType);
1450
1506
  debugLog(
1451
1507
  chalk.cyan("xxx"),
1452
1508
  " dataType",
@@ -1456,52 +1512,56 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1456
1512
  chalk.cyan(w(valueRankToString(field.valueRank), 10)),
1457
1513
  chalk.green(w(x, 25)),
1458
1514
  "basicType = ",
1459
- chalk.yellow(w(basicType.toString(), 20)),
1460
- property.nodeId.toString(),
1461
- property.readValue().statusCode.toString()
1515
+ chalk.yellow(w(basicDataType.toString(), 20)),
1516
+ propertyNode.nodeId.toString(),
1517
+ propertyNode.readValue().statusCode.toString()
1462
1518
  );
1463
1519
  }
1464
- if (this.$extensionObject[camelCaseName] !== undefined && dataTypeNodeId === DataType.ExtensionObject) {
1520
+ if (this.$extensionObject[camelCaseName] !== undefined && basicDataType === DataType.ExtensionObject) {
1465
1521
  assert(this.$extensionObject[camelCaseName] instanceof Object);
1466
- this.$extensionObject[camelCaseName] = new Proxy(this.$extensionObject[camelCaseName], makeHandler(property));
1467
- property._dataValue.value = new Variant({
1468
- dataType: DataType.ExtensionObject,
1469
- value: this.$extensionObject[camelCaseName]
1470
- });
1471
- property.bindExtensionObject();
1472
- property.$extensionObject = this.$extensionObject[camelCaseName];
1522
+ this.$extensionObject[camelCaseName] = new Proxy(this.$extensionObject[camelCaseName], makeHandler(propertyNode));
1523
+
1524
+ propertyNode._internal_set_value(
1525
+ new Variant({
1526
+ dataType: DataType.ExtensionObject,
1527
+ value: this.$extensionObject[camelCaseName]
1528
+ })
1529
+ );
1530
+
1531
+ propertyNode.bindExtensionObject();
1532
+ propertyNode.$extensionObject = this.$extensionObject[camelCaseName];
1473
1533
  } else {
1474
- const dataTypeAsString = DataType[dataTypeNodeId];
1475
- assert(typeof dataTypeAsString === "string");
1476
1534
  const prop = this.$extensionObject[camelCaseName];
1477
-
1478
1535
  if (prop === undefined) {
1479
- property._dataValue.value = new Variant({
1480
- dataType: DataType.Null
1481
- });
1536
+ propertyNode._internal_set_value(
1537
+ new Variant({
1538
+ dataType: DataType.Null
1539
+ })
1540
+ );
1482
1541
  } else {
1483
- const preparedValue = prepareVariantValue(dataTypeNodeId, prop);
1484
- property._dataValue.value = new Variant({
1485
- dataType: dataTypeAsString,
1486
- value: preparedValue
1487
- });
1542
+ const preparedValue = prepareVariantValue(basicDataType, prop);
1543
+ propertyNode._internal_set_value(
1544
+ new Variant({
1545
+ dataType: basicDataType,
1546
+ value: preparedValue
1547
+ })
1548
+ );
1488
1549
  }
1489
1550
 
1490
1551
  // eslint-disable-next-line @typescript-eslint/no-this-alias
1491
1552
  const self = this;
1492
- property.camelCaseName = camelCaseName;
1493
- property.setValueFromSource = function (this: any, variant: VariantLike) {
1553
+ // property.camelCaseName = camelCaseName;
1554
+ propertyNode.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
1494
1555
  // eslint-disable-next-line @typescript-eslint/no-this-alias
1495
1556
  const inner_this = this;
1496
- variant = Variant.coerce(variant);
1497
- // xx console.log("PropertySetValueFromSource this", inner_this.nodeId.toString(), inner_this.browseName.toString(), variant.toString(), inner_this.dataType.toString());
1498
- // xx assert(variant.dataType === this.dataType);
1499
- self.$extensionObject[inner_this.camelCaseName] = variant.value;
1557
+ const variant1 = Variant.coerce(variant);
1558
+ inner_this.verifyVariantCompatibility(variant1);
1559
+ self.$extensionObject[camelCaseName] = variant1.value;
1500
1560
  self.touchValue();
1501
1561
  };
1502
1562
  }
1503
- assert(property.readValue().statusCode.equals(StatusCodes.Good));
1504
- bindProperty(property, camelCaseName, this.$extensionObject, dataTypeNodeId);
1563
+ assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
1564
+ bindProperty(propertyNode, camelCaseName, this.$extensionObject, basicDataType);
1505
1565
  }
1506
1566
  assert(this.$extensionObject instanceof Object);
1507
1567
  return this.$extensionObject;
@@ -1543,7 +1603,6 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1543
1603
  c1[name] = c2[name];
1544
1604
  c1[name] += 1;
1545
1605
 
1546
- // xx console.log(partialData);
1547
1606
  setExtensionObjectValue(this, partialData);
1548
1607
  }
1549
1608
 
@@ -1687,10 +1746,16 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1687
1746
  return validateDataType(this.addressSpace, this.dataType, variantDataType, this.nodeId, /* allow Nulls */ false);
1688
1747
  }
1689
1748
 
1749
+ public _internal_set_value(value: Variant): void {
1750
+ if (value.dataType !== DataType.Null) {
1751
+ this.verifyVariantCompatibility(value);
1752
+ }
1753
+ this.$dataValue.value = value;
1754
+ }
1690
1755
  public _internal_set_dataValue(dataValue: DataValue, indexRange?: NumericRange | null): void {
1691
1756
  assert(dataValue, "expecting a dataValue");
1692
1757
  assert(dataValue instanceof DataValue, "expecting dataValue to be a DataValue");
1693
- assert(dataValue !== this._dataValue, "expecting dataValue to be different from previous DataValue instance");
1758
+ assert(dataValue !== this.$dataValue, "expecting dataValue to be different from previous DataValue instance");
1694
1759
 
1695
1760
  if (dataValue.value.arrayType === VariantArrayType.Matrix) {
1696
1761
  if (!dataValue.value.dimensions) {
@@ -1714,27 +1779,31 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1714
1779
  // istanbul ignore next
1715
1780
  if (this.dataType.namespace === 0) {
1716
1781
  if (this.dataType.value === DataType.LocalizedText && dataValue.value.dataType !== DataType.LocalizedText) {
1717
- throw new Error("Invalid dataValue provided (expecting a LocalizedText) but got " + dataValue.toString());
1782
+ const message = "Invalid dataValue provided (expecting a LocalizedText) but got " + dataValue.toString();
1783
+ errorLog(message);
1784
+ throw new Error(message);
1718
1785
  }
1719
1786
  }
1720
1787
 
1721
- const old_dataValue = this._dataValue;
1788
+ this.verifyVariantCompatibility(dataValue.value);
1722
1789
 
1723
- this._dataValue = dataValue;
1724
- this._dataValue.statusCode = this._dataValue.statusCode || StatusCodes.Good;
1790
+ const old_dataValue = this.$dataValue;
1791
+
1792
+ this.$dataValue = dataValue;
1793
+ this.$dataValue.statusCode = this.$dataValue.statusCode || StatusCodes.Good;
1725
1794
 
1726
1795
  // repair missing timestamps
1727
1796
  if (!dataValue.serverTimestamp) {
1728
- this._dataValue.serverTimestamp = old_dataValue.serverTimestamp;
1729
- this._dataValue.serverPicoseconds = old_dataValue.serverPicoseconds;
1797
+ this.$dataValue.serverTimestamp = old_dataValue.serverTimestamp;
1798
+ this.$dataValue.serverPicoseconds = old_dataValue.serverPicoseconds;
1730
1799
  }
1731
1800
  if (!dataValue.sourceTimestamp) {
1732
- this._dataValue.sourceTimestamp = old_dataValue.sourceTimestamp;
1733
- this._dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds;
1801
+ this.$dataValue.sourceTimestamp = old_dataValue.sourceTimestamp;
1802
+ this.$dataValue.sourcePicoseconds = old_dataValue.sourcePicoseconds;
1734
1803
  }
1735
1804
 
1736
1805
  if (!sameDataValue(old_dataValue, dataValue)) {
1737
- this.emit("value_changed", this._dataValue, indexRange);
1806
+ this.emit("value_changed", this.$dataValue, indexRange);
1738
1807
  }
1739
1808
  }
1740
1809
 
@@ -1930,10 +1999,10 @@ function _calculateEffectiveUserAccessLevelFromPermission(
1930
1999
  }
1931
2000
  }
1932
2001
 
1933
- function adjustVariant2(this: UAVariable, variant: Variant): Variant {
2002
+ function adjustVariant2(this: UAVariableImpl, variant: Variant): Variant {
1934
2003
  // convert Variant( Scalar|ByteString) => Variant(Array|ByteArray)
1935
2004
  const addressSpace = this.addressSpace;
1936
- const basicType = addressSpace.findCorrespondingBasicDataType(this.dataType);
2005
+ const basicType = this.getBasicDataType();
1937
2006
  variant = adjustVariant(variant, this.valueRank, basicType);
1938
2007
  return variant;
1939
2008
  }
@@ -1992,7 +2061,7 @@ function _Variable_bind_with_async_refresh(this: UAVariableImpl, options: any) {
1992
2061
  this.refreshFunc = options.refreshFunc;
1993
2062
 
1994
2063
  // assert(this.readValue().statusCode === StatusCodes.BadNodeIdUnknown);
1995
- this._dataValue.statusCode = StatusCodes.UncertainInitialValue;
2064
+ this.$dataValue.statusCode = StatusCodes.UncertainInitialValue;
1996
2065
 
1997
2066
  // TO DO : REVISIT THIS ASSUMPTION
1998
2067
  if (false && this.minimumSamplingInterval === 0) {
@@ -2014,7 +2083,10 @@ function _Variable_bind_with_timestamped_get(this: UAVariableImpl, options: any)
2014
2083
  const async_refresh_func = (callback: (err: Error | null, dataValue?: DataValue) => void) => {
2015
2084
  Promise.resolve((this._timestamped_get_func! as TimestampGetFunction1).call(this))
2016
2085
  .then((dataValue) => callback(null, dataValue))
2017
- .catch((err) => callback(err as Error));
2086
+ .catch((err) => {
2087
+ errorLog("asyncRefresh error: Variable is ", this.nodeId.toString(), this.browseName.toString());
2088
+ callback(err as Error);
2089
+ });
2018
2090
  };
2019
2091
 
2020
2092
  if (options.timestamped_get.length === 0) {
@@ -2045,11 +2117,11 @@ function _Variable_bind_with_timestamped_get(this: UAVariableImpl, options: any)
2045
2117
  }
2046
2118
 
2047
2119
  // variation 1
2048
- function _Variable_bind_with_simple_get(this: UAVariableImpl, options: any) {
2120
+ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: GetterOptions) {
2049
2121
  /* jshint validthis: true */
2050
2122
  assert(this instanceof UAVariableImpl);
2051
2123
  assert(typeof options.get === "function", "should specify get function");
2052
- assert(options.get.length === 0, "get function should not have arguments");
2124
+ assert(options.get!.length === 0, "get function should not have arguments");
2053
2125
  assert(!options.timestamped_get, "should not specify a timestamped_get function when get is specified");
2054
2126
  assert(!this._timestamped_get_func);
2055
2127
  assert(!this._get_func);
@@ -2073,12 +2145,10 @@ function _Variable_bind_with_simple_get(this: UAVariableImpl, options: any) {
2073
2145
  if (is_StatusCode(value)) {
2074
2146
  return new DataValue({ statusCode: value });
2075
2147
  } else {
2076
- if (!this._dataValue || !isGoodish(this._dataValue.statusCode) || !sameVariant(this._dataValue.value, value)) {
2148
+ if (!this.$dataValue || !isGoodish(this.$dataValue.statusCode) || !sameVariant(this.$dataValue.value, value)) {
2077
2149
  this.setValueFromSource(value, StatusCodes.Good);
2078
- } else {
2079
- // XX console.log("YYYYYYYYYYYYYYYYYYYYYYYYYY",this.browseName.toString());
2080
- }
2081
- return this._dataValue;
2150
+ }
2151
+ return this.$dataValue;
2082
2152
  }
2083
2153
  };
2084
2154
 
@@ -2105,11 +2175,13 @@ function _Variable_bind_with_simple_set(this: UAVariableImpl, options: any) {
2105
2175
  ) => {
2106
2176
  assert(timestamped_value instanceof DataValue);
2107
2177
  this._set_func(timestamped_value.value, (err: Error | null, statusCode: StatusCode) => {
2178
+
2179
+ // istanbul ignore next
2108
2180
  if (!err && !statusCode) {
2109
- console.log(
2181
+ errorLog(
2110
2182
  chalk.red("UAVariable Binding Error _set_func must return a StatusCode, check the bindVariable parameters")
2111
2183
  );
2112
- console.log(chalk.yellow("StatusCode.Good is assumed"));
2184
+ errorLog(chalk.yellow("StatusCode.Good is assumed"));
2113
2185
  return callback(err, StatusCodes.Good, timestamped_value);
2114
2186
  }
2115
2187
  callback(err, statusCode, timestamped_value);