node-opcua-address-space 2.98.2 → 2.100.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.
@@ -19,14 +19,17 @@ import {
19
19
  UAReference,
20
20
  UAVariable,
21
21
  UAVariableType,
22
- CloneFilter
22
+ CloneFilter,
23
+ CloneHelper,
24
+ reconstructFunctionalGroupType,
25
+ reconstructNonHierarchicalReferences
23
26
  } from "node-opcua-address-space-base";
24
- import { ReferenceTypeIds } from "node-opcua-constants";
27
+
25
28
  import { coerceQualifiedName, NodeClass, QualifiedName, BrowseDirection, AttributeIds } from "node-opcua-data-model";
26
29
  import { DataValue, DataValueLike } from "node-opcua-data-value";
27
30
  import { checkDebugFlag, make_debugLog, make_warningLog, make_errorLog } from "node-opcua-debug";
28
- import { coerceNodeId, makeNodeId, NodeId, NodeIdLike, sameNodeId } from "node-opcua-nodeid";
29
- import { StatusCode, StatusCodes } from "node-opcua-status-code";
31
+ import { coerceNodeId, NodeId, NodeIdLike, sameNodeId } from "node-opcua-nodeid";
32
+ import { StatusCodes } from "node-opcua-status-code";
30
33
  import { UInt32 } from "node-opcua-basic-types";
31
34
  import { isNullOrUndefined } from "node-opcua-utils";
32
35
  import { DataType, Variant, VariantArrayType, verifyRankAndDimensions } from "node-opcua-variant";
@@ -402,103 +405,6 @@ class MandatoryChildOrRequestedOptionalFilter implements CloneFilter {
402
405
  }
403
406
  }
404
407
 
405
- /*
406
- * @function _get_parent_as_VariableOrObjectType
407
- * @param originalObject
408
- * @return {null|BaseNode}
409
- * @private
410
- */
411
- function _get_parent_as_VariableOrObjectType(originalObject: BaseNode): UAVariableType | UAObjectType | null {
412
- if (originalObject.nodeClass === NodeClass.Method) {
413
- return null;
414
- }
415
-
416
- const addressSpace = originalObject.addressSpace;
417
-
418
- const parents = originalObject.findReferencesEx("HasChild", BrowseDirection.Inverse);
419
-
420
- // istanbul ignore next
421
- if (parents.length > 1) {
422
- warningLog(" object ", originalObject.browseName.toString(), " has more than one parent !");
423
- warningLog(originalObject.toString());
424
- warningLog(" parents : ");
425
- for (const parent of parents) {
426
- warningLog(" ", parent.toString(), addressSpace.findNode(parent.nodeId)!.browseName.toString());
427
- }
428
- return null;
429
- }
430
-
431
- assert(parents.length === 0 || parents.length === 1);
432
- if (parents.length === 0) {
433
- return null;
434
- }
435
- const theParent = addressSpace.findNode(parents[0]!.nodeId)!;
436
- if (theParent && (theParent.nodeClass === NodeClass.VariableType || theParent.nodeClass === NodeClass.ObjectType)) {
437
- return theParent as UAVariableType | UAObjectType;
438
- }
439
- return null;
440
- }
441
-
442
- interface CloneInfo {
443
- cloned: UAObject | UAVariable | UAMethod;
444
- original: UAVariableType | UAObjectType;
445
- }
446
- class CloneHelper {
447
- public level = 0;
448
- private readonly mapOrgToClone: Map<string, CloneInfo> = new Map();
449
-
450
- public pad(): string {
451
- return " ".padEnd(this.level * 2, " ");
452
- }
453
- public registerClonedObject<TT extends UAVariableType | UAObjectType, T extends UAObject | UAVariable | UAMethod>(
454
- objInType: TT,
455
- clonedObj: T
456
- ) {
457
- this.mapOrgToClone.set(objInType.nodeId.toString(), {
458
- cloned: clonedObj,
459
- original: objInType
460
- });
461
-
462
- //
463
- // /-----------------------------\
464
- // | AcknowledgeableConditionType |
465
- // \-----------------------------/
466
- // ^ |
467
- // | +---------------------|- (EnabledState) (shadow element)
468
- // |
469
- // /-----------------------------\
470
- // | AlarmConditionType |
471
- // \-----------------------------/
472
- // |
473
- // +-------------------------------|- EnabledState <
474
- //
475
- // find also child object with the same browse name that are
476
- // overridden in the SuperType
477
- //
478
- const origParent = _get_parent_as_VariableOrObjectType(objInType);
479
- if (origParent) {
480
- let base = origParent.subtypeOfObj;
481
- while (base) {
482
- const shadowChild = base.getChildByName(objInType.browseName) as UAObjectType | UAVariableType | null;
483
- if (shadowChild) {
484
- this.mapOrgToClone.set(shadowChild.nodeId.toString(), {
485
- cloned: clonedObj,
486
- original: shadowChild
487
- });
488
- }
489
- base = base.subtypeOfObj;
490
- }
491
- }
492
- // find subTypeOf
493
- }
494
- public getCloned(original: UAVariableType | UAObjectType): UAObject | UAVariable | UAMethod | null {
495
- const info = this.mapOrgToClone.get(original.nodeId.toString());
496
- if (info) {
497
- return info.cloned;
498
- }
499
- return null;
500
- }
501
- }
502
408
  // install properties and components on a instantiated Object
503
409
  //
504
410
  // based on their ModelingRule
@@ -514,7 +420,7 @@ function _initialize_properties_and_components<B extends UAObject | UAVariable |
514
420
  typeDefinitionNode: T,
515
421
  copyAlsoModellingRules: boolean,
516
422
  optionalsMap: OptionalMap,
517
- extraInfo: CloneHelper,
423
+ extraInfo: CloneHelper,
518
424
  browseNameMap: Set<string>
519
425
  ) {
520
426
  if (doDebug) {
@@ -539,7 +445,6 @@ function _initialize_properties_and_components<B extends UAObject | UAVariable |
539
445
  typeDefinitionNode.browseName.toString()
540
446
  );
541
447
 
542
-
543
448
  _clone_hierarchical_references(typeDefinitionNode, instance, copyAlsoModellingRules, filter, extraInfo, browseNameMap);
544
449
 
545
450
  // now apply recursion on baseTypeDefinition to get properties and components from base class
@@ -633,192 +538,27 @@ export function assertUnusedChildBrowseName(addressSpace: AddressSpacePrivate, o
633
538
  exports.assertUnusedChildBrowseName = assertUnusedChildBrowseName;
634
539
  exports.initialize_properties_and_components = initialize_properties_and_components;
635
540
 
636
- const hasTypeDefinitionNodeId = makeNodeId(ReferenceTypeIds.HasTypeDefinition);
637
- const hasModellingRuleNodeId = makeNodeId(ReferenceTypeIds.HasModellingRule);
638
-
639
- /**
640
- * remove unwanted reference such as HasTypeDefinition and HasModellingRule
641
- * from the list
642
- */
643
- function _remove_unwanted_ref(references: UAReference[]): UAReference[] {
644
- // filter out HasTypeDefinition (i=40) , HasModellingRule (i=37);
645
- references = references.filter(
646
- (reference: UAReference) =>
647
- !sameNodeId(reference.referenceType, hasTypeDefinitionNodeId) &&
648
- !sameNodeId(reference.referenceType, hasModellingRuleNodeId)
649
- );
650
- return references;
651
- }
652
-
653
- /**
654
- *
655
- */
656
- function findNonHierarchicalReferences(originalObject: BaseNode): UAReference[] {
657
- // todo: MEMOIZE this method
658
- const addressSpace: IAddressSpace = originalObject.addressSpace;
659
- const referenceId = addressSpace.findReferenceType("NonHierarchicalReferences");
660
- if (!referenceId) {
661
- return [];
662
- }
663
- assert(referenceId);
664
-
665
- // we need to explore the non hierarchical references backwards
666
- let references = originalObject.findReferencesEx("NonHierarchicalReferences", BrowseDirection.Inverse);
667
-
668
- references = ([] as UAReference[]).concat(
669
- references,
670
- originalObject.findReferencesEx("HasEventSource", BrowseDirection.Inverse)
671
- );
672
-
673
- const parent = _get_parent_as_VariableOrObjectType(originalObject);
674
-
675
- if (parent && parent.subtypeOfObj) {
676
- // parent is a ObjectType or VariableType and is not a root type
677
- assert(parent.nodeClass === NodeClass.VariableType || parent.nodeClass === NodeClass.ObjectType);
678
-
679
- // let investigate the same child base child
680
- const child = parent.subtypeOfObj!.getChildByName(originalObject.browseName);
681
-
682
- if (child) {
683
- const baseRef = findNonHierarchicalReferences(child);
684
- references = ([] as UAReference[]).concat(references, baseRef);
685
- }
686
- }
687
- // perform some cleanup
688
- references = _remove_unwanted_ref(references);
689
-
690
- return references;
691
- }
692
-
693
- function reconstructNonHierarchicalReferences(extraInfo: any): void {
694
- const findImplementedObject = (ref: UAReference): CloneInfo | null =>
695
- extraInfo.mapOrgToClone.get(ref.nodeId.toString()) || null;
696
-
697
- // navigate through original objects to find those that are being references by node that
698
- // have been cloned .
699
- // this could be node organized by some FunctionalGroup
700
- //
701
- for (const { original, cloned } of extraInfo.mapOrgToClone.values()) {
702
- // find NonHierarchical References on original object
703
- const originalNonHierarchical = findNonHierarchicalReferences(original);
704
-
705
- if (originalNonHierarchical.length === 0) {
706
- continue;
707
- }
708
-
709
- // istanbul ignore next
710
- if (doDebug) {
711
- debugLog(
712
- " investigation ",
713
- original.browseName.toString(),
714
- cloned.nodeClass.toString(),
715
- original.nodeClass.toString(),
716
- original.nodeId.toString(),
717
- cloned.nodeId.toString()
718
- );
719
- }
720
-
721
- for (const ref of originalNonHierarchical) {
722
- const info = findImplementedObject(ref);
723
-
724
- // if the object pointed by this reference is also cloned ...
725
- if (info) {
726
- const originalDest = info.original;
727
- const cloneDest = info.cloned;
728
-
729
- // istanbul ignore next
730
- if (doDebug) {
731
- debugLog(
732
- chalk.cyan(" adding reference "),
733
- ref.referenceType,
734
- " from cloned ",
735
- cloned.nodeId.toString(),
736
- cloned.browseName.toString(),
737
- " to cloned ",
738
- cloneDest.nodeId.toString(),
739
- cloneDest.browseName.toString()
740
- );
741
- }
742
-
743
- // restore reference
744
- cloned.addReference({
745
- isForward: false,
746
- nodeId: cloneDest.nodeId,
747
- referenceType: ref.referenceType
748
- });
749
- }
750
- }
751
- }
752
- }
753
-
754
- /**
755
- * recreate functional group types according to type definition
756
- *
757
- * @method reconstructFunctionalGroupType
758
- * @param baseType
759
- */
760
-
761
- /* @example:
762
- *
763
- * MyDeviceType
764
- * |
765
- * +----------|- ParameterSet(BaseObjectType)
766
- * | |
767
- * | +-----------------|- Parameter1
768
- * | ^
769
- * +----------|- Config(FunctionalGroupType) |
770
- * | |
771
- * +-------- Organizes---+
772
- */
773
- function reconstructFunctionalGroupType(extraInfo: any) {
774
- // navigate through original objects to find those that are being organized by some FunctionalGroup
775
- for (const { original, cloned } of extraInfo.mapOrgToClone.values()) {
776
- const organizedByArray = original.findReferencesEx("Organizes", BrowseDirection.Inverse);
777
-
778
- for (const ref of organizedByArray) {
779
- const info = extraInfo.mapOrgToClone.get(ref.nodeId.toString());
780
- if (!info) continue;
781
-
782
- const folder = info.original;
783
- if (folder.nodeClass !== NodeClass.Object) continue;
784
-
785
- if (!folder.typeDefinitionObj) continue;
786
-
787
- assert(folder.typeDefinitionObj.browseName.name.toString() === "FunctionalGroupType");
788
-
789
- // now create the same reference with the instantiated function group
790
- const destFolder = info.cloned as BaseNode;
791
-
792
- assert(ref.referenceType);
793
-
794
- // may be we should check that the referenceType is a subtype of Organizes
795
- const alreadyExist = destFolder.findReferences(ref.referenceType, !ref.isForward).find((r) => r.nodeId === cloned.nodeId);
796
- if (alreadyExist) {
797
- continue;
798
- }
799
-
800
- destFolder.addReference({
801
- isForward: !ref.isForward,
802
- nodeId: cloned.nodeId,
803
- referenceType: ref.referenceType
804
- });
805
- }
806
- }
807
- }
808
-
809
541
  export function initialize_properties_and_components<
810
542
  B extends UAObject | UAVariable | UAMethod,
811
543
  T extends UAVariableType | UAObjectType
812
544
  >(instance: B, topMostType: T, nodeType: T, copyAlsoModellingRules: boolean, optionals?: string[]): void {
813
545
  const extraInfo = new CloneHelper();
814
546
 
815
- extraInfo.registerClonedObject(nodeType, instance);
547
+ extraInfo.registerClonedObject(instance, nodeType);
816
548
 
817
549
  const optionalsMap = makeOptionalsMap(optionals);
818
550
 
819
551
  const browseNameMap = new Set<string>();
820
552
 
821
- _initialize_properties_and_components(instance, topMostType, nodeType, copyAlsoModellingRules, optionalsMap, extraInfo, browseNameMap);
553
+ _initialize_properties_and_components(
554
+ instance,
555
+ topMostType,
556
+ nodeType,
557
+ copyAlsoModellingRules,
558
+ optionalsMap,
559
+ extraInfo,
560
+ browseNameMap
561
+ );
822
562
 
823
563
  reconstructFunctionalGroupType(extraInfo);
824
564