node-opcua-address-space 2.181.1 → 2.182.2

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 (121) hide show
  1. package/api/helpers/ensure_secure_access.ts +53 -2
  2. package/api/index.ts +30 -1
  3. package/api/loader/generateAddressSpaceRaw.ts +44 -139
  4. package/api/loader/load_nodeset2.ts +5 -0
  5. package/api/loader/narrow_instance_datatypes.ts +264 -0
  6. package/api/loader/nodeset_builtin_formats.ts +143 -0
  7. package/api/loader/nodeset_format.ts +153 -0
  8. package/api/loader/nodeset_image.ts +37 -4
  9. package/api/loader/nodeset_image_codec.ts +153 -34
  10. package/api/loader/nodeset_record.ts +26 -2
  11. package/api/loader/nodeset_record_applier.ts +54 -3
  12. package/api/loader/nodeset_records_to_xml.ts +620 -0
  13. package/api/loader/nodeset_source.ts +185 -26
  14. package/api/loader/nodeset_to_image.ts +16 -5
  15. package/api/loader/nodeset_xml_header.ts +119 -0
  16. package/api/loader/nodeset_xml_primitives.ts +209 -0
  17. package/api/loader/nodeset_xml_producer.ts +61 -2
  18. package/api/loader/parsers/variant_parser.ts +9 -0
  19. package/bin/nodeset_equivalence.js +750 -0
  20. package/bin/nodeset_tool_common.js +72 -0
  21. package/bin/opcua-nodeset-image.js +93 -103
  22. package/bin/opcua-nodeset-live.js +139 -0
  23. package/dist/api/helpers/ensure_secure_access.d.ts +20 -0
  24. package/dist/api/helpers/ensure_secure_access.js +39 -0
  25. package/dist/api/helpers/ensure_secure_access.js.map +1 -1
  26. package/dist/api/index.d.ts +7 -2
  27. package/dist/api/index.js +21 -1
  28. package/dist/api/index.js.map +1 -1
  29. package/dist/api/loader/generateAddressSpaceRaw.d.ts +1 -7
  30. package/dist/api/loader/generateAddressSpaceRaw.js +32 -125
  31. package/dist/api/loader/generateAddressSpaceRaw.js.map +1 -1
  32. package/dist/api/loader/load_nodeset2.js +4 -0
  33. package/dist/api/loader/load_nodeset2.js.map +1 -1
  34. package/dist/api/loader/narrow_instance_datatypes.d.ts +30 -0
  35. package/dist/api/loader/narrow_instance_datatypes.js +217 -0
  36. package/dist/api/loader/narrow_instance_datatypes.js.map +1 -0
  37. package/dist/api/loader/nodeset_builtin_formats.d.ts +27 -0
  38. package/dist/api/loader/nodeset_builtin_formats.js +133 -0
  39. package/dist/api/loader/nodeset_builtin_formats.js.map +1 -0
  40. package/dist/api/loader/nodeset_format.d.ts +123 -0
  41. package/dist/api/loader/nodeset_format.js +63 -0
  42. package/dist/api/loader/nodeset_format.js.map +1 -0
  43. package/dist/api/loader/nodeset_image.d.ts +17 -1
  44. package/dist/api/loader/nodeset_image.js +32 -4
  45. package/dist/api/loader/nodeset_image.js.map +1 -1
  46. package/dist/api/loader/nodeset_image_codec.d.ts +4 -0
  47. package/dist/api/loader/nodeset_image_codec.js +142 -53
  48. package/dist/api/loader/nodeset_image_codec.js.map +1 -1
  49. package/dist/api/loader/nodeset_record.d.ts +26 -2
  50. package/dist/api/loader/nodeset_record.js +11 -2
  51. package/dist/api/loader/nodeset_record.js.map +1 -1
  52. package/dist/api/loader/nodeset_record_applier.js +52 -3
  53. package/dist/api/loader/nodeset_record_applier.js.map +1 -1
  54. package/dist/api/loader/nodeset_records_to_xml.d.ts +16 -0
  55. package/dist/api/loader/nodeset_records_to_xml.js +536 -0
  56. package/dist/api/loader/nodeset_records_to_xml.js.map +1 -0
  57. package/dist/api/loader/nodeset_source.d.ts +68 -7
  58. package/dist/api/loader/nodeset_source.js +157 -20
  59. package/dist/api/loader/nodeset_source.js.map +1 -1
  60. package/dist/api/loader/nodeset_to_image.d.ts +4 -4
  61. package/dist/api/loader/nodeset_to_image.js +14 -4
  62. package/dist/api/loader/nodeset_to_image.js.map +1 -1
  63. package/dist/api/loader/nodeset_xml_header.d.ts +22 -0
  64. package/dist/api/loader/nodeset_xml_header.js +113 -0
  65. package/dist/api/loader/nodeset_xml_header.js.map +1 -0
  66. package/dist/api/loader/nodeset_xml_primitives.d.ts +37 -0
  67. package/dist/api/loader/nodeset_xml_primitives.js +196 -0
  68. package/dist/api/loader/nodeset_xml_primitives.js.map +1 -0
  69. package/dist/api/loader/nodeset_xml_producer.js +56 -1
  70. package/dist/api/loader/nodeset_xml_producer.js.map +1 -1
  71. package/dist/api/loader/parsers/variant_parser.js +7 -0
  72. package/dist/api/loader/parsers/variant_parser.js.map +1 -1
  73. package/dist/impl/_instantiate_helpers.js +1 -0
  74. package/dist/impl/_instantiate_helpers.js.map +1 -1
  75. package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js +4 -0
  76. package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
  77. package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js +14 -0
  78. package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js.map +1 -1
  79. package/dist/impl/base_node_impl.d.ts +9 -0
  80. package/dist/impl/base_node_impl.js +11 -0
  81. package/dist/impl/base_node_impl.js.map +1 -1
  82. package/dist/impl/base_node_private.js +67 -97
  83. package/dist/impl/base_node_private.js.map +1 -1
  84. package/dist/impl/nodeset_tools/construct_namespace_dependency.js +5 -1
  85. package/dist/impl/nodeset_tools/construct_namespace_dependency.js.map +1 -1
  86. package/dist/impl/nodeset_tools/nodeset_to_records.js +61 -15
  87. package/dist/impl/nodeset_tools/nodeset_to_records.js.map +1 -1
  88. package/dist/impl/nodeset_tools/nodeset_to_xml.d.ts +1 -8
  89. package/dist/impl/nodeset_tools/nodeset_to_xml.js +174 -190
  90. package/dist/impl/nodeset_tools/nodeset_to_xml.js.map +1 -1
  91. package/dist/impl/ua_data_type_impl.d.ts +21 -0
  92. package/dist/impl/ua_data_type_impl.js +27 -2
  93. package/dist/impl/ua_data_type_impl.js.map +1 -1
  94. package/dist/impl/ua_object_type_impl.d.ts +9 -0
  95. package/dist/impl/ua_object_type_impl.js +12 -1
  96. package/dist/impl/ua_object_type_impl.js.map +1 -1
  97. package/dist/impl/ua_variable_impl.js +27 -10
  98. package/dist/impl/ua_variable_impl.js.map +1 -1
  99. package/dist/impl/ua_variable_impl_ext_obj.js +19 -2
  100. package/dist/impl/ua_variable_impl_ext_obj.js.map +1 -1
  101. package/dist/impl/ua_variable_type_impl.d.ts +8 -1
  102. package/dist/impl/ua_variable_type_impl.js +39 -2
  103. package/dist/impl/ua_variable_type_impl.js.map +1 -1
  104. package/dist/tsconfig_base.tsbuildinfo +1 -1
  105. package/distNodeJS/generate_address_space.js +4 -0
  106. package/distNodeJS/generate_address_space.js.map +1 -1
  107. package/impl/_instantiate_helpers.ts +3 -0
  108. package/impl/alarms_and_conditions/ua_alarm_condition_impl.ts +10 -0
  109. package/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.ts +17 -0
  110. package/impl/base_node_impl.ts +15 -0
  111. package/impl/base_node_private.ts +97 -146
  112. package/impl/nodeset_tools/construct_namespace_dependency.ts +5 -1
  113. package/impl/nodeset_tools/nodeset_to_records.ts +66 -16
  114. package/impl/nodeset_tools/nodeset_to_xml.ts +127 -160
  115. package/impl/ua_data_type_impl.ts +40 -2
  116. package/impl/ua_object_type_impl.ts +16 -3
  117. package/impl/ua_variable_impl.ts +27 -10
  118. package/impl/ua_variable_impl_ext_obj.ts +20 -2
  119. package/impl/ua_variable_type_impl.ts +48 -2
  120. package/package.json +29 -27
  121. package/source_nodejs/generate_address_space.ts +7 -1
@@ -55,6 +55,10 @@ const nodeset_image_file_store_js_1 = require("./nodeset_image_file_store.js");
55
55
  // a 200 KB image, and in the thread pool, so that the XML hash runs alongside
56
56
  const gunzipAsync = (0, node_util_1.promisify)(node_zlib_1.gunzip);
57
57
  (0, index_js_1.setImageInflater)(async (image) => (await gunzipAsync(image)).toString("utf8"));
58
+ // and out through zlib at level 9: CompressionStream has no level to ask for, and an image is
59
+ // written once and read many times, so the extra work at build time is free at load time
60
+ const gzipAsync = (0, node_util_1.promisify)(node_zlib_1.gzip);
61
+ (0, index_js_1.setImageDeflater)(async (text) => new Uint8Array(await gzipAsync(Buffer.from(text, "utf8"), { level: 9 })));
58
62
  const _doDebug = (0, node_opcua_debug_1.checkDebugFlag)("generate_address_space");
59
63
  const debugLog = (0, node_opcua_debug_1.make_debugLog)("generate_address_space");
60
64
  const errorLog = (0, node_opcua_debug_1.make_errorLog)("generate_address_space");
@@ -1 +1 @@
1
- {"version":3,"file":"generate_address_space.js","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate_address_space.js","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import {
6
6
  CloneHelper,
7
7
  reconstructFunctionalGroupType,
8
8
  reconstructNonHierarchicalReferences,
9
+ reconstructSharedHierarchicalReferences,
9
10
  type UAMethod,
10
11
  type UAObject,
11
12
  type UAObjectType,
@@ -153,6 +154,8 @@ export function initialize_properties_and_components<
153
154
  reconstructFunctionalGroupType(extraInfo);
154
155
 
155
156
  reconstructNonHierarchicalReferences(extraInfo);
157
+
158
+ reconstructSharedHierarchicalReferences(extraInfo);
156
159
  }
157
160
 
158
161
  function instantiate_interface_children<B extends UAObject | UAVariable | UAMethod>(
@@ -76,6 +76,16 @@ export class UAAlarmConditionImplBase extends UAAcknowledgeableConditionImplBase
76
76
  }
77
77
 
78
78
  options.optionals = options.optionals || [];
79
+ // ActiveState is a TwoStateVariable whose texts and transition times an alarm client
80
+ // expects, as UAConditionImpl requests them for EnabledState. A subtype that re-declares
81
+ // ActiveState with only Id (ExclusiveLimitAlarmType does) would otherwise get only Id.
82
+ options.optionals.push(
83
+ "ActiveState.TrueState",
84
+ "ActiveState.FalseState",
85
+ "ActiveState.TransitionTime",
86
+ "ActiveState.EffectiveTransitionTime",
87
+ "ActiveState.EffectiveDisplayName"
88
+ );
79
89
  if (Object.hasOwn(options, "maxTimeShelved")) {
80
90
  options.optionals.push("MaxTimeShelved");
81
91
  assert(Number.isFinite(options.maxTimeShelved));
@@ -72,6 +72,23 @@ class UACertificateExpirationAlarmImplBase extends UASystemOffNormalAlarmImpl im
72
72
  }
73
73
 
74
74
  public updateAlarmState2(isActive: boolean, severity: number, message: string) {
75
+ // A Condition reports its state *changes* (Part 9 5.5.2). This alarm is re-evaluated on
76
+ // timers - its own every half hour, push certificate management every minute - and a
77
+ // re-evaluation that finds the same verdict must stay silent: it used to raise a new
78
+ // "certificate ... is OK!" event on the Server object at every check, an unsolicited
79
+ // event every minute on any server with push certificate management installed (FEAT-24:
80
+ // CTT Subscription Minimum 02 020 subscribes to the Server events and expects none while
81
+ // it only writes to plain variables).
82
+ const branch = this.currentBranch();
83
+ if (
84
+ branch &&
85
+ branch.getActiveState() === isActive &&
86
+ branch.getSeverity() === severity &&
87
+ (branch.getMessage()?.text || "") === message
88
+ ) {
89
+ return;
90
+ }
91
+
75
92
  isActive ? this.activateAlarm() : this.deactivateAlarm();
76
93
 
77
94
  this.raiseNewCondition({
@@ -176,6 +176,10 @@ export interface InternalBaseNodeOptions {
176
176
  */
177
177
  accessRestrictions?: AccessRestrictionsFlag;
178
178
  rolePermissions?: RolePermissionTypeOptions[];
179
+ /** "Draft" or "Deprecated" as the nodeset declared it; see BaseNode.releaseStatus */
180
+ releaseStatus?: "Draft" | "Deprecated";
181
+ /** the AccessRestrictions as declared, whatever this loader applies; see BaseNode */
182
+ declaredAccessRestrictions?: string;
179
183
  }
180
184
 
181
185
  function _is_valid_BrowseDirection(browseDirection: BrowseDirection) {
@@ -216,6 +220,11 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
216
220
  return makeAttributeEventName(attributeId);
217
221
  }
218
222
 
223
+ /** see BaseNode.releaseStatus; only set when the nodeset declared one, so that it costs
224
+ * nothing on the overwhelming majority of nodes, which are Released */
225
+ public releaseStatus?: "Draft" | "Deprecated";
226
+ /** see BaseNode.declaredAccessRestrictions */
227
+ public declaredAccessRestrictions?: string;
219
228
  private _accessRestrictions?: AccessRestrictionsFlag;
220
229
  private _rolePermissions?: RolePermissionType[];
221
230
 
@@ -431,6 +440,12 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
431
440
 
432
441
  this._accessRestrictions = options.accessRestrictions;
433
442
  this._rolePermissions = coerceRolePermissions(options.rolePermissions);
443
+ if (options.releaseStatus) {
444
+ this.releaseStatus = options.releaseStatus;
445
+ }
446
+ if (options.declaredAccessRestrictions !== undefined) {
447
+ this.declaredAccessRestrictions = options.declaredAccessRestrictions;
448
+ }
434
449
 
435
450
  // make `parent.<thisName>` resolve to this node: through a getter shared by every node when
436
451
  // a nodeset is loading (defined in one batch by the loader, see flushSharedChildAccessors),
@@ -30,6 +30,7 @@ import {
30
30
  type LocalizedText,
31
31
  type LocalizedTextLike,
32
32
  NodeClass,
33
+ type QualifiedName,
33
34
  ResultMask
34
35
  } from "node-opcua-data-model";
35
36
  import type { DataValue } from "node-opcua-data-value";
@@ -516,7 +517,7 @@ export function VariableOrVariableType_toString(this: UAVariableType | UAVariabl
516
517
  }
517
518
 
518
519
  /**
519
- *
520
+ * A subtype (or an instance) may re-declare a child that its base type already declares:
520
521
  *
521
522
  * MyDeriveType ------------------- -> MyBaseType --------------> TopologyElementType
522
523
  * | | |
@@ -525,137 +526,71 @@ export function VariableOrVariableType_toString(this: UAVariableType | UAVariabl
525
526
  * +- Foo1 |
526
527
  * +- Bar
527
528
  *
528
- * Instance
529
- *
530
- * @param newParent
531
- * @param node
532
- * @param copyAlsoModellingRules
533
- * @param optionalFilter
534
- * @param extraInfo
535
- * @param browseNameMap
536
- * @returns
529
+ * The instance gets ONE ParameterSet, cloned from the nearest declaration (Foo1), into which the
530
+ * base declarations are merged (Bar): see _base_declarations_of and _merge_base_declaration.
537
531
  */
538
- function _clone_children_on_template(
539
- nodeToClone: UAObject | UAVariable | UAMethod | UAObjectType | UAVariableType,
540
- newParent: BaseNode,
541
- node: BaseNode,
542
- copyAlsoModellingRules: boolean,
543
- optionalFilter: CloneFilter,
544
- extraInfo: CloneExtraInfo
545
- ) {
546
- /**
547
- * the type definition node of the node to clone
548
- */
549
- const nodeToCloneTypeDefinition =
550
- nodeToClone.nodeClass === NodeClass.ObjectType || nodeToClone.nodeClass === NodeClass.VariableType
551
- ? nodeToClone.subtypeOfObj
552
- : null;
553
- if (!nodeToCloneTypeDefinition) return;
554
-
555
- // c8 ignore next
556
- doTrace &&
557
- traceLog(
558
- extraInfo?.pad(),
559
- chalk.gray(
560
- "-------------------- now cloning children on template ",
561
- node.browseName.toString(),
562
- node.nodeId.toString(),
563
- nodeToCloneTypeDefinition.browseName.toString()
564
- )
565
- );
566
-
567
- const namespace = newParent.namespace;
568
-
569
- /**
570
- * the child node of the new parent that match the node to clone or enrich
571
- */
572
- const newParentChild = newParent.getChildByName(node.browseName);
573
- if (!newParentChild) {
574
- return;
532
+ /**
533
+ * the declarations, on the supertypes of `type`, of the child that `type` declares under
534
+ * `browseName`, nearest supertype first; none when `type` is not a type
535
+ */
536
+ function _base_declarations_of(type: BaseNode, browseName: QualifiedName): BaseNode[] {
537
+ if (type.nodeClass !== NodeClass.ObjectType && type.nodeClass !== NodeClass.VariableType) {
538
+ return [];
575
539
  }
576
- // we have found a matching child on the new parent.
577
- // the mission is to enrich this child node with components and properties that
578
- // exist also in the template
579
-
580
- let typeDefinitionNode: UAVariableType | UAObjectType | null = nodeToCloneTypeDefinition;
581
- while (typeDefinitionNode) {
582
- // c8 ignore next
583
- doTrace &&
584
- traceLog(
585
- extraInfo?.pad(),
586
- chalk.green(
587
- "-------------------- now cloning children on ",
588
- newParentChild.browseName.toString(),
589
- newParentChild.nodeId.toString(),
590
- " (child of ",
591
- node.browseName.toString(),
592
- node.nodeId.toString(),
593
- ") from ",
594
- typeDefinitionNode.browseName.toString()
595
- )
596
- );
597
-
598
- // Find aggregates with same browseName as node. Do not search children as this includes nodes with HasSubType relation which we do
599
- // not want. See issue #1326.
600
- const aggregates = typeDefinitionNode.getAggregates().filter((n) => n.browseName.equals(node.browseName));
601
- const typeDefinitionChild = aggregates.length > 0 ? aggregates[0] : null;
602
- if (typeDefinitionChild) {
603
- const references = typeDefinitionChild.findReferencesEx("Aggregates", BrowseDirection.Forward);
604
-
605
- for (const ref of references) {
606
- const grandChild = ref.node as UAVariable | UAObject | UAMethod;
607
- if (grandChild.modellingRule === "MandatoryPlaceholder" || grandChild.modellingRule === "OptionalPlaceholder")
608
- continue;
609
- // if not already node present in new Parent => just ignore
610
- const hasAlready = newParentChild.getChildByName(grandChild.browseName) !== null;
611
- if (!hasAlready) {
612
- if (optionalFilter && node && !optionalFilter.shouldKeep(node)) {
613
- // c8 ignore next
614
- doTrace &&
615
- traceLog(
616
- extraInfo.pad(),
617
- "skipping optional ",
618
- node.browseName.toString(),
619
- "that doesn't appear in the filter"
620
- );
621
- continue; // skip this node
622
- }
623
-
624
- const options = {
625
- namespace,
626
- references: [
627
- new ReferenceImpl({
628
- referenceType: ref.referenceType,
629
- isForward: false,
630
- nodeId: newParentChild.nodeId
631
- })
632
- ],
633
- copyAlsoModellingRules
634
- };
635
-
636
- const alreadyCloned = extraInfo.getCloned({
637
- originalParent: nodeToClone,
638
- clonedParent: newParent,
639
- originalNode: grandChild
640
- });
641
- if (alreadyCloned) {
642
- alreadyCloned.addReference({
643
- referenceType: ref.referenceType,
644
- isForward: false,
645
- nodeId: newParentChild.nodeId
646
- });
647
- } else {
648
- const clonedGrandChild = grandChild.clone(options, optionalFilter, extraInfo);
649
- extraInfo.registerClonedObject({
650
- originalNode: grandChild,
651
- clonedNode: clonedGrandChild
652
- });
653
- }
654
- }
655
- }
540
+ const result: BaseNode[] = [];
541
+ let base = (type as UAObjectType | UAVariableType).subtypeOfObj;
542
+ while (base) {
543
+ // aggregates only: a child lookup would also follow HasSubtype (issue #1326)
544
+ const declaration = base.getAggregates().find((n) => n.browseName.equals(browseName));
545
+ if (declaration) {
546
+ result.push(declaration);
656
547
  }
657
- typeDefinitionNode = typeDefinitionNode.subtypeOfObj;
548
+ base = base.subtypeOfObj;
658
549
  }
550
+ return result;
551
+ }
552
+
553
+ /**
554
+ * record `cloned` as the clone of `original` and, by browse name, each child the clone already
555
+ * has as the clone of the matching child of `original`, recursively: a later reference to any
556
+ * of them then lands on the existing node instead of a second copy
557
+ */
558
+ function _register_existing_children(original: BaseNode, cloned: BaseNode, extraInfo: CloneExtraInfo): void {
559
+ extraInfo.registerClonedObject({ originalNode: original, clonedNode: cloned });
560
+ for (const ref of original.findReferencesEx("Aggregates", BrowseDirection.Forward)) {
561
+ const child = ref.node;
562
+ if (!child) continue;
563
+ const existing = cloned.getChildByName(child.browseName);
564
+ if (!existing) continue;
565
+ _register_existing_children(child, existing, extraInfo);
566
+ }
567
+ }
568
+
569
+ /**
570
+ * `clonedNode` was cloned from a declaration that shadows `baseDeclaration` (a subtype or an
571
+ * instance re-declaring a child of a base type). What the clone already has is recorded as the
572
+ * clone of the base declaration's same-named children; what the base declaration adds is cloned
573
+ * in, subject to the same filter and the same browse-name guard as the clone's own children.
574
+ */
575
+ function _merge_base_declaration(
576
+ baseDeclaration: BaseNode,
577
+ clonedNode: BaseNode,
578
+ copyAlsoModellingRules: boolean,
579
+ optionalFilter: CloneFilter,
580
+ extraInfo: CloneExtraInfo,
581
+ browseNameMap: Set<string>
582
+ ): void {
583
+ // c8 ignore next
584
+ doTrace && traceLog(extraInfo.pad(), "merging base declaration ", fullPath2(baseDeclaration), " into ", fullPath2(clonedNode));
585
+ _register_existing_children(baseDeclaration, clonedNode, extraInfo);
586
+ _clone_hierarchical_references(
587
+ baseDeclaration as UAObject | UAVariable | UAMethod,
588
+ clonedNode as UAObject | UAVariable | UAMethod,
589
+ copyAlsoModellingRules,
590
+ optionalFilter,
591
+ extraInfo,
592
+ browseNameMap
593
+ );
659
594
  }
660
595
 
661
596
  /*
@@ -707,27 +642,31 @@ function _clone_collection_new(
707
642
  }
708
643
  const key = `${newParent.nodeId.toString()}(${newParent.browseName.toString()})/${node.browseName.toString()}`;
709
644
  if (browseNameMap?.has(key)) {
710
- _clone_children_on_template(nodeToClone, newParent, node, copyAlsoModellingRules, optionalFilter, extraInfo);
711
- doTrace &&
712
- traceLog(
713
- extraInfo.pad(),
714
- "skipping required node with same browseName",
715
- fullPath2(node),
716
- "because it has already been cloned",
717
- "key=",
718
- key
645
+ // a same-named child was cloned already, from a nearer declaration: this one is a
646
+ // base declaration of it, merge what it adds
647
+ doTrace && traceLog(extraInfo.pad(), "node with same browseName already cloned, merging", fullPath2(node), "key=", key);
648
+ const existing = newParent.getChildByName(node.browseName);
649
+ if (existing) {
650
+ _merge_base_declaration(
651
+ node,
652
+ existing,
653
+ copyAlsoModellingRules,
654
+ optionalFilter.filterFor(existing as UAObject | UAVariable | UAMethod),
655
+ extraInfo,
656
+ new Set<string>()
719
657
  );
720
-
658
+ }
721
659
  continue; // skipping node with same browseName
722
660
  }
723
661
  browseNameMap?.add(key);
724
662
 
725
663
  // assert(reference.isForward);
726
664
  // assert(reference.referenceType instanceof NodeId, "" + reference.referenceType.toString());
727
- const options = {
665
+ const options: CloneOptions = {
728
666
  namespace,
729
667
  references: [new ReferenceImpl({ referenceType: reference.referenceType, isForward: false, nodeId: newParent.nodeId })],
730
- copyAlsoModellingRules
668
+ copyAlsoModellingRules,
669
+ baseDeclarations: _base_declarations_of(nodeToClone, node.browseName)
731
670
  };
732
671
 
733
672
  const alreadyCloned = extraInfo.getCloned({ originalParent: nodeToClone, clonedParent: newParent, originalNode: node });
@@ -746,8 +685,10 @@ function _clone_collection_new(
746
685
  fullPath2(newParent)
747
686
  );
748
687
 
749
- const hasReference =
750
- alreadyCloned.findReferencesExAsObject(reference.referenceType, BrowseDirection.Inverse).length > 0;
688
+ // this parent, not any parent: a shared child may already hang under another one
689
+ const hasReference = alreadyCloned
690
+ .findReferences(reference.referenceType, false)
691
+ .some((r) => sameNodeId(r.nodeId, newParent.nodeId));
751
692
  if (!hasReference) {
752
693
  alreadyCloned.addReference({
753
694
  referenceType: reference.referenceType,
@@ -791,10 +732,6 @@ function _clone_collection_new(
791
732
  `${fullPath2(clonedNode)}`
792
733
  );
793
734
 
794
- extraInfo.level++;
795
- _clone_children_on_template(nodeToClone, newParent, node, copyAlsoModellingRules, optionalFilter, extraInfo);
796
- extraInfo.level--;
797
-
798
735
  // also clone or instantiate interface members that may be required in the optionals
799
736
  extraInfo.level++;
800
737
  _cloneInterface(nodeToClone, newParent, node, optionalFilter, extraInfo, browseNameMap);
@@ -1123,6 +1060,20 @@ export function _clone<T extends UAObject | UAVariable | UAMethod, O>(
1123
1060
  browseNameMap
1124
1061
  );
1125
1062
 
1063
+ // what the base types declare under the same name, before the type definition is explored:
1064
+ // the base declaration overrides the type definition's children, so the later walk of the
1065
+ // type definition finds them present instead of cloning them a second time
1066
+ for (const baseDeclaration of options.baseDeclarations || []) {
1067
+ _merge_base_declaration(
1068
+ baseDeclaration,
1069
+ clonedNode,
1070
+ options.copyAlsoModellingRules,
1071
+ newFilter,
1072
+ extraInfo,
1073
+ browseNameMap
1074
+ );
1075
+ }
1076
+
1126
1077
  if (originalNode.nodeClass === NodeClass.Object || originalNode.nodeClass === NodeClass.Variable) {
1127
1078
  let typeDefinitionNode: UAVariableType | UAObjectType | null = originalNode.typeDefinitionObj;
1128
1079
 
@@ -367,7 +367,11 @@ export function _constructNamespaceTranslationTable(dependency: INamespace[], ex
367
367
  let counter = 0;
368
368
  translationTable.set(dependency[0].index, counter++);
369
369
  //
370
- if (exportedNamespace) {
370
+ // the exported namespace goes next, at 1 -- unless it *is* the UA namespace, which the line
371
+ // above has already placed at 0. Overwriting it there sent every ns0 id to ns=1, an index the
372
+ // <NamespaceUris> of such a document never declares, which is why exporting the UA namespace
373
+ // used to produce a document that could not be loaded back
374
+ if (exportedNamespace && !translationTable.has(exportedNamespace.index)) {
371
375
  translationTable.set(exportedNamespace.index, counter++);
372
376
  }
373
377
  for (let i = 1; i < dependency.length; i++) {
@@ -75,7 +75,6 @@ import {
75
75
  } from "./construct_namespace_dependency.js";
76
76
  import {
77
77
  _dumpVariantExtensionObjectValue_Body,
78
- _isDefaultValue,
79
78
  coerceInt64ToInt32,
80
79
  initXmlWriterEx,
81
80
  makeTypeXsd,
@@ -362,6 +361,9 @@ class RecordExporter {
362
361
  browseName: this.tq(node.browseName),
363
362
  references: this.referencesOf(node)
364
363
  };
364
+ if (node.releaseStatus) {
365
+ record.releaseStatus = node.releaseStatus;
366
+ }
365
367
  const parentNode = this.parentOf(node);
366
368
  if (parentNode && parentNode.nodeId.namespace <= node.nodeId.namespace) {
367
369
  record.parentNodeId = this.t(parentNode.nodeId);
@@ -380,7 +382,10 @@ class RecordExporter {
380
382
  record.userAccessLevel = variable.userAccessLevel.toString();
381
383
  }
382
384
  }
383
- if (node.accessRestrictions !== undefined) record.accessRestrictions = node.accessRestrictions.toString();
385
+ // the declared spelling first: the loader's accessRestrictions option governs what is
386
+ // enforced, not what the document said, and only the latter belongs in an export
387
+ const accessRestrictions = node.declaredAccessRestrictions ?? node.accessRestrictions?.toString();
388
+ if (accessRestrictions !== undefined) record.accessRestrictions = accessRestrictions;
384
389
  if (node.rolePermissions !== undefined && node.rolePermissions.length === 0) record.hasNoPermissions = true;
385
390
  if (Object.hasOwn(node, "minimumSamplingInterval")) {
386
391
  const minimumSamplingInterval = (node as UAVariable).minimumSamplingInterval;
@@ -517,6 +522,25 @@ class RecordExporter {
517
522
  /** the fields as the XML loader's definition parser shapes them: an absent rank is -1, an absent type BaseDataType */
518
523
  private definitionOf(node: UADataType): NodesetDataTypeDefinitionRecord | undefined {
519
524
  const baseDataType = this.t(resolveNodeId(DataTypeIds.BaseDataType));
525
+ // an OptionSet is neither an enumeration nor a structure to node-opcua -- it is a plain
526
+ // UInt16 or UInt32 subtype -- so the only account of it is the one the loader kept
527
+ const asImpl = node as unknown as {
528
+ isOptionSetDataType?: boolean;
529
+ declaredDefinitionFields?: NodesetDefinitionField[];
530
+ declaredDefinitionName?: string;
531
+ };
532
+ // what the document called this definition, or -- for a DataType built here, which never
533
+ // had a declaration -- the browse name, which is the only name available
534
+ const definitionName = asImpl.declaredDefinitionName ?? this.b(node.browseName);
535
+ if (asImpl.isOptionSetDataType && asImpl.declaredDefinitionFields) {
536
+ const fields = asImpl.declaredDefinitionFields.map((f) => {
537
+ const field: NodesetDefinitionField = { ...f, allowSubTypes: f.allowSubTypes ?? false };
538
+ field.valueRank = f.valueRank ?? -1;
539
+ field.dataType = f.dataType ? this.t(f.dataType as unknown as NodeId) : baseDataType;
540
+ return field;
541
+ });
542
+ return { name: definitionName, isOptionSet: true, fields };
543
+ }
520
544
  if (node.isEnumeration()) {
521
545
  const enumDefinition = node.getEnumDefinition();
522
546
  const fields: NodesetDefinitionField[] = (enumDefinition.fields || []).map((f) => {
@@ -527,29 +551,38 @@ class RecordExporter {
527
551
  field.dataType = baseDataType;
528
552
  return field;
529
553
  });
530
- return { name: this.b(node.browseName), fields };
554
+ return { name: definitionName, fields };
531
555
  }
532
556
  if (node.isStructure()) {
533
557
  const definition = node.getStructureDefinition();
534
- const base = node.subtypeOfObj ? (node.subtypeOfObj as UADataType).getStructureDefinition() : null;
558
+ // a structure's supertype need not be a structure: `Structure` itself subtypes BaseDataType,
559
+ // which has no definition at all. Asking it for one threw, and took the whole export with it
560
+ const baseNode = node.subtypeOfObj as UADataType | null;
561
+ const base = baseNode?.isStructure() ? baseNode.getStructureDefinition() : null;
535
562
  const nbFieldsInBase = base ? base.fields?.length || 0 : 0;
563
+ // Part 3 8.51: in a *WithSubtypedValues structure, isOptional does not mean optional --
564
+ // it is where "subtyping allowed" is held. The document spells that AllowSubTypes, and
565
+ // says nothing about IsOptional there, so the two must be swapped back on the way out
566
+ const subtypedValues =
567
+ definition.structureType === StructureType.StructureWithSubtypedValues ||
568
+ definition.structureType === StructureType.UnionWithSubtypedValues;
536
569
  const fields: NodesetDefinitionField[] = [];
537
570
  const all = definition.fields || [];
538
571
  for (let index = nbFieldsInBase; index < all.length; index++) {
539
572
  const f = all[index];
540
573
  const field: NodesetDefinitionField = {
541
574
  name: f.name as string,
542
- allowSubTypes: !!(f as unknown as { allowSubTypes?: boolean }).allowSubTypes
575
+ allowSubTypes: subtypedValues ? !!f.isOptional : !!(f as unknown as { allowSubTypes?: boolean }).allowSubTypes
543
576
  };
544
577
  if (f.description?.text?.length) field.description = { text: f.description.text } as unknown as string;
545
578
  field.valueRank = f.valueRank === undefined || f.valueRank === -1 ? -1 : f.valueRank;
546
579
  if (f.arrayDimensions && f.arrayDimensions.length > 0) field.arrayDimensions = f.arrayDimensions;
547
- if (f.isOptional) field.isOptional = f.isOptional;
580
+ if (f.isOptional && !subtypedValues) field.isOptional = f.isOptional;
548
581
  if (f.maxStringLength !== undefined && f.maxStringLength !== 0) field.maxStringLength = f.maxStringLength;
549
582
  field.dataType = f.dataType && !f.dataType.isEmpty() ? this.t(f.dataType) : baseDataType;
550
583
  fields.push(field);
551
584
  }
552
- const record: NodesetDataTypeDefinitionRecord = { name: this.b(node.browseName), fields };
585
+ const record: NodesetDataTypeDefinitionRecord = { name: definitionName, fields };
553
586
  if (definition.structureType === StructureType.Union) record.isUnion = true;
554
587
  return record;
555
588
  }
@@ -565,7 +598,10 @@ class RecordExporter {
565
598
  this.arrayDimensionsOf(node, record);
566
599
  if (this.addressSpace.findNode(node.dataType)) record.dataType = this.t(node.dataType);
567
600
  const dataValue = (node as UAVariableImpl).$dataValue;
568
- if (dataValue?.value && !dataValue.statusCode.equals(StatusCodes.BadWaitingForInitialData)) {
601
+ // a value the loader made up for a variable the document left unvalued is not the document's
602
+ // to write back; see valueWasSynthesized in nodeset_record_applier
603
+ const synthesized = (node as unknown as { valueWasSynthesized?: boolean }).valueWasSynthesized;
604
+ if (dataValue?.value && !synthesized && !dataValue.statusCode.equals(StatusCodes.BadWaitingForInitialData)) {
569
605
  const value = this.valueOf(node, dataValue.value);
570
606
  if (value) record.value = value;
571
607
  }
@@ -590,8 +626,14 @@ class RecordExporter {
590
626
  }
591
627
 
592
628
  private arrayDimensionsOf(node: UAVariable | UAVariableType, record: NodesetNodeRecord): void {
593
- if (!node.arrayDimensions) return;
594
- if (node.valueRank === -1 || (node.arrayDimensions.length === 1 && node.arrayDimensions[0] === 0)) return;
629
+ // ArrayDimensions="0" is written only when the document declared it: node-opcua synthesizes [0]
630
+ // on the variables it generates, so writing it unconditionally would invent the attribute on
631
+ // every generated node. See arrayDimensionsWereDeclared in nodeset_record_applier
632
+ if (!node.arrayDimensions || node.valueRank <= 0) return;
633
+ // all-zero dimensions are what node-opcua synthesizes when nobody declared any, at whatever
634
+ // rank: [0] for a one-dimensional value, [0,0] for a matrix
635
+ const degenerate = node.arrayDimensions.every((d) => d === 0);
636
+ if (degenerate && !(node as unknown as { arrayDimensionsWereDeclared?: boolean }).arrayDimensionsWereDeclared) return;
595
637
  record.arrayDimensions = node.arrayDimensions;
596
638
  }
597
639
 
@@ -605,7 +647,9 @@ class RecordExporter {
605
647
  this.markVisited(node);
606
648
  this.dumpReferencedNodes(node);
607
649
  const record = this.common(node);
608
- if (node.eventNotifier) record.eventNotifier = node.eventNotifier;
650
+ // typeof, not truthiness: a node with a child called "EventNotifier" resolves the name to that
651
+ // child through the shared child accessors, so this is a BaseNode there, not the attribute
652
+ if (typeof node.eventNotifier === "number" && node.eventNotifier !== 0) record.eventNotifier = node.eventNotifier;
609
653
  this.records.push(record);
610
654
  this.dumpAggregates(node);
611
655
  }
@@ -615,8 +659,10 @@ class RecordExporter {
615
659
  this.markVisited(node);
616
660
  this.dumpReferencedNodes(node);
617
661
  const record = this.common(node);
618
- const eventNotifier = (node as unknown as { eventNotifier?: number }).eventNotifier;
619
- if (eventNotifier) record.eventNotifier = eventNotifier;
662
+ // typeof, not truthiness: a node with a child called "EventNotifier" resolves the name to that
663
+ // child through the shared child accessors, so this is a BaseNode there, not the attribute
664
+ const eventNotifier = (node as unknown as { eventNotifier?: unknown }).eventNotifier;
665
+ if (typeof eventNotifier === "number" && eventNotifier !== 0) record.eventNotifier = eventNotifier;
620
666
  this.records.push(record);
621
667
  this.dumpAggregates(node);
622
668
  this.section(`ObjectType - ${this.b(node.browseName)} }}}}`);
@@ -634,9 +680,9 @@ class RecordExporter {
634
680
  private dumpView(node: BaseNode): void {
635
681
  this.markVisited(node);
636
682
  const record = this.common(node);
637
- const view = node as unknown as { containsNoLoops?: boolean; eventNotifier?: number };
683
+ const view = node as unknown as { containsNoLoops?: boolean; eventNotifier?: unknown };
638
684
  if (view.containsNoLoops) record.containsNoLoops = true;
639
- if (view.eventNotifier) record.eventNotifier = view.eventNotifier;
685
+ if (typeof view.eventNotifier === "number" && view.eventNotifier !== 0) record.eventNotifier = view.eventNotifier;
640
686
  this.records.push(record);
641
687
  this.dumpAggregates(node);
642
688
  }
@@ -675,8 +721,12 @@ class RecordExporter {
675
721
  private valueOf(node: UAVariable | UAVariableType, variant: Variant): VariantOptions | undefined {
676
722
  if (!(variant instanceof Variant)) return undefined;
677
723
  if (variant.dataType === DataType.Null) return undefined;
724
+ // a null value is nothing to write down, whatever its declared data type
725
+ if (variant.value === null || variant.value === undefined) return undefined;
678
726
  if (!this.addressSpace.findDataType(node.dataType)) return undefined;
679
- if (_isDefaultValue(variant)) return undefined;
727
+ // no _isDefaultValue test here: it dropped every zero and every empty string, which threw
728
+ // away the ones the document actually declared in order to suppress the ones the loader
729
+ // made up. valueWasSynthesized now separates the two, so a declared "" survives the trip
680
730
  const element = (v: unknown) => this.elementOf(node, variant.dataType, v);
681
731
  const out: VariantOptions = { dataType: variant.dataType, arrayType: variant.arrayType };
682
732
  if (variant.arrayType === VariantArrayType.Scalar) {