node-opcua-address-space 2.76.2 → 2.78.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 (73) hide show
  1. package/dist/source/continuation_points/continuation_point_manager.d.ts +59 -0
  2. package/dist/source/continuation_points/continuation_point_manager.js +6 -6
  3. package/dist/source/continuation_points/continuation_point_manager.js.map +1 -1
  4. package/dist/source/index.d.ts +1 -0
  5. package/dist/source/index.js +1 -0
  6. package/dist/source/index.js.map +1 -1
  7. package/dist/source/loader/ensure_datatype_extracted.js +25 -0
  8. package/dist/source/loader/ensure_datatype_extracted.js.map +1 -1
  9. package/dist/source/loader/generateAddressSpaceRaw.d.ts +2 -1
  10. package/dist/source/loader/generateAddressSpaceRaw.js +2 -2
  11. package/dist/source/loader/generateAddressSpaceRaw.js.map +1 -1
  12. package/dist/source/loader/load_nodeset2.d.ts +7 -3
  13. package/dist/source/loader/load_nodeset2.js +66 -31
  14. package/dist/source/loader/load_nodeset2.js.map +1 -1
  15. package/dist/source/xml_writer.d.ts +5 -0
  16. package/dist/src/base_node_private.js +5 -0
  17. package/dist/src/base_node_private.js.map +1 -1
  18. package/dist/src/index_current.d.ts +2 -1
  19. package/dist/src/index_current.js +3 -2
  20. package/dist/src/index_current.js.map +1 -1
  21. package/dist/src/namespace_impl.d.ts +2 -0
  22. package/dist/src/namespace_impl.js +11 -1
  23. package/dist/src/namespace_impl.js.map +1 -1
  24. package/dist/src/namespace_private.d.ts +1 -0
  25. package/dist/src/namespace_private.js.map +1 -1
  26. package/dist/src/nodeid_manager.d.ts +1 -0
  27. package/dist/src/nodeid_manager.js +14 -2
  28. package/dist/src/nodeid_manager.js.map +1 -1
  29. package/dist/src/nodeset_tools/dump_to_bsd.d.ts +2 -0
  30. package/dist/src/nodeset_tools/dump_to_bsd.js +164 -0
  31. package/dist/src/nodeset_tools/dump_to_bsd.js.map +1 -0
  32. package/dist/src/nodeset_tools/nodeset_to_xml.d.ts +9 -1
  33. package/dist/src/nodeset_tools/nodeset_to_xml.js +182 -87
  34. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  35. package/dist/src/tool_isSupertypeOf.js +12 -2
  36. package/dist/src/tool_isSupertypeOf.js.map +1 -1
  37. package/dist/src/ua_data_type_impl.js +10 -5
  38. package/dist/src/ua_data_type_impl.js.map +1 -1
  39. package/dist/src/ua_object_impl.js +8 -1
  40. package/dist/src/ua_object_impl.js.map +1 -1
  41. package/dist/src/ua_variable_impl.js +5 -1
  42. package/dist/src/ua_variable_impl.js.map +1 -1
  43. package/dist/src/ua_variable_impl_ext_obj.js +1 -1
  44. package/dist/src/ua_variable_impl_ext_obj.js.map +1 -1
  45. package/distHelpers/get_mini_address_space.js +1 -1
  46. package/distHelpers/get_mini_address_space.js.map +1 -1
  47. package/distNodeJS/generate_address_space.d.ts +3 -1
  48. package/distNodeJS/generate_address_space.js +13 -2
  49. package/distNodeJS/generate_address_space.js.map +1 -1
  50. package/package.json +38 -38
  51. package/source/continuation_points/continuation_point_manager.ts +13 -12
  52. package/source/index.ts +1 -0
  53. package/source/loader/ensure_datatype_extracted.ts +38 -3
  54. package/source/loader/generateAddressSpaceRaw.ts +4 -3
  55. package/source/loader/load_nodeset2.ts +86 -33
  56. package/source/xml_writer.ts +3 -0
  57. package/source_nodejs/generate_address_space.ts +27 -5
  58. package/src/base_node_private.ts +6 -0
  59. package/src/index_current.ts +3 -1
  60. package/src/namespace_impl.ts +24 -1
  61. package/src/namespace_private.ts +2 -0
  62. package/src/nodeid_manager.ts +14 -5
  63. package/src/nodeset_tools/{typedictionary_to_xml.ts → dump_to_bsd.ts} +24 -14
  64. package/src/nodeset_tools/nodeset_to_xml.ts +231 -74
  65. package/src/tool_isSupertypeOf.ts +14 -2
  66. package/src/ua_data_type_impl.ts +11 -7
  67. package/src/ua_object_impl.ts +12 -2
  68. package/src/ua_variable_impl.ts +9 -2
  69. package/src/ua_variable_impl_ext_obj.ts +1 -1
  70. package/test_helpers/get_mini_address_space.ts +1 -1
  71. package/test_helpers/test_fixtures/mini.Node.Set2.xml +29 -0
  72. package/test_helpers/test_fixtures/nodeset_no_aliases.xml +30 -0
  73. package/test_helpers/test_fixtures/nodeset_no_aliases_with_aliases.xml +31 -0
@@ -3,7 +3,7 @@ import { CallbackT } from "node-opcua-status-code";
3
3
  import { IAddressSpace } from "node-opcua-address-space-base";
4
4
 
5
5
  import { adjustNamespaceArray } from "../../src/nodeset_tools/adjust_namespace_array";
6
- import { NodeSetLoader } from "./load_nodeset2";
6
+ import { NodeSetLoader, NodeSetLoaderOptions } from "./load_nodeset2";
7
7
 
8
8
  const doDebug = checkDebugFlag(__filename);
9
9
  const debugLog = make_debugLog(__filename);
@@ -17,9 +17,10 @@ const errorLog = make_errorLog(__filename);
17
17
  export async function generateAddressSpaceRaw(
18
18
  addressSpace: IAddressSpace,
19
19
  xmlFiles: string | string[],
20
- xmlLoader: (nodeset2xmlUri: string) => Promise<string>
20
+ xmlLoader: (nodeset2xmlUri: string) => Promise<string>,
21
+ options: NodeSetLoaderOptions
21
22
  ): Promise<void> {
22
- const nodesetLoader = new NodeSetLoader(addressSpace);
23
+ const nodesetLoader = new NodeSetLoader(addressSpace, options);
23
24
 
24
25
  if (!Array.isArray(xmlFiles)) {
25
26
  xmlFiles = [xmlFiles];
@@ -110,7 +110,7 @@ function makeDefaultVariant(addressSpace: IAddressSpace, dataTypeNode: NodeId, v
110
110
  }
111
111
  const dv = builtInType.defaultValue;
112
112
  const value = typeof dv === "function" ? dv() : dv;
113
-
113
+
114
114
  let arrayType: VariantArrayType;
115
115
  /*
116
116
  * * n > 1 : the Value is an array with the specified number of dimensions.
@@ -145,11 +145,15 @@ export interface NodeSet2ParserEngine {
145
145
  terminate: (callback: SimpleCallback) => void;
146
146
  }
147
147
 
148
- export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2ParserEngine {
148
+ function makeNodeSetParserEngine(addressSpace: IAddressSpace, options: NodeSetLoaderOptions): NodeSet2ParserEngine {
149
149
  const addressSpace1 = addressSpace as AddressSpacePrivate;
150
150
  addressSpace1.suspendBackReference = true;
151
151
 
152
+ options.loadDeprecatedNodes = options.loadDeprecatedNodes === undefined ? true: options.loadDeprecatedNodes;
153
+ options.loadDraftNodes = options.loadDraftNodes || false;
154
+
152
155
  const postTasks: Task[] = [];
156
+ const postTasks0_InitializeVariable: Task[] = [];
153
157
  const postTasks0_DecodePojoString: Task[] = [];
154
158
  const postTasks1_InitializeVariable: Task[] = [];
155
159
  const postTasks2_AssignedExtensionObjectToDataValue: Task[] = [];
@@ -171,6 +175,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
171
175
  let namespaceCounter = 0;
172
176
  let found_namespace_in_uri: { [key: string]: NamespacePrivate } = {};
173
177
  let models: Model[] = [];
178
+ let performedCalled = false;
174
179
 
175
180
  function _reset_namespace_translation() {
176
181
  debugLog("_reset_namespace_translation");
@@ -179,6 +184,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
179
184
  namespaceCounter = 0;
180
185
  alias_map = {};
181
186
  models = [];
187
+ performedCalled = false;
182
188
  }
183
189
 
184
190
  function _translateNamespaceIndex(innerIndex: number) {
@@ -186,9 +192,9 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
186
192
 
187
193
  // istanbul ignore next
188
194
  if (namespaceIndex === undefined) {
189
- // tslint:disable-next-line: no-console
190
195
  debugLog("Warning: namespace_uri_translation = ", namespace_uri_translation);
191
- throw new Error("_translateNamespaceIndex! Cannot find namespace definition for index " + innerIndex);
196
+ errorLog("namespace_uri_translation", namespace_uri_translation);
197
+ throw new Error("_translateNamespaceIndex() ! Cannot find namespace definition for index " + innerIndex);
192
198
  }
193
199
  return namespaceIndex;
194
200
  }
@@ -213,9 +219,9 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
213
219
  return namespace.internalCreateNode(params) as BaseNode;
214
220
  }
215
221
 
216
- function _register_namespace_uri_in_translation_table(namespaceUri: string): NamespacePrivate {
222
+ function _register_namespace_uri_in_translation_table(namespaceUri: string): void {
217
223
  if (found_namespace_in_uri[namespaceUri]) {
218
- return found_namespace_in_uri[namespaceUri];
224
+ return;
219
225
  }
220
226
  const namespace = addressSpace1.getNamespace(namespaceUri);
221
227
  if (!namespace) {
@@ -240,7 +246,6 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
240
246
  " index in addressSpace",
241
247
  namespace.index
242
248
  );
243
- return namespace;
244
249
  }
245
250
 
246
251
  function _add_namespace(model: Model) {
@@ -384,6 +389,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
384
389
 
385
390
  const state_UAObject = {
386
391
  init(this: any, name: string, attrs: XmlAttributes) {
392
+ _perform();
393
+
387
394
  this.obj = {};
388
395
  this.obj.nodeClass = NodeClass.Object;
389
396
  this.obj.isAbstract = ec.coerceBoolean(attrs.IsAbstract);
@@ -393,12 +400,10 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
393
400
  this.obj.symbolicName = attrs.SymbolicName || null;
394
401
 
395
402
  this.isDraft = attrs.ReleaseStatus === "Draft";
396
- this.obj.isDeprecated = attrs.ReleaseStatus === "Deprecated";
403
+ this.isDeprecated = attrs.ReleaseStatus === "Deprecated";
397
404
  },
398
405
  finish(this: any) {
399
- if (this.isDraft || this.isDeprecated) {
400
- // ignore Draft or Deprecated element
401
- debugLog("Ignoring Draft/Deprecated UAObject =", this.obj.browseName.toString());
406
+ if (canIngore({ isDraft: this.isDraft, isDeprecated: this.isDeprecated }, this.obj)) {
402
407
  return;
403
408
  }
404
409
  _internal_createNode(this.obj);
@@ -422,6 +427,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
422
427
 
423
428
  const state_UAObjectType = {
424
429
  init(this: any, name: string, attrs: XmlAttributes) {
430
+ _perform();
431
+
425
432
  this.obj = {};
426
433
  this.obj.nodeClass = NodeClass.ObjectType;
427
434
  this.obj.isAbstract = ec.coerceBoolean(attrs.IsAbstract);
@@ -451,6 +458,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
451
458
 
452
459
  const state_UAReferenceType = {
453
460
  init(this: any, name: string, attrs: XmlAttributes) {
461
+ _perform();
462
+
454
463
  this.obj = {};
455
464
  this.obj.nodeClass = NodeClass.ReferenceType;
456
465
  this.obj.isAbstract = ec.coerceBoolean(attrs.IsAbstract);
@@ -486,6 +495,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
486
495
 
487
496
  const state_UADataType = {
488
497
  init(this: any, name: string, attrs: XmlAttributes) {
498
+ _perform();
499
+
489
500
  this.obj = {};
490
501
  this.obj.nodeClass = NodeClass.DataType;
491
502
  this.obj.isAbstract = ec.coerceBoolean(attrs.IsAbstract) || false;
@@ -501,9 +512,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
501
512
  this.definitionFields = [];
502
513
  },
503
514
  finish(this: any) {
504
- if (this.isDraft || this.isDeprecated) {
505
- // ignore Draft or Deprecated element
506
- debugLog("Ignoring Draft/Deprecated dataType =", this.obj.browseName.toString());
515
+ if (canIngore({ isDraft: this.isDraft, isDeprecated: this.isDeprecated }, this.obj)) {
507
516
  return;
508
517
  }
509
518
  /*
@@ -861,6 +870,14 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
861
870
  assert(self.extensionObject instanceof ExtensionObject);
862
871
  break;
863
872
  default: {
873
+ // istanbul ignore next
874
+ if (! this._cloneFragment) {
875
+ // the XML file is probably not exposing standard UA extension object correctly.
876
+ // this has been seen in some generated xml files using the dataType nodeId instead of the default encoding
877
+ // nodeid
878
+ errorLog("[NODE-OPCUA-E12] standard OPCUA Extension object from (namespace=0) has a invalid TypeId", self.typeDefinitionId.toString());
879
+ break;
880
+ }
864
881
  this.bodyXML = this._cloneFragment!.value;
865
882
  this._cloneFragment!.value = null;
866
883
 
@@ -1329,8 +1346,22 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1329
1346
  };
1330
1347
  postTasks2_AssignedExtensionObjectToDataValue.push(task);
1331
1348
  }
1349
+
1350
+ const canIngore = ({ isDraft, isDeprecated }: { isDraft: boolean; isDeprecated: boolean }, node: BaseNode) => {
1351
+ if (isDraft && !options.loadDraftNodes) {
1352
+ debugLog("Ignoring Draft =", NodeClass[node.nodeClass], node.browseName.toString());
1353
+ return true;
1354
+ }
1355
+ if (isDeprecated && !options.loadDeprecatedNodes) {
1356
+ debugLog("Ignoring Deprecate =", NodeClass[node.nodeClass], node.browseName.toString());
1357
+ return true;
1358
+ }
1359
+ return false;
1360
+ };
1332
1361
  const state_UAVariable = {
1333
1362
  init(this: any, name: string, attrs: XmlAttributes) {
1363
+ _perform();
1364
+
1334
1365
  this.obj = {};
1335
1366
 
1336
1367
  this.obj.nodeClass = NodeClass.Variable;
@@ -1354,10 +1385,10 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1354
1385
  this.isDeprecated = attrs.ReleaseStatus === "Deprecated";
1355
1386
  },
1356
1387
  finish(this: any) {
1357
- if (this.isDraft || this.isDeprecated) {
1358
- debugLog("Ignoring Draft/Deprecated UAVariable =", this.obj.browseName.toString());
1388
+ if (canIngore({ isDraft: this.isDraft, isDeprecated: this.isDeprecated }, this.obj)) {
1359
1389
  return;
1360
1390
  }
1391
+
1361
1392
  /*
1362
1393
  // set default value based on obj data Type
1363
1394
  if (this.obj.value === undefined) {
@@ -1378,7 +1409,14 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1378
1409
  capturedValue = undefined;
1379
1410
  (capturedVariable as any) = undefined;
1380
1411
  };
1381
- postTasks1_InitializeVariable.push(task);
1412
+ if (capturedValue.dataType !== DataType.ExtensionObject) {
1413
+ postTasks0_InitializeVariable.push(task);
1414
+ } else {
1415
+ // do them later
1416
+ postTasks1_InitializeVariable.push(task);
1417
+ }
1418
+
1419
+
1382
1420
  } else {
1383
1421
  const task = async (addressSpace2: IAddressSpace) => {
1384
1422
  const dataTypeNode = capturedVariable.dataType;
@@ -1396,7 +1434,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1396
1434
  }
1397
1435
  (capturedVariable as any) = undefined;
1398
1436
  };
1399
- postTasks1_InitializeVariable.push(task);
1437
+ postTasks0_InitializeVariable.push(task);
1400
1438
  }
1401
1439
  this.obj.value = undefined;
1402
1440
  capturedVariable = _internal_createNode(this.obj) as UAVariable;
@@ -1421,6 +1459,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1421
1459
 
1422
1460
  const state_UAVariableType = {
1423
1461
  init(this: any, name: string, attrs: XmlAttributes) {
1462
+ _perform();
1463
+
1424
1464
  this.obj = {};
1425
1465
  this.obj.isAbstract = ec.coerceBoolean(attrs.IsAbstract);
1426
1466
 
@@ -1441,8 +1481,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1441
1481
  this.isDeprecated = attrs.ReleaseStatus === "Deprecated";
1442
1482
  },
1443
1483
  finish(this: any) {
1444
- if (this.isDraft || this.isDeprecated) {
1445
- debugLog("Ignoring Draft/Deprecated UAVariableType =", this.obj.browseName.toString());
1484
+ if (canIngore({ isDraft: this.isDraft, isDeprecated: this.isDeprecated }, this.obj)) {
1446
1485
  return;
1447
1486
  }
1448
1487
  try {
@@ -1473,6 +1512,8 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1473
1512
 
1474
1513
  const state_UAMethod = {
1475
1514
  init(this: any, name: string, attrs: XmlAttributes) {
1515
+ _perform();
1516
+
1476
1517
  this.obj = {};
1477
1518
  this.obj.nodeClass = NodeClass.Method;
1478
1519
  // MethodDeclarationId
@@ -1486,8 +1527,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1486
1527
  this.isDeprecated = attrs.ReleaseStatus === "Deprecated";
1487
1528
  },
1488
1529
  finish(this: any) {
1489
- if (this.isDraft || this.isDeprecated) {
1490
- debugLog("Ignoring Draft/Deprecated UAMethod =", this.obj.browseName.toString());
1530
+ if (canIngore({ isDraft: this.isDraft, isDeprecated: this.isDeprecated }, this.obj)) {
1491
1531
  return;
1492
1532
  }
1493
1533
  _internal_createNode(this.obj);
@@ -1557,7 +1597,17 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1557
1597
  }
1558
1598
  });
1559
1599
 
1600
+ function _updateTranslationTable() {
1601
+ _register_namespace_uri_in_translation_table("http://opcfoundation.org/UA/");
1602
+ for (const namespaceUri of _namespaceUris) {
1603
+ _register_namespace_uri_in_translation_table(namespaceUri);
1604
+ }
1605
+ }
1606
+
1560
1607
  function _perform() {
1608
+ if (performedCalled) return;
1609
+ performedCalled = true;
1610
+
1561
1611
  /**special case for old nodeset file version 1.02 where no models exists */
1562
1612
  if (models.length === 0) {
1563
1613
  for (const namespaceuri of _namespaceUris) {
@@ -1573,13 +1623,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1573
1623
  });
1574
1624
  }
1575
1625
  }
1576
-
1577
- doDebug && debugLog("xxx models =", JSON.stringify(models, null, " "));
1578
- doDebug && debugLog("xxx _namespaceUris =", _namespaceUris);
1579
- _register_namespace_uri_in_translation_table("http://opcfoundation.org/UA/");
1580
- for (const namespaceUri of _namespaceUris) {
1581
- _register_namespace_uri_in_translation_table(namespaceUri);
1582
- }
1626
+ _updateTranslationTable();
1583
1627
  }
1584
1628
  // state_ModelTableEntry.parser["RequiredModel"] = state_ModelTableEntry;
1585
1629
  let _namespaceUris: string[] = [];
@@ -1681,6 +1725,9 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1681
1725
  doDebug && debugLog(chalk.bgGreenBright("Performing post loading tasks -------------------------------------------"));
1682
1726
  await performPostLoadingTasks(postTasks);
1683
1727
 
1728
+ doDebug && debugLog(chalk.bgGreenBright("Performing post loading task: Initializing Simple Variables ---------------------"));
1729
+ await performPostLoadingTasks(postTasks0_InitializeVariable);
1730
+
1684
1731
  doDebug && debugLog(chalk.bgGreenBright("Performing DataType extraction -------------------------------------------"));
1685
1732
  assert(!addressSpace1.suspendBackReference);
1686
1733
  await ensureDatatypeExtracted(addressSpace);
@@ -1700,7 +1747,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1700
1747
  doDebug && debugLog(chalk.bgGreenBright("Performing post loading task: Decoding Pojo String (parsing XML objects) -"));
1701
1748
  await performPostLoadingTasks(postTasks0_DecodePojoString);
1702
1749
 
1703
- doDebug && debugLog(chalk.bgGreenBright("Performing post loading task: Initializing Variables ---------------------"));
1750
+ doDebug && debugLog(chalk.bgGreenBright("Performing post loading task: Initializing Complex Variables ---------------------"));
1704
1751
  await performPostLoadingTasks(postTasks1_InitializeVariable);
1705
1752
 
1706
1753
  doDebug && debugLog(chalk.bgGreenBright("Performing post loading tasks: (assigning Extension Object to Variables) -"));
@@ -1726,10 +1773,16 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1726
1773
  terminate
1727
1774
  };
1728
1775
  }
1776
+
1777
+ export interface NodeSetLoaderOptions {
1778
+ loadDraftNodes?: boolean;
1779
+ loadDeprecatedNodes?: boolean;
1780
+ }
1781
+
1729
1782
  export class NodeSetLoader {
1730
- _s: any;
1731
- constructor(addressSpace: IAddressSpace) {
1732
- this._s = makeNodeSetParserEngine(addressSpace);
1783
+ _s: NodeSet2ParserEngine;
1784
+ constructor(addressSpace: IAddressSpace, private options?: NodeSetLoaderOptions) {
1785
+ this._s = makeNodeSetParserEngine(addressSpace, options || {});
1733
1786
  }
1734
1787
 
1735
1788
  addNodeSet(xmlData: string, callback: ErrorCallback): void {
@@ -2,6 +2,7 @@ export interface XmlWriter {
2
2
  translationTable: any;
3
3
  visitedNode: any;
4
4
 
5
+ startDocument(options: { encoding: string; version: string }): void;
5
6
  startElement(elementName: string): this;
6
7
 
7
8
  endElement(): this;
@@ -11,4 +12,6 @@ export interface XmlWriter {
11
12
  writeComment(comment: string): this;
12
13
 
13
14
  text(str: string): this;
15
+
16
+ endDocument(): void;
14
17
  }
@@ -1,11 +1,11 @@
1
1
  import * as fs from "fs";
2
- import { callbackify, promisify } from "util";
2
+ import { callbackify } from "util";
3
3
 
4
4
  import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
5
- import { ErrorCallback } from "node-opcua-status-code";
6
5
  import { IAddressSpace } from "node-opcua-address-space-base";
7
6
 
8
7
  import { generateAddressSpaceRaw } from "..";
8
+ import { NodeSetLoaderOptions } from "../source/loader/load_nodeset2";
9
9
  const doDebug = checkDebugFlag(__filename);
10
10
  const debugLog = make_debugLog(__filename);
11
11
  const errorLog = make_errorLog(__filename);
@@ -26,9 +26,31 @@ export function generateAddressSpace(
26
26
  xmlFiles: string | string[],
27
27
  callback: (err?: Error) => void
28
28
  ): void;
29
- export function generateAddressSpace(addressSpace: IAddressSpace, xmlFiles: string | string[]): Promise<void>;
30
- export function generateAddressSpace(addressSpace: IAddressSpace, xmlFiles: string | string[], callback?: ErrorCallback): any {
31
- callbackify(generateAddressSpaceRaw)(addressSpace, xmlFiles, readNodeSet2XmlFile, callback!);
29
+ export function generateAddressSpace(
30
+ addressSpace: IAddressSpace,
31
+ xmlFiles: string | string[],
32
+ options: NodeSetLoaderOptions | undefined,
33
+ callback: (err?: Error) => void
34
+ ): void;
35
+ export function generateAddressSpace(
36
+ addressSpace: IAddressSpace,
37
+ xmlFiles: string | string[],
38
+ options?: NodeSetLoaderOptions
39
+ ): Promise<void>;
40
+ export function generateAddressSpace(
41
+ ... args: any[]
42
+ ): any {
43
+ const addressSpace = args[0] as IAddressSpace;
44
+ const xmlFiles = args[1] as string | string[];
45
+ if (args.length === 4) {
46
+ const options = args[2] as NodeSetLoaderOptions | undefined;
47
+ const callback = args[3] as (err?: Error) => void;
48
+ callbackify(generateAddressSpaceRaw)(addressSpace, xmlFiles, readNodeSet2XmlFile, options ||{}, callback!);
49
+ } else {
50
+ const options = {};
51
+ const callback = args[2] as (err?: Error) => void;
52
+ callbackify(generateAddressSpaceRaw)(addressSpace, xmlFiles, readNodeSet2XmlFile, options, callback!);
53
+ }
32
54
  }
33
55
 
34
56
  // tslint:disable:no-var-requires
@@ -538,6 +538,12 @@ function _extractInterfaces2(typeDefinitionNode: UAObjectType | UAVariableType,
538
538
  }
539
539
 
540
540
  const addressSpace = typeDefinitionNode.addressSpace;
541
+
542
+ const hasInterfaceReference = addressSpace.findReferenceType("HasInterface");
543
+ if (!hasInterfaceReference) {
544
+ // this version of the standard UA namespace doesn't support Interface yet
545
+ return [];
546
+ }
541
547
  // example:
542
548
  // FolderType
543
549
  // FunctionalGroupType
@@ -13,6 +13,8 @@ export * from "../source/helpers/ensure_secure_access";
13
13
  export * from "../source/helpers/resolve_opaque_on_address_space";
14
14
  export * from "../source/interfaces/alarms_and_conditions/condition_info_i";
15
15
 
16
+ export * from "../src/nodeset_tools/construct_namespace_dependency";
17
+
16
18
 
17
19
  export * from "../source/set_namespace_meta_data";
18
20
  export * from "../source/namespace";
@@ -34,7 +36,7 @@ export * from "./event_data";
34
36
 
35
37
  export { NamespaceOptions } from "./nodeid_manager";
36
38
  export { dumpXml } from "./nodeset_tools/nodeset_to_xml";
37
- export { dumpToBSD } from "./nodeset_tools/typedictionary_to_xml";
39
+ export { dumpToBSD } from "./nodeset_tools/dump_to_bsd";
38
40
  export { adjustNamespaceArray } from "./nodeset_tools/adjust_namespace_array";
39
41
  export { makeAttributeEventName } from "./base_node_impl";
40
42
  export { resolveReferenceNode, resolveReferenceType } from "./reference_impl";
@@ -219,9 +219,13 @@ export class NamespaceImpl implements NamespacePrivate {
219
219
  public addressSpace: AddressSpacePrivate;
220
220
  public readonly index: number;
221
221
 
222
+ public emulateVersion103 = false;
223
+
222
224
  public version = "0.0.0";
223
225
  public publicationDate: Date = new Date(Date.UTC(1900, 0, 1));
224
226
 
227
+ public registerSymbolicNames = false;
228
+
225
229
  private _objectTypeMap: Map<string, UAObjectType>;
226
230
  private _variableTypeMap: Map<string, UAVariableType>;
227
231
  private _referenceTypeMap: Map<string, UAReferenceType>;
@@ -289,27 +293,35 @@ export class NamespaceImpl implements NamespacePrivate {
289
293
  public _objectTypeIterator(): IterableIterator<UAObjectType> {
290
294
  return this._objectTypeMap.values();
291
295
  }
296
+
292
297
  public _objectTypeCount(): number {
293
298
  return this._objectTypeMap.size;
294
299
  }
300
+
295
301
  public _variableTypeIterator(): IterableIterator<UAVariableType> {
296
302
  return this._variableTypeMap.values();
297
303
  }
304
+
298
305
  public _variableTypeCount(): number {
299
306
  return this._variableTypeMap.size;
300
307
  }
308
+
301
309
  public _dataTypeIterator(): IterableIterator<UADataType> {
302
310
  return this._dataTypeMap.values();
303
311
  }
312
+
304
313
  public _dataTypeCount(): number {
305
314
  return this._dataTypeMap.size;
306
315
  }
316
+
307
317
  public _referenceTypeIterator(): IterableIterator<UAReferenceType> {
308
318
  return this._referenceTypeMap.values();
309
319
  }
320
+
310
321
  public _referenceTypeCount(): number {
311
322
  return this._referenceTypeMap.size;
312
323
  }
324
+
313
325
  public _aliasCount(): number {
314
326
  return this._aliases.size;
315
327
  }
@@ -1627,7 +1639,10 @@ export class NamespaceImpl implements NamespacePrivate {
1627
1639
 
1628
1640
  // --- internal stuff
1629
1641
  public constructNodeId(options: ConstructNodeIdOptions): NodeId {
1630
- return this._nodeIdManager.constructNodeId(options);
1642
+ return this._nodeIdManager.constructNodeId({
1643
+ registerSymbolicNames: this.registerSymbolicNames,
1644
+ ...options
1645
+ });
1631
1646
  }
1632
1647
 
1633
1648
  public _register(node: BaseNode): void {
@@ -1943,6 +1958,14 @@ export class NamespaceImpl implements NamespacePrivate {
1943
1958
  }
1944
1959
  // ------------------------------------------ TypeDefinition
1945
1960
  let typeDefinition = options.typeDefinition || baseDataVariableTypeId;
1961
+ if (typeDefinition instanceof BaseNodeImpl) {
1962
+ // istanbul ignore next
1963
+ if (typeDefinition.nodeClass !== NodeClass.VariableType) {
1964
+ const message = `invalid typeDefinition expecting a VariableType got ${NodeClass[typeDefinition.nodeClass]}`;
1965
+ errorLog(message);
1966
+ throw new Error(message);
1967
+ }
1968
+ }
1946
1969
  typeDefinition = addressSpace._coerce_VariableTypeIds(typeDefinition);
1947
1970
  assert(typeDefinition instanceof NodeId);
1948
1971
 
@@ -33,6 +33,8 @@ export interface NamespacePrivate extends INamespace {
33
33
  internalCreateNode(options: CreateNodeOptions): BaseNode;
34
34
 
35
35
  _dataTypeIterator(): IterableIterator<UADataType>;
36
+
37
+ registerSymbolicNames: boolean;
36
38
  }
37
39
 
38
40
  export declare const NamespacePrivate: new (options: any) => NamespacePrivate;
@@ -1,3 +1,5 @@
1
+ /* eslint-disable max-depth */
2
+ /* eslint-disable max-statements */
1
3
  import { assert } from "node-opcua-assert";
2
4
  import { NodeClass, QualifiedName } from "node-opcua-data-model";
3
5
  import { makeNodeId, NodeId, NodeIdLike, NodeIdType, resolveNodeId, sameNodeId } from "node-opcua-nodeid";
@@ -50,6 +52,7 @@ export interface ConstructNodeIdOptions {
50
52
  browseName: QualifiedName;
51
53
  nodeClass: NodeClass;
52
54
  references?: UAReference[];
55
+ registerSymbolicNames?: boolean;
53
56
  }
54
57
  export type NodeEntry = [string, number, NodeClass];
55
58
  export type NodeEntry1 = [string, number, string /*"Object" | "Variable" etc...*/];
@@ -116,7 +119,6 @@ export class NodeIdManager {
116
119
 
117
120
  public constructNodeId(options: ConstructNodeIdOptions): NodeId {
118
121
  function prepareName(browseName: QualifiedName): string {
119
- assert(browseName instanceof QualifiedName);
120
122
  const m = browseName.name!.toString().replace(/[ ]/g, "").replace(/(<|>)/g, "");
121
123
  return m;
122
124
  }
@@ -124,10 +126,7 @@ export class NodeIdManager {
124
126
  const nodeClass = options.nodeClass;
125
127
 
126
128
  if (!nodeId) {
127
- // console.log("xx constructNodeId", options.browseName.toString());
128
-
129
129
  const parentInfo = this.findParentNodeId(options);
130
-
131
130
  if (parentInfo) {
132
131
  const [parentNodeId, linkName] = parentInfo;
133
132
  const name = prepareName(options.browseName);
@@ -148,6 +147,16 @@ export class NodeIdManager {
148
147
  } else {
149
148
  return this._getOrCreateFromName(newName, nodeClass);
150
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
+ }
151
160
  }
152
161
  }
153
162
  // }} has parent ...
@@ -228,4 +237,4 @@ export class NodeIdManager {
228
237
  return nodeIdResult;
229
238
  }
230
239
  }
231
- }
240
+ }
@@ -33,7 +33,7 @@ function buildXmlName(addressSpace: AddressSpacePrivate, map: { [key: number]: s
33
33
  throw new Error("Cannot find Node for" + nodeId?.toString());
34
34
  }
35
35
  const typeName = node.browseName.name!;
36
- const prefix = node.nodeId.namespace === 0 ? (node.nodeId.value <= 15 ? "opc" : "ua") : map[node.nodeId.namespace];
36
+ const prefix = node.nodeId.namespace === 0 ? (node.nodeId.value<= 15 ? "opc" : "ua") : map[node.nodeId.namespace];
37
37
  return prefix + ":" + (typeName === "Structure" && prefix === "ua" ? "ExtensionObject" : typeName);
38
38
  }
39
39
 
@@ -43,7 +43,7 @@ function dumpDataTypeStructure(
43
43
  addressSpace: IAddressSpace,
44
44
  map: { [key: number]: string },
45
45
  structureDefinition: StructureDefinition,
46
- structureDefinitionBase: StructureDefinition | undefined| null,
46
+ structureDefinitionBase: StructureDefinition | undefined | null,
47
47
  name: string,
48
48
  doc?: string
49
49
  ): void {
@@ -59,11 +59,11 @@ function dumpDataTypeStructure(
59
59
 
60
60
  const fields = structureDefinition.fields || [];
61
61
  // get base class
62
- const nbFieldsInBase = structureDefinitionBase? structureDefinitionBase.fields?.length || 0 : 0;
62
+ const nbFieldsInBase = structureDefinitionBase ? structureDefinitionBase.fields?.length || 0 : 0;
63
63
 
64
64
  let optionalsCount = 0;
65
- for (let index = nbFieldsInBase; index < fields.length; index ++) {
66
- const f= fields [index];
65
+ for (let index = nbFieldsInBase; index < fields.length; index++) {
66
+ const f = fields[index];
67
67
  if (f.isOptional) {
68
68
  xw.startElement("opc:Field");
69
69
  xw.writeAttribute("Name", f.name + "Specified");
@@ -96,9 +96,9 @@ function dumpDataTypeStructure(
96
96
  xw.endElement();
97
97
  }
98
98
  }
99
- for (let index = nbFieldsInBase; index < fields.length; index ++) {
100
- const f= fields [index];
101
-
99
+ for (let index = nbFieldsInBase; index < fields.length; index++) {
100
+ const f = fields[index];
101
+
102
102
  const isArray = f.valueRank > 0 && f.arrayDimensions?.length;
103
103
 
104
104
  if (isArray) {
@@ -145,27 +145,29 @@ function dumpDataTypeToBSD(xw: XmlWriter, dataType: UADataType, map: { [key: num
145
145
  function shortcut(namespace: INamespace) {
146
146
  return "n" + namespace.index;
147
147
  }
148
- export function dumpToBSD(namespace: NamespacePrivate): void {
148
+ export function dumpToBSD(namespace: NamespacePrivate): string {
149
149
  const dependency: INamespace[] = constructNamespaceDependency(namespace);
150
150
 
151
151
  const addressSpace = namespace.addressSpace;
152
152
 
153
- const xw = new XMLWriter(true);
153
+ const xw: XmlWriter = new XMLWriter(true);
154
154
 
155
- xw.startDocument({ encoding: "utf-8", version: "1.0" });
155
+ //xx xw.startDocument():// { encoding: "utf-8", version: "1.0" });
156
156
 
157
157
  xw.startElement("opc:TypeDictionary");
158
158
 
159
159
  xw.writeAttribute("xmlns:opc", "http://opcfoundation.org/BinarySchema/");
160
160
  xw.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
161
161
  xw.writeAttribute("xmlns:ua", "http://opcfoundation.org/UA/");
162
+ xw.writeAttribute("xmlns:tns", namespace.namespaceUri);
162
163
 
163
164
  const map: { [key: number]: string } = {};
165
+
166
+ map[namespace.index] = "tns";
164
167
 
165
168
  for (const dependantNamespace of dependency) {
166
169
  const namespaceIndex = dependantNamespace.index;
167
- if (namespaceIndex === 0) {
168
- //|| namespaceIndex === namespace.index) {
170
+ if (namespaceIndex === 0 || namespaceIndex === namespace.index) {
169
171
  continue;
170
172
  }
171
173
  const ns = shortcut(dependantNamespace);
@@ -176,11 +178,19 @@ export function dumpToBSD(namespace: NamespacePrivate): void {
176
178
  xw.writeAttribute("DefaultByteOrder", "LittleEndian");
177
179
  xw.writeAttribute("TargetNamespace", namespace.namespaceUri);
178
180
 
181
+ // <opc:Import Namespace="http://opcfoundation.org/UA/"/>
182
+ for (const dependantNamespace of dependency) {
183
+ if (dependantNamespace.index === namespace.index) {
184
+ continue;
185
+ }
186
+ xw.startElement("opc:Import").writeAttribute("Namespace", dependantNamespace.namespaceUri).endElement();
187
+ }
188
+ //
179
189
  for (const dataType of namespace._dataTypeIterator()) {
180
190
  dumpDataTypeToBSD(xw, dataType, map);
181
191
  }
182
192
  xw.endElement();
183
- xw.endDocument();
193
+ // xw.endDocument();
184
194
 
185
195
  return xw.toString();
186
196
  }