node-opcua-address-space 2.115.0 → 2.117.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 (35) hide show
  1. package/dist/source/helpers/call_helpers.d.ts +1 -2
  2. package/dist/source/helpers/call_helpers.js +15 -0
  3. package/dist/source/helpers/call_helpers.js.map +1 -1
  4. package/dist/source/index.d.ts +1 -0
  5. package/dist/source/index.js +3 -1
  6. package/dist/source/index.js.map +1 -1
  7. package/dist/source/loader/generateAddressSpaceRaw.d.ts +19 -1
  8. package/dist/source/loader/generateAddressSpaceRaw.js +157 -4
  9. package/dist/source/loader/generateAddressSpaceRaw.js.map +1 -1
  10. package/dist/source/loader/load_nodeset2.js +3 -10
  11. package/dist/source/loader/load_nodeset2.js.map +1 -1
  12. package/dist/src/index_current.d.ts +1 -0
  13. package/dist/src/index_current.js +1 -0
  14. package/dist/src/index_current.js.map +1 -1
  15. package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +27 -3
  16. package/dist/src/nodeset_tools/construct_namespace_dependency.js +210 -81
  17. package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
  18. package/dist/src/nodeset_tools/nodeset_to_xml.js +15 -23
  19. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  20. package/dist/src/ua_variable_impl.js +2 -74
  21. package/dist/src/ua_variable_impl.js.map +1 -1
  22. package/dist/src/validate_data_type_correctness.d.ts +6 -0
  23. package/dist/src/validate_data_type_correctness.js +98 -0
  24. package/dist/src/validate_data_type_correctness.js.map +1 -0
  25. package/dist/tsconfig_common.tsbuildinfo +1 -1
  26. package/package.json +38 -38
  27. package/source/helpers/call_helpers.ts +1 -1
  28. package/source/index.ts +1 -1
  29. package/source/loader/generateAddressSpaceRaw.ts +180 -5
  30. package/source/loader/load_nodeset2.ts +3 -9
  31. package/src/index_current.ts +1 -1
  32. package/src/nodeset_tools/construct_namespace_dependency.ts +232 -91
  33. package/src/nodeset_tools/nodeset_to_xml.ts +19 -27
  34. package/src/ua_variable_impl.ts +2 -89
  35. package/src/validate_data_type_correctness.ts +115 -0
@@ -1,4 +1,4 @@
1
- import { INamespace, UADataType, UAVariable, UAVariableType } from "node-opcua-address-space-base";
1
+ import { IAddressSpace, INamespace, UADataType, UAVariable, UAVariableType } from "node-opcua-address-space-base";
2
2
  import { NodeClass } from "node-opcua-data-model";
3
3
  import { StructureField } from "node-opcua-types";
4
4
  import { DataType } from "node-opcua-basic-types";
@@ -9,42 +9,46 @@ import { make_debugLog, make_warningLog } from "node-opcua-debug";
9
9
  import { NamespacePrivate } from "../namespace_private";
10
10
  import { BaseNodeImpl, getReferenceType } from "../base_node_impl";
11
11
  import { UAVariableImpl } from "../ua_variable_impl";
12
+ import { ITranslationTable } from "../../source/xml_writer";
12
13
 
13
14
  const warningLog = make_warningLog(__filename);
14
15
  const debugLog = make_debugLog(__filename);
15
16
 
16
- function _constructNamespaceDependency(
17
+ // eslint-disable-next-line max-statements, complexity
18
+ export function _recomputeRequiredModelsFromTypes(
17
19
  namespace: INamespace,
18
- dependency: INamespace[],
19
- depMap: Set<number>,
20
- _visitedDataType: Set<string>,
21
- priorityTable: number[]
22
- ): void {
23
- const addressSpace = namespace.addressSpace;
24
- const namespace_ = namespace as NamespacePrivate;
25
- // navigate all namespace recursively to
26
-
27
- function consider(namespaceIndex: number) {
28
- if (hasHigherPriorityThan(namespaceIndex, namespace.index, priorityTable)) {
29
- return;
30
- }
31
- considerStrongly(namespaceIndex);
20
+ cache?: Map<number, { requiredNamespaceIndexes: number[]; nbTypes: number }>
21
+ ): { requiredNamespaceIndexes: number[]; nbTypes: number } {
22
+ if (namespace.index === 0) {
23
+ return { requiredNamespaceIndexes: [], nbTypes: 1 };
32
24
  }
33
- function considerStrongly(namespaceIndex: number) {
34
- if (!depMap.has(namespaceIndex)) {
35
- depMap.add(namespaceIndex);
36
- const namespace = addressSpace.getNamespace(namespaceIndex);
37
- dependency.push(namespace);
38
- if (namespaceIndex > 0) {
39
- _constructNamespaceDependency(namespace, dependency, depMap, _visitedDataType, priorityTable);
40
- }
25
+ if (cache) {
26
+ if (cache.has(namespace.index)) {
27
+ return cache.get(namespace.index)!;
41
28
  }
42
29
  }
30
+ const requiredNamespaceIndexes = [0];
31
+ const requiredModelsSet = new Set<number>();
32
+ requiredModelsSet.add(0);
33
+ const namespace_ = namespace as NamespacePrivate;
34
+ let nbTypes = 0;
35
+ const addressSpace = namespace.addressSpace;
36
+ const types = [NodeClass.VariableType, NodeClass.ObjectType, NodeClass.ReferenceType, NodeClass.DataType];
37
+ const instances = [NodeClass.Variable, NodeClass.Object, NodeClass.Method];
38
+
39
+ const consider = (requiredModel: number) => {
40
+ if (requiredModel !== namespace.index && !requiredModelsSet.has(requiredModel)) {
41
+ requiredModelsSet.add(requiredModel);
42
+ requiredNamespaceIndexes.push(requiredModel);
43
+ }
44
+ };
45
+
46
+ const _visitedDataType: Set<string> = new Set<string>();
43
47
 
44
48
  function exploreDataTypeField(field: StructureField) {
45
49
  const dataType = field.dataType;
46
50
  const namespaceIndex = dataType.namespace;
47
- considerStrongly(namespaceIndex);
51
+ consider(namespaceIndex);
48
52
  const dataTypeNode = addressSpace.findDataType(field.dataType);
49
53
  if (dataTypeNode) {
50
54
  exploreDataTypes(dataTypeNode);
@@ -65,7 +69,7 @@ function _constructNamespaceDependency(
65
69
  }
66
70
 
67
71
  const namespaceIndex = dataType.namespace;
68
- considerStrongly(namespaceIndex);
72
+ consider(namespaceIndex);
69
73
  if (dataTypeNode.isStructure()) {
70
74
  const definition = dataTypeNode.getStructureDefinition();
71
75
  for (const field of definition.fields || []) {
@@ -78,7 +82,7 @@ function _constructNamespaceDependency(
78
82
  function exploreExtensionObject(e: ExtensionObject) {
79
83
  assert(!(e instanceof Variant));
80
84
  const nodeId = e.schema.encodingDefaultXml || e.schema.dataTypeNodeId || e.schema.dataTypeNodeId;
81
- considerStrongly(nodeId.namespace);
85
+ consider(nodeId.namespace);
82
86
  // istanbul ignore next
83
87
  if (e.schema.dataTypeNodeId.isEmpty()) {
84
88
  warningLog("Cannot find dataTypeNodeId for ", e.schema.name);
@@ -88,6 +92,7 @@ function _constructNamespaceDependency(
88
92
  if (!d) return;
89
93
  exploreDataTypes(d);
90
94
  }
95
+
91
96
  function exploreDataValue(uaVariable: UAVariableImpl) {
92
97
  if (uaVariable.getBasicDataType() !== DataType.ExtensionObject) {
93
98
  return;
@@ -104,36 +109,131 @@ function _constructNamespaceDependency(
104
109
  }
105
110
  }
106
111
  for (const node of namespace_.nodeIterator()) {
107
- if (node.nodeClass === NodeClass.Variable || node.nodeClass === NodeClass.VariableType) {
108
- const dataTypeNodeId = (node as UAVariable | UAVariableType).dataType;
109
- const dataTypeNode = addressSpace.findDataType(dataTypeNodeId)!;
110
- if (dataTypeNode) {
111
- exploreDataTypes(dataTypeNode);
112
- } else {
113
- // istanbul ignore next
114
- if (dataTypeNodeId.value != 0) {
115
- warningLog("Warning: Cannot find dataType", dataTypeNodeId.toString());
112
+ const isType = types.indexOf(node.nodeClass);
113
+ const isInstance = instances.indexOf(node.nodeClass);
114
+ if (isType !== -1) {
115
+ nbTypes++;
116
+ const superTypes = node.findReferencesAsObject("HasSubtype", false);
117
+ if (superTypes.length === 0) {
118
+ continue;
119
+ }
120
+ if (superTypes.length !== 1) {
121
+ continue;
122
+ }
123
+ const superType = superTypes[0];
124
+ if (superType.nodeId.namespace === 0) {
125
+ continue;
126
+ }
127
+ const requiredModel = superType.nodeId.namespace;
128
+ consider(requiredModel);
129
+ } else if (isInstance !== -1) {
130
+ if (node.nodeClass === NodeClass.Variable || node.nodeClass === NodeClass.VariableType) {
131
+ const dataTypeNodeId = (node as UAVariable | UAVariableType).dataType;
132
+ const dataTypeNode = addressSpace.findDataType(dataTypeNodeId)!;
133
+ if (dataTypeNode) {
134
+ consider(dataTypeNode.nodeId.namespace);
135
+ } else {
136
+ // istanbul ignore next
137
+ if (dataTypeNodeId.value != 0) {
138
+ warningLog("Warning: Cannot find dataType", dataTypeNodeId.toString());
139
+ }
116
140
  }
141
+ const nodeV = node as UAVariableImpl;
142
+ exploreDataValue(nodeV);
117
143
  }
118
- const nodeV = node as UAVariableImpl;
119
- exploreDataValue(nodeV);
144
+
145
+ const typeDefinitions = node.findReferencesAsObject("HasTypeDefinition", true);
146
+ if (typeDefinitions.length === 0) {
147
+ continue;
148
+ }
149
+ if (typeDefinitions.length !== 1) {
150
+ continue;
151
+ }
152
+ const typeDefinition = typeDefinitions[0];
153
+ const requiredModel = typeDefinition.nodeId.namespace;
154
+ consider(requiredModel);
120
155
  }
121
- // visit all references
122
- const references = (<BaseNodeImpl>node).ownReferences();
123
- for (const reference of references) {
124
- // check referenceId
125
- const namespaceIndex = getReferenceType(reference)!.nodeId.namespace;
126
- consider(namespaceIndex);
127
- const namespaceIndex2 = reference.nodeId.namespace;
128
- consider(namespaceIndex2);
156
+ }
157
+
158
+ const result = { requiredNamespaceIndexes: requiredNamespaceIndexes, nbTypes: nbTypes };
159
+ if (cache) {
160
+ cache.set(namespace.index, result);
161
+ }
162
+ return result;
163
+ }
164
+
165
+ export function _recomputeRequiredModelsFromTypes2(
166
+ namespace: INamespace,
167
+ cache?: Map<number, { requiredNamespaceIndexes: number[]; nbTypes: number }>
168
+ ): { requiredNamespaceIndexes: number[] } {
169
+ const addressSpace = namespace.addressSpace;
170
+
171
+ const { requiredNamespaceIndexes } = _recomputeRequiredModelsFromTypes(namespace, cache);
172
+
173
+ const set = new Set<number>(requiredNamespaceIndexes);
174
+ const pass2: number[] = [];
175
+ for (const r of requiredNamespaceIndexes) {
176
+ if (r === 0) {
177
+ pass2.push(0);
178
+ continue;
179
+ }
180
+ const namespaces = _recomputeRequiredModelsFromTypes(addressSpace.getNamespace(r), cache);
181
+ for (const nIndex of namespaces.requiredNamespaceIndexes) {
182
+ if (!set.has(nIndex)) {
183
+ set.add(nIndex);
184
+ pass2.push(nIndex);
185
+ }
129
186
  }
187
+ pass2.push(r);
130
188
  }
189
+
190
+ return { requiredNamespaceIndexes: pass2 };
131
191
  }
132
192
 
133
- export function hasHigherPriorityThan(namespaceIndex1: number, namespaceIndex2: number, priorityTable: number[]) {
134
- const order1 = priorityTable[namespaceIndex1];
135
- const order2 = priorityTable[namespaceIndex2];
136
- return order1 > order2;
193
+ export function _getCompleteRequiredModelsFromValuesAndReferences(
194
+ namespace: INamespace,
195
+ priorityList: number[],
196
+ cache?: Map<number, { requiredNamespaceIndexes: number[]; nbTypes: number }>
197
+ ): number[] {
198
+
199
+ const namespace_ = namespace as NamespacePrivate;
200
+
201
+ const thisPriority = priorityList[namespace.index];
202
+
203
+ const requiredNamespaceIndexes = _recomputeRequiredModelsFromTypes2(namespace, cache).requiredNamespaceIndexes;
204
+ const requiredModelsSet: Set<number> = new Set<number>([... requiredNamespaceIndexes]);
205
+
206
+ const consider = (requiredModel: number) => {
207
+ if (requiredModel !== namespace.index && !requiredModelsSet.has(requiredModel)) {
208
+ requiredModelsSet.add(requiredModel);
209
+ requiredNamespaceIndexes.push(requiredModel);
210
+ }
211
+ }
212
+
213
+ //const maxIndex = Math.max(...requiredNamespaceIndexes);
214
+ for (const node of namespace_.nodeIterator()) {
215
+ const references = (<BaseNodeImpl>node).allReferences();
216
+ for (const reference of references) {
217
+ // if (reference.isForward) continue;
218
+ // only look at backward reference
219
+ // check referenceId
220
+ const namespaceIndexOfReferenceType = getReferenceType(reference)!.nodeId.namespace;
221
+ if (namespaceIndexOfReferenceType !== 0 && namespaceIndexOfReferenceType !== namespace.index) {
222
+ const refPriority = priorityList[namespaceIndexOfReferenceType];
223
+ if (refPriority <= thisPriority) {
224
+ consider(namespaceIndexOfReferenceType);
225
+ }
226
+ }
227
+ const namespaceIndexOfTargetNode = reference.nodeId.namespace;
228
+ if (namespaceIndexOfTargetNode !== 0 && namespaceIndexOfTargetNode !== namespace.index) {
229
+ const refPriority = priorityList[namespaceIndexOfTargetNode];
230
+ if (refPriority <= thisPriority) {
231
+ consider(namespaceIndexOfTargetNode);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ return requiredNamespaceIndexes;
137
237
  }
138
238
 
139
239
  /**
@@ -150,58 +250,99 @@ export function hasHigherPriorityThan(namespaceIndex1: number, namespaceIndex2:
150
250
  * ---
151
251
  * ua, own , di , kitchen , own2, adi => 0 , 2, 3, 5, 1
152
252
  */
153
- export function constructNamespacePriorityTable(namespace: INamespace): number[] {
154
- // Namespace 0 will always be 0
155
- // Namespaces with no requiredModel will be considered as instance namespaces and will added at the end
156
- // in the same order as they appear,
157
- // Namespace with requiredModels are considered to be companion specification, so already loaded in the correct order
158
-
159
- const addressSpace = namespace.addressSpace;
253
+ export function constructNamespacePriorityTable(addressSpace: IAddressSpace): { loadingOrder: number[]; priorityTable: number[] } {
254
+ // - Namespace 0 will always be 0
255
+ // - Namespace with requiredModels are considered to be companion specification,
256
+ // so RequireModel will be used to determine the order
257
+ // - Namespaces with no requiredModel are more complicated:
258
+ //
259
+ // we study ObjectType,ReferenceType, DataType and VariableType
260
+ // to find strong dependencies between namespace.
261
+ //
262
+ // if the namespace doesn't define ObjectType,ReferenceType, DataType and VariableType
263
+ // it will be considered as instance namespaces and will added at the end
264
+ // in the same order as they appear,
160
265
  const namespaces = addressSpace.getNamespaceArray();
161
266
 
162
- const namespaceWithReq = namespaces.filter((n) => n.getRequiredModels() !== undefined && n.index !== 0);
163
- const namespaceWithoutReq = namespaces.filter((n) => n.getRequiredModels() === undefined && n.index !== 0);
267
+ const loadingOrder: number[] = [0];
164
268
 
165
- const priorityList: number[] = [0];
166
- let counter = 1;
167
- for (let i = 0; i < namespaceWithReq.length; i++) {
168
- priorityList[namespaceWithReq[i].index] = counter++;
169
- }
170
- for (let i = 0; i < namespaceWithoutReq.length; i++) {
171
- priorityList[namespaceWithoutReq[i].index] = counter++;
269
+ const map = new Map<number, { nbTypes: number; requiredNamespaceIndexes: number[]; namespace: INamespace }>();
270
+ for (let i = 0; i < namespaces.length; i++) {
271
+ const { nbTypes, requiredNamespaceIndexes } = _recomputeRequiredModelsFromTypes(namespaces[i], map);
272
+ map.set(namespaces[i].index, { nbTypes, requiredNamespaceIndexes, namespace: namespaces[i] });
172
273
  }
173
- return priorityList;
174
- }
175
- const doDebug = false;
176
- export function constructNamespaceDependency(namespace: INamespace, priorityTable?: number[]): INamespace[] {
177
- const addressSpace = namespace.addressSpace;
178
274
 
179
- priorityTable = priorityTable || constructNamespacePriorityTable(namespace);
275
+ const visited = new Set<number>();
276
+ visited.add(0);
180
277
 
181
- const dependency: INamespace[] = [];
182
- const depMap = new Set<number>();
278
+ const h = (n: INamespace) => {
279
+ if (visited.has(n.index)) {
280
+ return;
281
+ }
282
+ visited.add(n.index);
283
+ const data = map.get(n.index);
284
+ if (!data) return;
285
+ const { requiredNamespaceIndexes } = data;
286
+ for (const r of requiredNamespaceIndexes || []) {
287
+ h(namespaces[r]);
288
+ }
289
+ loadingOrder.push(n.index);
290
+ };
183
291
 
184
- dependency.push(addressSpace.getDefaultNamespace());
185
- depMap.add(0);
292
+ for (let i = 0; i < namespaces.length; i++) {
293
+ const { nbTypes } = map.get(i)!;
294
+ if (nbTypes) {
295
+ h(namespaces[i]);
296
+ }
297
+ }
298
+ for (let i = 0; i < namespaces.length; i++) {
299
+ const { nbTypes } = map.get(i)!;
300
+ if (!nbTypes) {
301
+ h(namespaces[i]);
302
+ }
303
+ }
186
304
 
187
- if (namespace !== addressSpace.getDefaultNamespace()) {
188
- dependency.push(namespace);
189
- depMap.add(namespace.index);
305
+ const priorityTable: number[] = [];
306
+ for (let i = 0; i < loadingOrder.length; i++) {
307
+ const namespaceIndex = loadingOrder[i];
308
+ assert(namespaceIndex !== -1);
309
+ priorityTable[namespaceIndex] = i;
190
310
  }
191
- const _visitedDataType = new Set<string>();
192
311
 
193
- _constructNamespaceDependency(namespace, dependency, depMap, _visitedDataType, priorityTable);
312
+ return { loadingOrder, priorityTable };
313
+ }
194
314
 
195
- // istanbul ignore next
196
- doDebug && debugLog("namespace : ", namespace.index, namespace.namespaceUri);
197
- // istanbul ignore next
198
- doDebug && debugLog(" ", dependency.map((d) => d.index + " " + d.namespaceUri).join("\n "));
315
+ const doDebug = true;
316
+ export function constructNamespaceDependency(namespace: INamespace, priorityTable?: number[]): INamespace[] {
317
+ const addressSpace = namespace.addressSpace;
318
+ priorityTable = priorityTable || constructNamespacePriorityTable(addressSpace).priorityTable;
319
+ const requiredNamespaceIndexes = _getCompleteRequiredModelsFromValuesAndReferences(namespace, priorityTable);
320
+ return [...requiredNamespaceIndexes.map((r) => addressSpace.getNamespace(r)), namespace];
321
+ }
199
322
 
200
- const sorted = dependency.sort((a, b) => (priorityTable![a.index] < priorityTable![b.index] ? -1 : 1));
201
- // istanbul ignore next
202
- doDebug && debugLog("sorted:");
203
- // istanbul ignore next
204
- doDebug && debugLog(" ", sorted.map((d) => d.index + " " + d.namespaceUri).join("\n "));
323
+ /**
324
+ * @private
325
+ */
326
+ export function _constructNamespaceTranslationTable(dependency: INamespace[], exportedNamespace: INamespace): ITranslationTable {
327
+ if (!dependency || dependency.length === 0) {
328
+ return { 0: 0 };
329
+ // throw new Error("Cannot constructNamespaceTranslationTable on empty dependency");
330
+ }
331
+ const translationTable: ITranslationTable = {};
332
+ assert(dependency[0].namespaceUri === "http://opcfoundation.org/UA/");
205
333
 
206
- return sorted;
334
+ let counter = 0;
335
+ translationTable[dependency[0].index] = counter++;
336
+ //
337
+ if (exportedNamespace) {
338
+ translationTable[exportedNamespace.index] = counter++;
339
+ }
340
+ for (let i = 1; i < dependency.length; i++) {
341
+ const dep = dependency[i];
342
+ if (exportedNamespace && exportedNamespace === dep) {
343
+ continue;
344
+ }
345
+ translationTable[dep.index] = counter++;
346
+ }
347
+ return translationTable;
207
348
  }
@@ -53,9 +53,9 @@ import { UAViewImpl } from "../ua_view_impl";
53
53
  import { DefinitionMap2, TypeInfo } from "../../source/loader/make_xml_extension_object_parser";
54
54
  import { makeDefinitionMap } from "../../source/loader/decode_xml_extension_object";
55
55
  import {
56
+ _constructNamespaceTranslationTable,
56
57
  constructNamespaceDependency,
57
- constructNamespacePriorityTable,
58
- hasHigherPriorityThan
58
+ constructNamespacePriorityTable
59
59
  } from "./construct_namespace_dependency";
60
60
 
61
61
  // tslint:disable:no-var-requires
@@ -105,6 +105,13 @@ function b(xw: XmlWriter, browseName: QualifiedName): string {
105
105
  return translateBrowseName(xw, browseName).toString().replace("ns=0;", "");
106
106
  }
107
107
 
108
+
109
+ function hasHigherPriorityThan(namespaceIndex1: number, namespaceIndex2: number, priorityTable: number[]) {
110
+ const order1 = priorityTable[namespaceIndex1];
111
+ const order2 = priorityTable[namespaceIndex2];
112
+ return order1 > order2;
113
+ }
114
+
108
115
  function _hasHigherPriorityThan(xw: XmlWriter, namespaceIndex1: number, namespaceIndex2: number) {
109
116
  assert(xw.priorityTable, "expecting a priorityTable");
110
117
  assert(namespaceIndex1 < xw.priorityTable.length);
@@ -128,7 +135,6 @@ function _dumpReferences(xw: XmlWriter, node: BaseNode) {
128
135
 
129
136
  function referenceToKeep(reference: UAReference): boolean {
130
137
  const referenceType = (reference as ReferenceImpl)._referenceType!;
131
-
132
138
  const targetedNamespaceIndex = reference.nodeId.namespace;
133
139
  if (_hasHigherPriorityThan(xw, targetedNamespaceIndex, node.nodeId.namespace)) {
134
140
  // this reference has nothing to do here ! drop it
@@ -165,8 +171,8 @@ function _dumpReferences(xw: XmlWriter, node: BaseNode) {
165
171
  }
166
172
  return false;
167
173
  }
168
-
169
- const references = node.allReferences().filter(referenceToKeep);
174
+ const allReferences = node.allReferences();
175
+ const references = allReferences.filter(referenceToKeep);
170
176
 
171
177
  for (const reference of references.sort(sortByNodeId)) {
172
178
  if (getReferenceType(reference).browseName.toString() === "HasSubtype" && reference.isForward) {
@@ -535,6 +541,10 @@ function _dumpVariantExtensionObjectValue2(xw: XmlWriter, addressSpace: IAddress
535
541
  const dataTypeNodeId = value.schema.dataTypeNodeId;
536
542
  const definitionMap = makeDefinitionMap(addressSpace);
537
543
  const dataTypeNode = addressSpace.findDataType(dataTypeNodeId)!;
544
+ if (!dataTypeNode) {
545
+ warningLog("_dumpVariantExtensionObjectValue2: Cannot find dataType for ", dataTypeNodeId.toString());
546
+ return;
547
+ }
538
548
  _dumpVariantExtensionObjectValue(xw, dataTypeNode.nodeId, definitionMap, value);
539
549
  }
540
550
 
@@ -1155,7 +1165,7 @@ function dumpUAObjectType(xw: XmlWriter, node: UAObjectTypeImpl) {
1155
1165
  xw.writeComment("ObjectType - " + b(xw, node.browseName) + " {{{{ ");
1156
1166
  _markAsVisited(xw, node);
1157
1167
 
1158
- // dump SubtypeOf and HasTypeDefinition
1168
+ // dump SubtypeOf and HasTypeDefinition node if part of the same namespace
1159
1169
  dumpReferencedNodes(xw, node, false);
1160
1170
 
1161
1171
  xw.startElement("UAObjectType");
@@ -1268,25 +1278,6 @@ function writeAliases(xw: XmlWriter, aliases: Record<string, NodeIdString>) {
1268
1278
  xw.endElement();
1269
1279
  }
1270
1280
 
1271
- function constructNamespaceTranslationTable(dependency: INamespace[], exportedNamespace: INamespace): ITranslationTable {
1272
- const translationTable: ITranslationTable = {};
1273
- assert(dependency[0].namespaceUri === "http://opcfoundation.org/UA/");
1274
-
1275
- let counter = 0;
1276
- translationTable[dependency[0].index] = counter++;
1277
- //
1278
- if (exportedNamespace) {
1279
- translationTable[exportedNamespace.index] = counter++;
1280
- }
1281
- for (let i = 1; i < dependency.length; i++) {
1282
- const dep = dependency[i];
1283
- if (exportedNamespace && exportedNamespace === dep) {
1284
- continue;
1285
- }
1286
- translationTable[dep.index] = counter++;
1287
- }
1288
- return translationTable;
1289
- }
1290
1281
  function dumpReferenceType(xw: XmlWriter, referenceType: UAReferenceType) {
1291
1282
  _markAsVisited(xw, referenceType);
1292
1283
 
@@ -1382,9 +1373,10 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
1382
1373
 
1383
1374
  const xw: XmlWriter = new XMLWriter(true);
1384
1375
 
1385
- xw.priorityTable = constructNamespacePriorityTable(this);
1376
+ xw.priorityTable = constructNamespacePriorityTable(this.addressSpace).priorityTable;
1377
+
1386
1378
  const dependency = constructNamespaceDependency(this, xw.priorityTable);
1387
- const translationTable = constructNamespaceTranslationTable(dependency, this);
1379
+ const translationTable = _constructNamespaceTranslationTable(dependency, this);
1388
1380
  xw.translationTable = translationTable;
1389
1381
 
1390
1382
  xw.startDocument({ encoding: "utf-8", version: "1.0" });
@@ -94,6 +94,7 @@ import {
94
94
  } from "./ua_variable_impl_ext_obj";
95
95
  import { adjustDataValueStatusCode } from "./data_access/adjust_datavalue_status_code";
96
96
  import { _getBasicDataType } from "./get_basic_datatype";
97
+ import { validateDataTypeCorrectness} from "./validate_data_type_correctness";
97
98
 
98
99
  const debugLog = make_debugLog(__filename);
99
100
  const warningLog = make_warningLog(__filename);
@@ -149,94 +150,6 @@ function is_Variant_or_StatusCode(v: any): boolean {
149
150
  return is_Variant(v) || is_StatusCode(v);
150
151
  }
151
152
 
152
- function _dataType_toUADataType(addressSpace: IAddressSpace, dataType: DataType): UADataType {
153
- assert(addressSpace);
154
- assert(dataType !== DataType.Null);
155
-
156
- const dataTypeNode = addressSpace.findDataType(DataType[dataType]);
157
- /* istanbul ignore next */
158
- if (!dataTypeNode) {
159
- throw new Error(" Cannot find DataType " + DataType[dataType] + " in address Space");
160
- }
161
- return dataTypeNode as UADataType;
162
- }
163
- /*=
164
- *
165
- * @param addressSpace
166
- * @param dataTypeNodeId : the nodeId matching the dataType of the destination variable.
167
- * @param variantDataType: the dataType of the variant to write to the destination variable
168
- * @param nodeId
169
- * @return {boolean} true if the variant dataType is compatible with the Variable DataType
170
- */
171
- function validateDataType(
172
- addressSpace: IAddressSpace,
173
- dataTypeNodeId: NodeId,
174
- variantDataType: DataType,
175
- nodeId: NodeId,
176
- allowNulls: boolean
177
- ): boolean {
178
- if (variantDataType === DataType.ExtensionObject) {
179
- return true;
180
- }
181
- if (variantDataType === DataType.Null && allowNulls) {
182
- return true;
183
- }
184
- if (variantDataType === DataType.Null && !allowNulls) {
185
- return false;
186
- }
187
- let builtInType: DataType;
188
- let builtInUADataType: UADataType;
189
-
190
- const destUADataType = addressSpace.findDataType(dataTypeNodeId)!;
191
- assert(destUADataType instanceof UADataTypeImpl);
192
-
193
- if (destUADataType.isAbstract || destUADataType.nodeId.namespace !== 0) {
194
- builtInUADataType = destUADataType;
195
- } else {
196
- builtInType = addressSpace.findCorrespondingBasicDataType(destUADataType);
197
- builtInUADataType = addressSpace.findDataType(builtInType)!;
198
- }
199
- assert(builtInUADataType instanceof UADataTypeImpl);
200
-
201
- const enumerationUADataType = addressSpace.findDataType("Enumeration");
202
- if (!enumerationUADataType) {
203
- throw new Error("cannot find Enumeration DataType node in standard address space");
204
- }
205
- if (destUADataType.isSubtypeOf(enumerationUADataType)) {
206
- // istanbul ignore next
207
- if (doDebug) {
208
- debugLog("destUADataType.", destUADataType.browseName.toString(), destUADataType.nodeId.toString());
209
- debugLog(
210
- "enumerationUADataType.",
211
- enumerationUADataType.browseName.toString(),
212
- enumerationUADataType.nodeId.toString()
213
- );
214
- }
215
- return true;
216
- }
217
-
218
- // The value supplied for the attribute is not of the same type as the value.
219
- const variantUADataType = _dataType_toUADataType(addressSpace, variantDataType);
220
- assert(variantUADataType instanceof UADataTypeImpl);
221
-
222
- const dest_isSubTypeOf_variant = variantUADataType.isSubtypeOf(builtInUADataType);
223
-
224
- /* istanbul ignore next */
225
- if (doDebug) {
226
- if (dest_isSubTypeOf_variant) {
227
- /* istanbul ignore next*/
228
- debugLog(chalk.green(" ---------- Type match !!! "), " on ", nodeId.toString());
229
- } else {
230
- /* istanbul ignore next*/
231
- debugLog(chalk.red(" ---------- Type mismatch "), " on ", nodeId.toString());
232
- }
233
- debugLog(chalk.cyan(" Variable data Type is = "), destUADataType.browseName.toString());
234
- debugLog(chalk.cyan(" which matches basic Type = "), builtInUADataType.browseName.toString());
235
- debugLog(chalk.yellow(" Actual dataType = "), variantUADataType.browseName.toString());
236
- }
237
-
238
- return dest_isSubTypeOf_variant;
239
- }
240
153
 
241
154
  function default_func(this: UAVariable, dataValue1: DataValue, callback1: CallbackT<StatusCode>) {
242
155
  return _default_writable_timestamped_set_func.call(this, dataValue1, callback1);
@@ -1707,7 +1620,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1707
1620
  }
1708
1621
 
1709
1622
  public _validate_DataType(variantDataType: DataType): boolean {
1710
- return validateDataType(this.addressSpace, this.dataType, variantDataType, this.nodeId, /* allow Nulls */ false);
1623
+ return validateDataTypeCorrectness(this.addressSpace, this.dataType, variantDataType, /* allow Nulls */ false, this.nodeId);
1711
1624
  }
1712
1625
 
1713
1626
  public _internal_set_value(value: Variant): void {