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.
- package/dist/source/helpers/call_helpers.d.ts +1 -2
- package/dist/source/helpers/call_helpers.js +15 -0
- package/dist/source/helpers/call_helpers.js.map +1 -1
- package/dist/source/index.d.ts +1 -0
- package/dist/source/index.js +3 -1
- package/dist/source/index.js.map +1 -1
- package/dist/source/loader/generateAddressSpaceRaw.d.ts +19 -1
- package/dist/source/loader/generateAddressSpaceRaw.js +157 -4
- package/dist/source/loader/generateAddressSpaceRaw.js.map +1 -1
- package/dist/source/loader/load_nodeset2.js +3 -10
- package/dist/source/loader/load_nodeset2.js.map +1 -1
- package/dist/src/index_current.d.ts +1 -0
- package/dist/src/index_current.js +1 -0
- package/dist/src/index_current.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/src/ua_variable_impl.js +2 -74
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/validate_data_type_correctness.d.ts +6 -0
- package/dist/src/validate_data_type_correctness.js +98 -0
- package/dist/src/validate_data_type_correctness.js.map +1 -0
- package/dist/tsconfig_common.tsbuildinfo +1 -1
- package/package.json +38 -38
- package/source/helpers/call_helpers.ts +1 -1
- package/source/index.ts +1 -1
- package/source/loader/generateAddressSpaceRaw.ts +180 -5
- package/source/loader/load_nodeset2.ts +3 -9
- package/src/index_current.ts +1 -1
- package/src/nodeset_tools/construct_namespace_dependency.ts +232 -91
- package/src/nodeset_tools/nodeset_to_xml.ts +19 -27
- package/src/ua_variable_impl.ts +2 -89
- 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
|
-
|
|
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" });
|
package/src/ua_variable_impl.ts
CHANGED
|
@@ -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
|
|
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 {
|