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/dist/source/loader/generateAddressSpaceRaw.js +8 -4
- package/dist/source/loader/generateAddressSpaceRaw.js.map +1 -1
- package/dist/source/loader/load_nodeset2.js +2 -2
- package/dist/source/loader/load_nodeset2.js.map +1 -1
- package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +27 -3
- package/dist/src/nodeset_tools/construct_namespace_dependency.js +210 -81
- package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.js +15 -23
- package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/tsconfig_common.tsbuildinfo +1 -1
- package/package.json +38 -38
- package/source/loader/generateAddressSpaceRaw.ts +10 -4
- package/source/loader/load_nodeset2.ts +2 -2
- package/src/nodeset_tools/construct_namespace_dependency.ts +232 -91
- package/src/nodeset_tools/nodeset_to_xml.ts +19 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-address-space",
|
|
3
|
-
"version": "2.
|
|
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.
|
|
20
|
-
"@types/semver": "^7.5.
|
|
21
|
-
"async": "^3.2.
|
|
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.
|
|
25
|
+
"node-opcua-address-space-base": "2.117.0",
|
|
26
26
|
"node-opcua-assert": "2.105.0",
|
|
27
|
-
"node-opcua-basic-types": "2.
|
|
28
|
-
"node-opcua-binary-stream": "2.
|
|
29
|
-
"node-opcua-client-dynamic-extension-object": "2.
|
|
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.
|
|
33
|
-
"node-opcua-data-model": "2.
|
|
34
|
-
"node-opcua-data-value": "2.
|
|
35
|
-
"node-opcua-date-time": "2.
|
|
36
|
-
"node-opcua-debug": "2.
|
|
37
|
-
"node-opcua-enum": "2.
|
|
38
|
-
"node-opcua-extension-object": "2.
|
|
39
|
-
"node-opcua-factory": "2.
|
|
40
|
-
"node-opcua-nodeid": "2.
|
|
41
|
-
"node-opcua-nodeset-ua": "2.
|
|
42
|
-
"node-opcua-numeric-range": "2.
|
|
43
|
-
"node-opcua-object-registry": "2.
|
|
44
|
-
"node-opcua-pseudo-session": "2.
|
|
45
|
-
"node-opcua-service-browse": "2.
|
|
46
|
-
"node-opcua-service-call": "2.
|
|
47
|
-
"node-opcua-service-history": "2.
|
|
48
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
49
|
-
"node-opcua-service-write": "2.
|
|
50
|
-
"node-opcua-status-code": "2.
|
|
51
|
-
"node-opcua-types": "2.
|
|
52
|
-
"node-opcua-utils": "2.
|
|
53
|
-
"node-opcua-variant": "2.
|
|
54
|
-
"node-opcua-xml2json": "2.
|
|
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.
|
|
63
|
-
"node-opcua-leak-detector": "2.
|
|
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.
|
|
66
|
-
"node-opcua-service-filter": "2.
|
|
67
|
-
"node-opcua-test-fixtures": "2.
|
|
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": "^
|
|
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": "
|
|
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
|
|
192
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
17
|
+
// eslint-disable-next-line max-statements, complexity
|
|
18
|
+
export function _recomputeRequiredModelsFromTypes(
|
|
17
19
|
namespace: INamespace,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
119
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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(
|
|
154
|
-
// Namespace 0 will always be 0
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
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
|
|
163
|
-
const namespaceWithoutReq = namespaces.filter((n) => n.getRequiredModels() === undefined && n.index !== 0);
|
|
267
|
+
const loadingOrder: number[] = [0];
|
|
164
268
|
|
|
165
|
-
const
|
|
166
|
-
let
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
275
|
+
const visited = new Set<number>();
|
|
276
|
+
visited.add(0);
|
|
180
277
|
|
|
181
|
-
const
|
|
182
|
-
|
|
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
|
-
|
|
185
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
312
|
+
return { loadingOrder, priorityTable };
|
|
313
|
+
}
|
|
194
314
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
1379
|
+
const translationTable = _constructNamespaceTranslationTable(dependency, this);
|
|
1388
1380
|
xw.translationTable = translationTable;
|
|
1389
1381
|
|
|
1390
1382
|
xw.startDocument({ encoding: "utf-8", version: "1.0" });
|