node-opcua-address-space 2.86.1 → 2.87.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/index.d.ts +1 -0
- package/dist/source/index.js +1 -0
- package/dist/source/index.js.map +1 -1
- package/dist/src/base_node_private.js +7 -6
- package/dist/src/base_node_private.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/namespace_impl.js +7 -4
- package/dist/src/namespace_impl.js.map +1 -1
- package/dist/src/nodeid_manager.d.ts +6 -6
- package/dist/src/nodeid_manager.js +71 -97
- package/dist/src/nodeid_manager.js.map +1 -1
- package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +14 -0
- package/dist/src/nodeset_tools/construct_namespace_dependency.js +21 -1
- package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +1 -3
- package/dist/src/nodeset_tools/nodeset_to_xml.js +24 -10
- package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/src/private_namespace.d.ts +5 -0
- package/dist/src/private_namespace.js +20 -0
- package/dist/src/private_namespace.js.map +1 -0
- package/dist/src/ua_reference_type_impl.d.ts +1 -1
- package/package.json +17 -17
- package/source/index.ts +1 -0
- package/src/base_node_private.ts +52 -48
- package/src/index_current.ts +1 -0
- package/src/namespace_impl.ts +23 -20
- package/src/nodeid_manager.ts +84 -100
- package/src/nodeset_tools/construct_namespace_dependency.ts +30 -9
- package/src/nodeset_tools/nodeset_to_xml.ts +30 -14
- package/src/private_namespace.ts +18 -0
package/src/nodeid_manager.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
import { assert } from "node-opcua-assert";
|
|
4
4
|
import { NodeClass, QualifiedName } from "node-opcua-data-model";
|
|
5
5
|
import { makeNodeId, NodeId, NodeIdLike, NodeIdType, resolveNodeId, sameNodeId } from "node-opcua-nodeid";
|
|
6
|
-
import { make_debugLog } from "node-opcua-debug";
|
|
7
|
-
|
|
6
|
+
import { make_debugLog, make_warningLog } from "node-opcua-debug";
|
|
8
7
|
import { BaseNode, UAReference, UAReferenceType } from "node-opcua-address-space-base";
|
|
9
8
|
import { getReferenceType } from "./base_node_impl";
|
|
10
9
|
|
|
11
10
|
const debugLog = make_debugLog(__filename);
|
|
11
|
+
const warningLog = make_warningLog(__filename);
|
|
12
12
|
|
|
13
13
|
export const NamespaceOptions = {
|
|
14
14
|
nodeIdNameSeparator: "-"
|
|
@@ -21,13 +21,17 @@ const regExp1 = /^(s|i|b|g)=/;
|
|
|
21
21
|
const regExp2 = /^ns=[0-9]+;(s|i|b|g)=/;
|
|
22
22
|
const hasPropertyRefId = resolveNodeId("HasProperty");
|
|
23
23
|
const hasComponentRefId = resolveNodeId("HasComponent");
|
|
24
|
+
const hasOrderedComponentRefId = resolveNodeId("HasOrderedComponent");
|
|
24
25
|
const hasEncoding = resolveNodeId("HasEncoding");
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
type Suffix = string;
|
|
28
|
+
|
|
29
|
+
function _identifyParentInReference(references: UAReference[]): [NodeId, Suffix] | null {
|
|
27
30
|
const candidates = references.filter((r: UAReference) => {
|
|
28
31
|
return (
|
|
29
32
|
!r.isForward &&
|
|
30
33
|
(sameNodeId(r.referenceType, hasComponentRefId) ||
|
|
34
|
+
sameNodeId(r.referenceType, hasOrderedComponentRefId) ||
|
|
31
35
|
sameNodeId(r.referenceType, hasPropertyRefId) ||
|
|
32
36
|
sameNodeId(r.referenceType, hasEncoding))
|
|
33
37
|
);
|
|
@@ -43,6 +47,27 @@ function _identifyParentInReference(references: UAReference[]): [NodeId, string]
|
|
|
43
47
|
return [ref.nodeId, ""];
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
function _findParentNodeId(addressSpace: AddressSpacePartial, options: ConstructNodeIdOptions): [NodeId, Suffix] | null {
|
|
51
|
+
if (!options.references) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
for (const ref of options.references) {
|
|
55
|
+
(ref as any)._referenceType = addressSpace.findReferenceType(ref.referenceType);
|
|
56
|
+
/* istanbul ignore next */
|
|
57
|
+
if (!getReferenceType(ref)) {
|
|
58
|
+
throw new Error("Cannot find referenceType " + JSON.stringify(ref));
|
|
59
|
+
}
|
|
60
|
+
(ref as any).referenceType = (ref as any)._referenceType.nodeId;
|
|
61
|
+
}
|
|
62
|
+
// find HasComponent, or has Property reverse
|
|
63
|
+
return _identifyParentInReference(options.references);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function prepareName(browseName: QualifiedName): string {
|
|
67
|
+
const m = browseName.name!.toString().replace(/[ ]/g, "").replace(/(<|>)/g, "");
|
|
68
|
+
return m;
|
|
69
|
+
}
|
|
70
|
+
|
|
46
71
|
export interface AddressSpacePartial {
|
|
47
72
|
findNode(nodeId: NodeIdLike): BaseNode | null;
|
|
48
73
|
findReferenceType(refType: NodeIdLike, namespaceIndex?: number): UAReferenceType | null;
|
|
@@ -58,8 +83,8 @@ export type NodeEntry = [string, number, NodeClass];
|
|
|
58
83
|
export type NodeEntry1 = [string, number, string /*"Object" | "Variable" etc...*/];
|
|
59
84
|
|
|
60
85
|
export class NodeIdManager {
|
|
61
|
-
private
|
|
62
|
-
private
|
|
86
|
+
private _cacheSymbolicName: { [key: string]: [number,NodeClass] } = {};
|
|
87
|
+
private _cacheSymbolicNameRev: Set<number> = new Set<number>();
|
|
63
88
|
|
|
64
89
|
private _internal_id_counter: number;
|
|
65
90
|
private namespaceIndex: number;
|
|
@@ -71,14 +96,6 @@ export class NodeIdManager {
|
|
|
71
96
|
this.addressSpace = addressSpace;
|
|
72
97
|
}
|
|
73
98
|
|
|
74
|
-
public setCache(cache: NodeEntry[]): void {
|
|
75
|
-
this._cache = {};
|
|
76
|
-
this._reverseCache = {};
|
|
77
|
-
for (const [key, value, nodeClass] of cache) {
|
|
78
|
-
this._addInCache(key, value, nodeClass);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
99
|
public setSymbols(symbols: NodeEntry1[]): void {
|
|
83
100
|
function convertNodeClass(nodeClass: string): NodeClass {
|
|
84
101
|
return (NodeClass as any)[nodeClass as any] as NodeClass;
|
|
@@ -88,13 +105,17 @@ export class NodeIdManager {
|
|
|
88
105
|
number,
|
|
89
106
|
NodeClass
|
|
90
107
|
][];
|
|
91
|
-
|
|
108
|
+
for (const [name, value, nodeClass] of symbols2) {
|
|
109
|
+
this._cacheSymbolicName[name] = [value, nodeClass];
|
|
110
|
+
this._cacheSymbolicNameRev.add(value);
|
|
111
|
+
}
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
public getSymbols(): NodeEntry1[] {
|
|
95
115
|
const line: NodeEntry1[] = [];
|
|
96
|
-
for (const [key, value] of Object.entries(this.
|
|
97
|
-
const
|
|
116
|
+
for (const [key, [value, nodeClass1]] of Object.entries(this._cacheSymbolicName)) {
|
|
117
|
+
const node = this.addressSpace.findNode(makeNodeId(value, this.namespaceIndex));
|
|
118
|
+
const nodeClass = NodeClass[nodeClass1 || NodeClass.Unspecified];
|
|
98
119
|
line.push([key, value, nodeClass]);
|
|
99
120
|
}
|
|
100
121
|
return line;
|
|
@@ -113,18 +134,51 @@ export class NodeIdManager {
|
|
|
113
134
|
do {
|
|
114
135
|
nodeId = makeNodeId(this._internal_id_counter, this.namespaceIndex);
|
|
115
136
|
this._internal_id_counter += 1;
|
|
116
|
-
} while (this.addressSpace.findNode(nodeId) || this._isInCache(nodeId
|
|
137
|
+
} while (this.addressSpace.findNode(nodeId) || this._isInCache(nodeId));
|
|
117
138
|
return nodeId;
|
|
118
139
|
}
|
|
119
140
|
|
|
120
141
|
public constructNodeId(options: ConstructNodeIdOptions): NodeId {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
142
|
+
|
|
143
|
+
const compose = (left: string, right: string) => { return right ? (left ? left + '_' + right : right) : left };
|
|
144
|
+
|
|
145
|
+
const buildUpName2 = (nodeId: NodeId, suffix: string) => {
|
|
146
|
+
const namespaceIndex = nodeId.namespace;
|
|
147
|
+
let name = "";
|
|
148
|
+
let n: BaseNode | null = this.addressSpace.findNode(nodeId);
|
|
149
|
+
while (n && n.nodeId.namespace === namespaceIndex) {
|
|
150
|
+
const e = prepareName(n.browseName) + suffix;
|
|
151
|
+
name = compose(e, name);
|
|
152
|
+
n = n.parentNodeId ? this.addressSpace.findNode(n.parentNodeId) : null;
|
|
153
|
+
}
|
|
154
|
+
return name;
|
|
124
155
|
}
|
|
125
|
-
let nodeId = options.nodeId;
|
|
126
|
-
const nodeClass = options.nodeClass;
|
|
127
156
|
|
|
157
|
+
if (!options.nodeId && options.registerSymbolicNames) {
|
|
158
|
+
const parentInfo = this.findParentNodeId(options);
|
|
159
|
+
let fullParentName = "";
|
|
160
|
+
if (parentInfo) {
|
|
161
|
+
const [parentNodeId, suffix] = parentInfo;
|
|
162
|
+
fullParentName = buildUpName2(parentNodeId, suffix);
|
|
163
|
+
}
|
|
164
|
+
const fullName = compose(fullParentName, prepareName(options.browseName));
|
|
165
|
+
if (this._cacheSymbolicName[fullName]) {
|
|
166
|
+
return makeNodeId(this._cacheSymbolicName[fullName][0], this.namespaceIndex);
|
|
167
|
+
}
|
|
168
|
+
const nodeId = this._constructNodeId(options);
|
|
169
|
+
if (nodeId.identifierType === NodeIdType.NUMERIC) {
|
|
170
|
+
this._cacheSymbolicName[fullName] = [nodeId.value as number, options.nodeClass];
|
|
171
|
+
this._cacheSymbolicNameRev.add(nodeId.value as number);
|
|
172
|
+
}
|
|
173
|
+
return nodeId;
|
|
174
|
+
}
|
|
175
|
+
return this._constructNodeId(options);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private _constructNodeId(options: ConstructNodeIdOptions): NodeId {
|
|
179
|
+
|
|
180
|
+
let nodeId = options.nodeId;
|
|
181
|
+
|
|
128
182
|
if (!nodeId) {
|
|
129
183
|
const parentInfo = this.findParentNodeId(options);
|
|
130
184
|
if (parentInfo) {
|
|
@@ -136,41 +190,7 @@ export class NodeIdManager {
|
|
|
136
190
|
const childName = parentNodeId.value + NamespaceOptions.nodeIdNameSeparator + name;
|
|
137
191
|
nodeId = new NodeId(NodeId.NodeIdType.STRING, childName, parentNodeId.namespace);
|
|
138
192
|
return nodeId;
|
|
139
|
-
}
|
|
140
|
-
//
|
|
141
|
-
const baseNameInCache = this._reverseCache[parentNodeId.value as number];
|
|
142
|
-
if (baseNameInCache) {
|
|
143
|
-
const newName = baseNameInCache.name + linkName + "_" + name;
|
|
144
|
-
const nodeIdValueInCache = this._cache[newName];
|
|
145
|
-
if (nodeIdValueInCache) {
|
|
146
|
-
return new NodeId(NodeIdType.NUMERIC, nodeIdValueInCache, this.namespaceIndex);
|
|
147
|
-
} else {
|
|
148
|
-
return this._getOrCreateFromName(newName, nodeClass);
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
if (options.registerSymbolicNames) {
|
|
152
|
-
const newName = name;
|
|
153
|
-
const nodeIdValueInCache = this._cache[newName];
|
|
154
|
-
if (nodeIdValueInCache) {
|
|
155
|
-
return new NodeId(NodeIdType.NUMERIC, nodeIdValueInCache, this.namespaceIndex);
|
|
156
|
-
} else {
|
|
157
|
-
return this._getOrCreateFromName(newName, nodeClass);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// }} has parent ...
|
|
163
|
-
} else {
|
|
164
|
-
const isRootType =
|
|
165
|
-
options.nodeClass === NodeClass.DataType ||
|
|
166
|
-
options.nodeClass === NodeClass.ObjectType ||
|
|
167
|
-
options.nodeClass === NodeClass.ReferenceType ||
|
|
168
|
-
options.nodeClass === NodeClass.VariableType;
|
|
169
|
-
// try to find
|
|
170
|
-
if (isRootType) {
|
|
171
|
-
const baseName = options.browseName.name!.toString();
|
|
172
|
-
return this._getOrCreateFromName(baseName, nodeClass);
|
|
173
|
-
}
|
|
193
|
+
}
|
|
174
194
|
}
|
|
175
195
|
} else if (typeof nodeId === "string") {
|
|
176
196
|
if (this.namespaceIndex !== 0) {
|
|
@@ -178,8 +198,8 @@ export class NodeIdManager {
|
|
|
178
198
|
// nothing
|
|
179
199
|
} else if (nodeId.match(regExp1)) {
|
|
180
200
|
nodeId = "ns=" + this.namespaceIndex + ";" + nodeId;
|
|
181
|
-
|
|
182
|
-
nodeId = this._getOrCreateFromName(nodeId, nodeClass);
|
|
201
|
+
// } else {
|
|
202
|
+
// nodeId = this._getOrCreateFromName(nodeId, nodeClass);
|
|
183
203
|
}
|
|
184
204
|
}
|
|
185
205
|
}
|
|
@@ -193,48 +213,12 @@ export class NodeIdManager {
|
|
|
193
213
|
return nodeId;
|
|
194
214
|
}
|
|
195
215
|
|
|
196
|
-
public findParentNodeId(options: ConstructNodeIdOptions): [NodeId,
|
|
197
|
-
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
for (const ref of options.references) {
|
|
201
|
-
(ref as any)._referenceType = this.addressSpace.findReferenceType(ref.referenceType);
|
|
202
|
-
/* istanbul ignore next */
|
|
203
|
-
if (!getReferenceType(ref)) {
|
|
204
|
-
throw new Error("Cannot find referenceType " + JSON.stringify(ref));
|
|
205
|
-
}
|
|
206
|
-
(ref as any).referenceType = (ref as any)._referenceType.nodeId;
|
|
207
|
-
}
|
|
208
|
-
// find HasComponent, or has Property reverse
|
|
209
|
-
return _identifyParentInReference(options.references);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
private _addInCache(name: string, nodeIdValue: number, nodeClass: NodeClass) {
|
|
213
|
-
assert(!name.includes(":"), "Alias name should not contain special characters");
|
|
214
|
-
assert(typeof name === "string" && name[0] !== "[");
|
|
215
|
-
if (this._isInCache(nodeIdValue) || this._cache[name]) {
|
|
216
|
-
throw new Error("Already in Cache !" + name + " " + nodeIdValue + " = " + this._cache[name]);
|
|
217
|
-
}
|
|
218
|
-
this._cache[name] = nodeIdValue;
|
|
219
|
-
this._reverseCache[nodeIdValue] = { name, nodeClass };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private _isInCache(nodeIdValue: number) {
|
|
223
|
-
return this._reverseCache[nodeIdValue] ? true : false;
|
|
216
|
+
public findParentNodeId(options: ConstructNodeIdOptions): [NodeId, Suffix] | null {
|
|
217
|
+
return _findParentNodeId(this.addressSpace, options);
|
|
224
218
|
}
|
|
225
219
|
|
|
226
|
-
private
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
debugLog("alias name should not contain special characters");
|
|
230
|
-
}
|
|
231
|
-
assert(!aliasName.includes(":"), "Alias name should not contain special characters");
|
|
232
|
-
if (this._cache[aliasName]) {
|
|
233
|
-
return new NodeId(NodeIdType.NUMERIC, this._cache[aliasName], this.namespaceIndex);
|
|
234
|
-
} else {
|
|
235
|
-
const nodeIdResult = this.buildNewNodeId();
|
|
236
|
-
this._addInCache(aliasName, nodeIdResult.value as number, nodeClass);
|
|
237
|
-
return nodeIdResult;
|
|
238
|
-
}
|
|
220
|
+
private _isInCache(nodeId: NodeId): boolean {
|
|
221
|
+
if( nodeId.namespace !== this.namespaceIndex || nodeId.identifierType !== NodeIdType.NUMERIC) return false;
|
|
222
|
+
return this._cacheSymbolicNameRev.has(nodeId.value as number) ? true : false;
|
|
239
223
|
}
|
|
240
224
|
}
|
|
@@ -19,7 +19,7 @@ function _constructNamespaceDependency(
|
|
|
19
19
|
// navigate all namespace recursively to
|
|
20
20
|
|
|
21
21
|
function consider(namespaceIndex: number) {
|
|
22
|
-
if (hasHigherPriorityThan(namespaceIndex,namespace.index, priorityTable)) {
|
|
22
|
+
if (hasHigherPriorityThan(namespaceIndex, namespace.index, priorityTable)) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
if (!depMap.has(namespaceIndex)) {
|
|
@@ -48,7 +48,7 @@ function _constructNamespaceDependency(
|
|
|
48
48
|
}
|
|
49
49
|
// istanbul ignore next
|
|
50
50
|
if (dataTypeNode.nodeClass !== NodeClass.DataType) {
|
|
51
|
-
warningLog("exploreDataTypes! ignoring ",dataTypeNode.toString());
|
|
51
|
+
warningLog("exploreDataTypes! ignoring ", dataTypeNode.toString());
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -94,19 +94,33 @@ export function hasHigherPriorityThan(namespaceIndex1: number, namespaceIndex2:
|
|
|
94
94
|
return order1 > order2;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
*
|
|
99
|
+
* @param namespace
|
|
100
|
+
* @returns the order
|
|
101
|
+
*
|
|
102
|
+
* ---
|
|
103
|
+
* ua, own , di => 0 , 2, 1
|
|
104
|
+
*
|
|
105
|
+
* ---
|
|
106
|
+
* ua, own , di , kitchen , own2, adi => 0 , 2, 3, 1
|
|
107
|
+
*
|
|
108
|
+
* ---
|
|
109
|
+
* ua, own , di , kitchen , own2, adi => 0 , 2, 3, 5, 1
|
|
110
|
+
*/
|
|
97
111
|
export function constructNamespacePriorityTable(namespace: INamespace): number[] {
|
|
98
112
|
|
|
99
113
|
// Namespace 0 will always be 0
|
|
100
114
|
// Namespaces with no requiredModel will be considered as instance namespaces and will added at the end
|
|
101
115
|
// in the same order as they appear,
|
|
102
116
|
// Namespace with requiredModels are considered to be companion specification, so already loaded in the correct order
|
|
103
|
-
|
|
117
|
+
|
|
104
118
|
const addressSpace = namespace.addressSpace;
|
|
105
119
|
const namespaces = addressSpace.getNamespaceArray();
|
|
106
120
|
|
|
107
|
-
const namespaceWithReq = namespaces.filter((n)=> (n.getRequiredModels() !== undefined)
|
|
108
|
-
const namespaceWithoutReq = namespaces.filter((n)=>(n.getRequiredModels() === undefined) && n.index !==0);
|
|
109
|
-
|
|
121
|
+
const namespaceWithReq = namespaces.filter((n) => (n.getRequiredModels() !== undefined) && n.index !== 0);
|
|
122
|
+
const namespaceWithoutReq = namespaces.filter((n) => (n.getRequiredModels() === undefined) && n.index !== 0);
|
|
123
|
+
|
|
110
124
|
const priorityList: number[] = [0];
|
|
111
125
|
let counter = 1;
|
|
112
126
|
for (let i = 0; i < namespaceWithReq.length; i++) {
|
|
@@ -117,10 +131,10 @@ export function constructNamespacePriorityTable(namespace: INamespace): number[]
|
|
|
117
131
|
}
|
|
118
132
|
return priorityList;
|
|
119
133
|
}
|
|
120
|
-
|
|
134
|
+
const doDebug = false;
|
|
121
135
|
export function constructNamespaceDependency(namespace: INamespace, priorityTable?: number[]): INamespace[] {
|
|
122
136
|
const addressSpace = namespace.addressSpace;
|
|
123
|
-
|
|
137
|
+
|
|
124
138
|
priorityTable = priorityTable || constructNamespacePriorityTable(namespace);
|
|
125
139
|
|
|
126
140
|
const dependency: INamespace[] = [];
|
|
@@ -137,5 +151,12 @@ export function constructNamespaceDependency(namespace: INamespace, priorityTabl
|
|
|
137
151
|
|
|
138
152
|
_constructNamespaceDependency(namespace, dependency, depMap, _visitedDataType, priorityTable);
|
|
139
153
|
|
|
140
|
-
|
|
154
|
+
doDebug && console.log("namespace : ", namespace.index, namespace.namespaceUri);
|
|
155
|
+
doDebug && console.log(" ", dependency.map((d)=>d.index + " " + d.namespaceUri).join("\n "));
|
|
156
|
+
|
|
157
|
+
const sorted = dependency.sort((a, b) => priorityTable![a.index] < priorityTable![b.index] ? -1 : 1);
|
|
158
|
+
doDebug && console.log("sorted:")
|
|
159
|
+
doDebug && console.log(" ", sorted.map((d)=>d.index + " " + d.namespaceUri).join("\n "));
|
|
160
|
+
|
|
161
|
+
return sorted;
|
|
141
162
|
}
|
|
@@ -61,6 +61,7 @@ const XMLWriter = require("xml-writer");
|
|
|
61
61
|
const debugLog = make_debugLog(__filename);
|
|
62
62
|
const warningLog = make_warningLog(__filename);
|
|
63
63
|
const errorLog = make_errorLog(__filename);
|
|
64
|
+
const doDebug = false;
|
|
64
65
|
|
|
65
66
|
function _hash(node: BaseNode | UAReference): string {
|
|
66
67
|
return node.nodeId.toString();
|
|
@@ -1036,11 +1037,11 @@ function dumpUAVariableType(xw: XmlWriter, node: UAVariableType) {
|
|
|
1036
1037
|
// throw new Error(" cannot find datatype " + node.dataType);
|
|
1037
1038
|
console.log(
|
|
1038
1039
|
" cannot find datatype " +
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1040
|
+
node.dataType +
|
|
1041
|
+
" for node " +
|
|
1042
|
+
node.browseName.toString() +
|
|
1043
|
+
" id =" +
|
|
1044
|
+
node.nodeId.toString()
|
|
1044
1045
|
);
|
|
1045
1046
|
} else {
|
|
1046
1047
|
const dataTypeName = b(xw, resolveDataTypeName(addressSpace, dataTypeNode.nodeId));
|
|
@@ -1247,10 +1248,21 @@ function writeAliases(xw: XmlWriter, aliases: Record<string, NodeIdString>) {
|
|
|
1247
1248
|
xw.endElement();
|
|
1248
1249
|
}
|
|
1249
1250
|
|
|
1250
|
-
|
|
1251
|
+
function constructNamespaceTranslationTable(dependency: INamespace[], exportedNamespace: INamespace): ITranslationTable {
|
|
1252
|
+
|
|
1251
1253
|
const translationTable: ITranslationTable = {};
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
+
assert(dependency[0].namespaceUri === "http://opcfoundation.org/UA/");
|
|
1255
|
+
|
|
1256
|
+
let counter = 0;
|
|
1257
|
+
translationTable[dependency[0].index] = counter++;
|
|
1258
|
+
//
|
|
1259
|
+
if (exportedNamespace) {
|
|
1260
|
+
translationTable[exportedNamespace.index] = counter++;
|
|
1261
|
+
}
|
|
1262
|
+
for (let i = 1; i < dependency.length; i++) {
|
|
1263
|
+
const dep = dependency[i];
|
|
1264
|
+
if (exportedNamespace && exportedNamespace === dep) { continue; }
|
|
1265
|
+
translationTable[dep.index] = counter++;
|
|
1254
1266
|
}
|
|
1255
1267
|
return translationTable;
|
|
1256
1268
|
}
|
|
@@ -1342,7 +1354,7 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
|
|
|
1342
1354
|
|
|
1343
1355
|
xw.priorityTable = constructNamespacePriorityTable(this);
|
|
1344
1356
|
const dependency = constructNamespaceDependency(this, xw.priorityTable);
|
|
1345
|
-
const translationTable = constructNamespaceTranslationTable(dependency);
|
|
1357
|
+
const translationTable = constructNamespaceTranslationTable(dependency, this);
|
|
1346
1358
|
xw.translationTable = translationTable;
|
|
1347
1359
|
|
|
1348
1360
|
xw.startDocument({ encoding: "utf-8", version: "1.0" });
|
|
@@ -1372,12 +1384,17 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
|
|
|
1372
1384
|
// xx xw.writeAttribute("LastModified", (new Date()).toISOString());
|
|
1373
1385
|
|
|
1374
1386
|
// ------------- INamespace Uris
|
|
1387
|
+
initXmlWriterEx(xw, namespacesMap, namespaceArray);
|
|
1388
|
+
|
|
1375
1389
|
xw.startElement("NamespaceUris");
|
|
1376
1390
|
|
|
1377
|
-
|
|
1391
|
+
// let's sort the dependencies in the same order as the translation table
|
|
1392
|
+
const sortedDependencies = dependency.sort((a,b)=> translationTable[a.index] > translationTable[b.index] ? 1: -1);
|
|
1393
|
+
|
|
1394
|
+
doDebug && console.log(sortedDependencies.map((a)=>a.index + " + "+ a.namespaceUri).join("\n"));
|
|
1395
|
+
doDebug && console.log("translation table ", translationTable);
|
|
1378
1396
|
|
|
1379
|
-
|
|
1380
|
-
for (const depend of dependency) {
|
|
1397
|
+
for (const depend of sortedDependencies) {
|
|
1381
1398
|
if (depend.index === 0) {
|
|
1382
1399
|
continue; // ignore namespace 0
|
|
1383
1400
|
}
|
|
@@ -1385,7 +1402,6 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
|
|
|
1385
1402
|
xw.text(depend.namespaceUri);
|
|
1386
1403
|
xw.endElement();
|
|
1387
1404
|
}
|
|
1388
|
-
|
|
1389
1405
|
xw.endElement();
|
|
1390
1406
|
|
|
1391
1407
|
// ------------- INamespace Uris
|
|
@@ -1395,7 +1411,7 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
|
|
|
1395
1411
|
xw.writeAttribute("ModelUri", this.namespaceUri);
|
|
1396
1412
|
xw.writeAttribute("Version", this.version);
|
|
1397
1413
|
xw.writeAttribute("PublicationDate", this.publicationDate.toISOString());
|
|
1398
|
-
for (const depend of
|
|
1414
|
+
for (const depend of sortedDependencies) {
|
|
1399
1415
|
if (depend.index === this.index) {
|
|
1400
1416
|
continue; // ignore our namespace 0
|
|
1401
1417
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { Namespace } from "../source/namespace";
|
|
4
|
+
import { NodeEntry1, NodeIdManager } from "./nodeid_manager";
|
|
5
|
+
|
|
6
|
+
export function getNodeIdManager(ns: Namespace): NodeIdManager {
|
|
7
|
+
const nodeIdManager = (ns as any)._nodeIdManager as NodeIdManager;
|
|
8
|
+
return nodeIdManager;
|
|
9
|
+
}
|
|
10
|
+
export function setSymbols(ns: Namespace, symbols: NodeEntry1[]) {
|
|
11
|
+
const nodeIdManager = getNodeIdManager(ns);
|
|
12
|
+
(ns.addressSpace.getOwnNamespace() as any).registerSymbolicNames = true;
|
|
13
|
+
nodeIdManager.setSymbols(symbols);
|
|
14
|
+
}
|
|
15
|
+
export function getSymbols(ns: Namespace): NodeEntry1[] {
|
|
16
|
+
const nodeIdManager = getNodeIdManager(ns);
|
|
17
|
+
return nodeIdManager?.getSymbols() || [];
|
|
18
|
+
}
|