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.
Files changed (32) hide show
  1. package/dist/source/index.d.ts +1 -0
  2. package/dist/source/index.js +1 -0
  3. package/dist/source/index.js.map +1 -1
  4. package/dist/src/base_node_private.js +7 -6
  5. package/dist/src/base_node_private.js.map +1 -1
  6. package/dist/src/index_current.d.ts +1 -0
  7. package/dist/src/index_current.js +1 -0
  8. package/dist/src/index_current.js.map +1 -1
  9. package/dist/src/namespace_impl.js +7 -4
  10. package/dist/src/namespace_impl.js.map +1 -1
  11. package/dist/src/nodeid_manager.d.ts +6 -6
  12. package/dist/src/nodeid_manager.js +71 -97
  13. package/dist/src/nodeid_manager.js.map +1 -1
  14. package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +14 -0
  15. package/dist/src/nodeset_tools/construct_namespace_dependency.js +21 -1
  16. package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
  17. package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +1 -3
  18. package/dist/src/nodeset_tools/nodeset_to_xml.js +24 -10
  19. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  20. package/dist/src/private_namespace.d.ts +5 -0
  21. package/dist/src/private_namespace.js +20 -0
  22. package/dist/src/private_namespace.js.map +1 -0
  23. package/dist/src/ua_reference_type_impl.d.ts +1 -1
  24. package/package.json +17 -17
  25. package/source/index.ts +1 -0
  26. package/src/base_node_private.ts +52 -48
  27. package/src/index_current.ts +1 -0
  28. package/src/namespace_impl.ts +23 -20
  29. package/src/nodeid_manager.ts +84 -100
  30. package/src/nodeset_tools/construct_namespace_dependency.ts +30 -9
  31. package/src/nodeset_tools/nodeset_to_xml.ts +30 -14
  32. package/src/private_namespace.ts +18 -0
@@ -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
- function _identifyParentInReference(references: UAReference[]): [NodeId, string] | null {
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 _cache: { [key: string]: number } = {};
62
- private _reverseCache: { [key: number]: { name: string; nodeClass: NodeClass } } = {};
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
- this.setCache(symbols2);
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._cache)) {
97
- const nodeClass = NodeClass[this._reverseCache[value].nodeClass];
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.value as number));
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
- function prepareName(browseName: QualifiedName): string {
122
- const m = browseName.name!.toString().replace(/[ ]/g, "").replace(/(<|>)/g, "");
123
- return m;
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
- } else if (parentNodeId.identifierType === NodeId.NodeIdType.NUMERIC) {
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
- } else {
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, string] | null {
197
- if (!options.references) {
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 _getOrCreateFromName(aliasName: string, nodeClass: NodeClass): NodeId {
227
- assert(isValidNodeClass(nodeClass), "invalid node class " + nodeClass);
228
- if (aliasName.includes(":")) {
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) && n.index !==0);
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
- return dependency;
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
- node.dataType +
1040
- " for node " +
1041
- node.browseName.toString() +
1042
- " id =" +
1043
- node.nodeId.toString()
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
- export function constructNamespaceTranslationTable(dependency: INamespace[]): ITranslationTable {
1251
+ function constructNamespaceTranslationTable(dependency: INamespace[], exportedNamespace: INamespace): ITranslationTable {
1252
+
1251
1253
  const translationTable: ITranslationTable = {};
1252
- for (let i = 0; i < dependency.length; i++) {
1253
- translationTable[dependency[i].index] = i;
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
- initXmlWriterEx(xw, namespacesMap, namespaceArray);
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
- // xx const namespaceArray = namespace.addressSpace.getNamespaceArray();
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 dependency) {
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
+ }