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.
- package/api/helpers/ensure_secure_access.ts +53 -2
- package/api/index.ts +30 -1
- package/api/loader/generateAddressSpaceRaw.ts +44 -139
- package/api/loader/load_nodeset2.ts +5 -0
- package/api/loader/narrow_instance_datatypes.ts +264 -0
- package/api/loader/nodeset_builtin_formats.ts +143 -0
- package/api/loader/nodeset_format.ts +153 -0
- package/api/loader/nodeset_image.ts +37 -4
- package/api/loader/nodeset_image_codec.ts +153 -34
- package/api/loader/nodeset_record.ts +26 -2
- package/api/loader/nodeset_record_applier.ts +54 -3
- package/api/loader/nodeset_records_to_xml.ts +620 -0
- package/api/loader/nodeset_source.ts +185 -26
- package/api/loader/nodeset_to_image.ts +16 -5
- package/api/loader/nodeset_xml_header.ts +119 -0
- package/api/loader/nodeset_xml_primitives.ts +209 -0
- package/api/loader/nodeset_xml_producer.ts +61 -2
- package/api/loader/parsers/variant_parser.ts +9 -0
- package/bin/nodeset_equivalence.js +750 -0
- package/bin/nodeset_tool_common.js +72 -0
- package/bin/opcua-nodeset-image.js +93 -103
- package/bin/opcua-nodeset-live.js +139 -0
- package/dist/api/helpers/ensure_secure_access.d.ts +20 -0
- package/dist/api/helpers/ensure_secure_access.js +39 -0
- package/dist/api/helpers/ensure_secure_access.js.map +1 -1
- package/dist/api/index.d.ts +7 -2
- package/dist/api/index.js +21 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/loader/generateAddressSpaceRaw.d.ts +1 -7
- package/dist/api/loader/generateAddressSpaceRaw.js +32 -125
- package/dist/api/loader/generateAddressSpaceRaw.js.map +1 -1
- package/dist/api/loader/load_nodeset2.js +4 -0
- package/dist/api/loader/load_nodeset2.js.map +1 -1
- package/dist/api/loader/narrow_instance_datatypes.d.ts +30 -0
- package/dist/api/loader/narrow_instance_datatypes.js +217 -0
- package/dist/api/loader/narrow_instance_datatypes.js.map +1 -0
- package/dist/api/loader/nodeset_builtin_formats.d.ts +27 -0
- package/dist/api/loader/nodeset_builtin_formats.js +133 -0
- package/dist/api/loader/nodeset_builtin_formats.js.map +1 -0
- package/dist/api/loader/nodeset_format.d.ts +123 -0
- package/dist/api/loader/nodeset_format.js +63 -0
- package/dist/api/loader/nodeset_format.js.map +1 -0
- package/dist/api/loader/nodeset_image.d.ts +17 -1
- package/dist/api/loader/nodeset_image.js +32 -4
- package/dist/api/loader/nodeset_image.js.map +1 -1
- package/dist/api/loader/nodeset_image_codec.d.ts +4 -0
- package/dist/api/loader/nodeset_image_codec.js +142 -53
- package/dist/api/loader/nodeset_image_codec.js.map +1 -1
- package/dist/api/loader/nodeset_record.d.ts +26 -2
- package/dist/api/loader/nodeset_record.js +11 -2
- package/dist/api/loader/nodeset_record.js.map +1 -1
- package/dist/api/loader/nodeset_record_applier.js +52 -3
- package/dist/api/loader/nodeset_record_applier.js.map +1 -1
- package/dist/api/loader/nodeset_records_to_xml.d.ts +16 -0
- package/dist/api/loader/nodeset_records_to_xml.js +536 -0
- package/dist/api/loader/nodeset_records_to_xml.js.map +1 -0
- package/dist/api/loader/nodeset_source.d.ts +68 -7
- package/dist/api/loader/nodeset_source.js +157 -20
- package/dist/api/loader/nodeset_source.js.map +1 -1
- package/dist/api/loader/nodeset_to_image.d.ts +4 -4
- package/dist/api/loader/nodeset_to_image.js +14 -4
- package/dist/api/loader/nodeset_to_image.js.map +1 -1
- package/dist/api/loader/nodeset_xml_header.d.ts +22 -0
- package/dist/api/loader/nodeset_xml_header.js +113 -0
- package/dist/api/loader/nodeset_xml_header.js.map +1 -0
- package/dist/api/loader/nodeset_xml_primitives.d.ts +37 -0
- package/dist/api/loader/nodeset_xml_primitives.js +196 -0
- package/dist/api/loader/nodeset_xml_primitives.js.map +1 -0
- package/dist/api/loader/nodeset_xml_producer.js +56 -1
- package/dist/api/loader/nodeset_xml_producer.js.map +1 -1
- package/dist/api/loader/parsers/variant_parser.js +7 -0
- package/dist/api/loader/parsers/variant_parser.js.map +1 -1
- package/dist/impl/_instantiate_helpers.js +1 -0
- package/dist/impl/_instantiate_helpers.js.map +1 -1
- package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js +4 -0
- package/dist/impl/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
- package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js +14 -0
- package/dist/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js.map +1 -1
- package/dist/impl/base_node_impl.d.ts +9 -0
- package/dist/impl/base_node_impl.js +11 -0
- package/dist/impl/base_node_impl.js.map +1 -1
- package/dist/impl/base_node_private.js +67 -97
- package/dist/impl/base_node_private.js.map +1 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js +5 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/impl/nodeset_tools/nodeset_to_records.js +61 -15
- package/dist/impl/nodeset_tools/nodeset_to_records.js.map +1 -1
- package/dist/impl/nodeset_tools/nodeset_to_xml.d.ts +1 -8
- package/dist/impl/nodeset_tools/nodeset_to_xml.js +174 -190
- package/dist/impl/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/impl/ua_data_type_impl.d.ts +21 -0
- package/dist/impl/ua_data_type_impl.js +27 -2
- package/dist/impl/ua_data_type_impl.js.map +1 -1
- package/dist/impl/ua_object_type_impl.d.ts +9 -0
- package/dist/impl/ua_object_type_impl.js +12 -1
- package/dist/impl/ua_object_type_impl.js.map +1 -1
- package/dist/impl/ua_variable_impl.js +27 -10
- package/dist/impl/ua_variable_impl.js.map +1 -1
- package/dist/impl/ua_variable_impl_ext_obj.js +19 -2
- package/dist/impl/ua_variable_impl_ext_obj.js.map +1 -1
- package/dist/impl/ua_variable_type_impl.d.ts +8 -1
- package/dist/impl/ua_variable_type_impl.js +39 -2
- package/dist/impl/ua_variable_type_impl.js.map +1 -1
- package/dist/tsconfig_base.tsbuildinfo +1 -1
- package/distNodeJS/generate_address_space.js +4 -0
- package/distNodeJS/generate_address_space.js.map +1 -1
- package/impl/_instantiate_helpers.ts +3 -0
- package/impl/alarms_and_conditions/ua_alarm_condition_impl.ts +10 -0
- package/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.ts +17 -0
- package/impl/base_node_impl.ts +15 -0
- package/impl/base_node_private.ts +97 -146
- package/impl/nodeset_tools/construct_namespace_dependency.ts +5 -1
- package/impl/nodeset_tools/nodeset_to_records.ts +66 -16
- package/impl/nodeset_tools/nodeset_to_xml.ts +127 -160
- package/impl/ua_data_type_impl.ts +40 -2
- package/impl/ua_object_type_impl.ts +16 -3
- package/impl/ua_variable_impl.ts +27 -10
- package/impl/ua_variable_impl_ext_obj.ts +20 -2
- package/impl/ua_variable_type_impl.ts +48 -2
- package/package.json +29 -27
- 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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({
|
package/impl/base_node_impl.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
|
|
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
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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
|
-
|
|
750
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
554
|
+
return { name: definitionName, fields };
|
|
531
555
|
}
|
|
532
556
|
if (node.isStructure()) {
|
|
533
557
|
const definition = node.getStructureDefinition();
|
|
534
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
594
|
-
|
|
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
|
-
|
|
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
|
-
|
|
619
|
-
|
|
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?:
|
|
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
|
-
|
|
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) {
|