node-opcua-address-space 2.116.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space",
3
- "version": "2.116.0",
3
+ "version": "2.117.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",
@@ -16,42 +16,42 @@
16
16
  "c": "mocha --version"
17
17
  },
18
18
  "dependencies": {
19
- "@types/lodash": "4.14.199",
20
- "@types/semver": "^7.5.3",
21
- "async": "^3.2.4",
19
+ "@types/lodash": "4.14.201",
20
+ "@types/semver": "^7.5.5",
21
+ "async": "^3.2.5",
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.114.0",
25
+ "node-opcua-address-space-base": "2.117.0",
26
26
  "node-opcua-assert": "2.105.0",
27
- "node-opcua-basic-types": "2.114.0",
28
- "node-opcua-binary-stream": "2.114.0",
29
- "node-opcua-client-dynamic-extension-object": "2.116.0",
27
+ "node-opcua-basic-types": "2.117.0",
28
+ "node-opcua-binary-stream": "2.117.0",
29
+ "node-opcua-client-dynamic-extension-object": "2.117.0",
30
30
  "node-opcua-constants": "2.114.0",
31
31
  "node-opcua-crypto": "4.5.0",
32
- "node-opcua-data-access": "2.114.0",
33
- "node-opcua-data-model": "2.114.0",
34
- "node-opcua-data-value": "2.114.0",
35
- "node-opcua-date-time": "2.114.0",
36
- "node-opcua-debug": "2.114.0",
37
- "node-opcua-enum": "2.114.0",
38
- "node-opcua-extension-object": "2.114.0",
39
- "node-opcua-factory": "2.114.0",
40
- "node-opcua-nodeid": "2.114.0",
41
- "node-opcua-nodeset-ua": "2.114.0",
42
- "node-opcua-numeric-range": "2.114.0",
43
- "node-opcua-object-registry": "2.114.0",
44
- "node-opcua-pseudo-session": "2.116.0",
45
- "node-opcua-service-browse": "2.114.0",
46
- "node-opcua-service-call": "2.114.0",
47
- "node-opcua-service-history": "2.114.0",
48
- "node-opcua-service-translate-browse-path": "2.114.0",
49
- "node-opcua-service-write": "2.114.0",
50
- "node-opcua-status-code": "2.114.0",
51
- "node-opcua-types": "2.114.0",
52
- "node-opcua-utils": "2.114.0",
53
- "node-opcua-variant": "2.114.0",
54
- "node-opcua-xml2json": "2.114.0",
32
+ "node-opcua-data-access": "2.117.0",
33
+ "node-opcua-data-model": "2.117.0",
34
+ "node-opcua-data-value": "2.117.0",
35
+ "node-opcua-date-time": "2.117.0",
36
+ "node-opcua-debug": "2.117.0",
37
+ "node-opcua-enum": "2.117.0",
38
+ "node-opcua-extension-object": "2.117.0",
39
+ "node-opcua-factory": "2.117.0",
40
+ "node-opcua-nodeid": "2.117.0",
41
+ "node-opcua-nodeset-ua": "2.117.0",
42
+ "node-opcua-numeric-range": "2.117.0",
43
+ "node-opcua-object-registry": "2.117.0",
44
+ "node-opcua-pseudo-session": "2.117.0",
45
+ "node-opcua-service-browse": "2.117.0",
46
+ "node-opcua-service-call": "2.117.0",
47
+ "node-opcua-service-history": "2.117.0",
48
+ "node-opcua-service-translate-browse-path": "2.117.0",
49
+ "node-opcua-service-write": "2.117.0",
50
+ "node-opcua-status-code": "2.117.0",
51
+ "node-opcua-types": "2.117.0",
52
+ "node-opcua-utils": "2.117.0",
53
+ "node-opcua-variant": "2.117.0",
54
+ "node-opcua-xml2json": "2.117.0",
55
55
  "semver": "^7.5.4",
56
56
  "set-prototype-of": "^1.0.0",
57
57
  "thenify": "^3.3.1",
@@ -59,14 +59,14 @@
59
59
  },
60
60
  "devDependencies": {
61
61
  "mocha": "^10.2.0",
62
- "node-opcua-benchmarker": "2.114.0",
63
- "node-opcua-leak-detector": "2.114.0",
62
+ "node-opcua-benchmarker": "2.117.0",
63
+ "node-opcua-leak-detector": "2.117.0",
64
64
  "node-opcua-nodesets": "2.110.0",
65
- "node-opcua-packet-analyzer": "2.114.0",
66
- "node-opcua-service-filter": "2.114.0",
67
- "node-opcua-test-fixtures": "2.114.0",
65
+ "node-opcua-packet-analyzer": "2.117.0",
66
+ "node-opcua-service-filter": "2.117.0",
67
+ "node-opcua-test-fixtures": "2.117.0",
68
68
  "should": "^13.2.3",
69
- "sinon": "^16.0.0",
69
+ "sinon": "^17.0.1",
70
70
  "source-map-support": "^0.5.21"
71
71
  },
72
72
  "author": "Etienne Rossignon",
@@ -84,7 +84,7 @@
84
84
  "internet of things"
85
85
  ],
86
86
  "homepage": "http://node-opcua.github.io/",
87
- "gitHead": "713ad387571a323c8d886ad1c907f50ad96a5e76",
87
+ "gitHead": "99ed7589a203923985c25be8907b36485c798bbe",
88
88
  "files": [
89
89
  "dist",
90
90
  "distHelpers",
@@ -187,15 +187,21 @@ export async function generateAddressSpaceRaw(
187
187
 
188
188
  const nodesetDesc = await preLoad(xmlFiles, xmlLoader);
189
189
  const order = findOrder(nodesetDesc);
190
+
191
+ // register namespace in the same order as specified in the xmlFiles array
190
192
  for (let index = 0; index < order.length; index++) {
191
- const nodesetIndex = order[index];
192
- const nodeset = nodesetDesc[nodesetIndex];
193
- debugLog(" loading ", nodesetIndex, nodeset.xmlData.length);
194
- for (const model of nodeset.namespaceModel.models) {
193
+ const n = nodesetDesc[index];
194
+ for (const model of n.namespaceModel.models) {
195
195
  const ns = addressSpace.registerNamespace(model.modelUri) as NamespacePrivate;
196
196
  ns.setRequiredModels(model.requiredModel);
197
197
  }
198
+ }
198
199
 
200
+
201
+ for (let index = 0; index < order.length; index++) {
202
+ const nodesetIndex = order[index];
203
+ const nodeset = nodesetDesc[nodesetIndex];
204
+ debugLog(" loading ", nodesetIndex, nodeset.xmlData.length);
199
205
  try {
200
206
  await nodesetLoader.addNodeSetAsync(nodeset.xmlData);
201
207
  } catch (err) {
@@ -194,8 +194,8 @@ function makeNodeSetParserEngine(addressSpace: IAddressSpace, options: NodeSetLo
194
194
 
195
195
  // istanbul ignore next
196
196
  if (namespaceIndex === undefined) {
197
- debugLog("Warning: namespace_uri_translation = ", namespace_uri_translation);
198
- errorLog("namespace_uri_translation", namespace_uri_translation);
197
+ errorLog("Warning: namespace_uri_translation = ", namespace_uri_translation);
198
+ errorLog("Error; namespace_uri_translation", namespace_uri_translation);
199
199
  throw new Error("_translateNamespaceIndex() ! Cannot find namespace definition for index " + innerIndex);
200
200
  }
201
201
  return namespaceIndex;
@@ -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" });