node-opcua-address-space-base 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.
@@ -0,0 +1,20 @@
1
+ import { UAObject } from "./ua_object";
2
+ import { UAVariable } from "./ua_variable";
3
+ import { UAMethod } from "./ua_method";
4
+ import { UAObjectType } from "./ua_object_type";
5
+ import { UAVariableType } from "./ua_variable_type";
6
+ export declare class CloneHelper {
7
+ level: number;
8
+ private readonly mapOrgToClone;
9
+ pad(): string;
10
+ registerClonedObject<TO extends UAObject | UAVariable | UAMethod | UAObjectType | UAVariableType, TC extends UAObject | UAVariable | UAMethod>(clonedNode: TC, originalNode: TO): void;
11
+ getCloned(originalNode: UAVariableType | UAObjectType): UAObject | UAVariable | UAMethod | null;
12
+ }
13
+ export declare function reconstructNonHierarchicalReferences(extraInfo: CloneHelper): void;
14
+ /**
15
+ * recreate functional group types according to type definition
16
+ *
17
+ * @method reconstructFunctionalGroupType
18
+ * @param baseType
19
+ */
20
+ export declare function reconstructFunctionalGroupType(extraInfo: CloneHelper): void;
@@ -0,0 +1,270 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reconstructFunctionalGroupType = exports.reconstructNonHierarchicalReferences = exports.CloneHelper = void 0;
4
+ const node_opcua_assert_1 = require("node-opcua-assert");
5
+ const node_opcua_debug_1 = require("node-opcua-debug");
6
+ const node_opcua_data_model_1 = require("node-opcua-data-model");
7
+ const node_opcua_nodeid_1 = require("node-opcua-nodeid");
8
+ const node_opcua_constants_1 = require("node-opcua-constants");
9
+ const debugLog = (0, node_opcua_debug_1.make_debugLog)("CLONE");
10
+ const doDebug = (0, node_opcua_debug_1.checkDebugFlag)("CLONE");
11
+ const warningLog = (0, node_opcua_debug_1.make_warningLog)("CLONE");
12
+ //
13
+ // case 1:
14
+ // /-----------------------------\
15
+ // | AcknowledgeableConditionType |
16
+ // \-----------------------------/
17
+ // ^ |
18
+ // | +---------------------|- (EnabledState) (shadow element)
19
+ // |
20
+ // /-----------------------------\
21
+ // | AlarmConditionType |
22
+ // \-----------------------------/
23
+ // |
24
+ // +-------------------------------|- EnabledState <
25
+ //
26
+ // find also child object with the same browse name that are
27
+ // overridden in the SuperType
28
+ // case 2:
29
+ //
30
+ // /-----------------------------\
31
+ // | MyDeviceType |
32
+ // \-----------------------------/
33
+ // ^ |
34
+ // | | +----------+
35
+ // | +-------| Folder1  |
36
+ // | +----------+
37
+ // | |
38
+ // | +--------------|- (EnabledState) (shadow element)
39
+ // |
40
+ // /-----------------------------\
41
+ // | MyDeriveDeviceType |
42
+ // \-----------------------------/
43
+ // |
44
+ // | | +----------+
45
+ // | +-------| Folder1  |
46
+ // | +----------+
47
+ // | |
48
+ // | +--------------|- (EnabledState)
49
+ //
50
+ // find also child object with the same browse name that are
51
+ function _get_parent_type_and_path(originalObject) {
52
+ if (originalObject.nodeClass === node_opcua_data_model_1.NodeClass.Method) {
53
+ return { parentType: null, path: [] };
54
+ }
55
+ const addressSpace = originalObject.addressSpace;
56
+ const parents = originalObject.findReferencesEx("HasChild", node_opcua_data_model_1.BrowseDirection.Inverse);
57
+ // istanbul ignore next
58
+ if (parents.length > 1) {
59
+ warningLog(" object ", originalObject.browseName.toString(), " has more than one parent !");
60
+ warningLog(originalObject.toString());
61
+ warningLog(" parents : ");
62
+ for (const parent of parents) {
63
+ warningLog(" ", parent.toString(), addressSpace.findNode(parent.nodeId).browseName.toString());
64
+ }
65
+ return { parentType: null, path: [] };
66
+ }
67
+ (0, node_opcua_assert_1.assert)(parents.length === 0 || parents.length === 1);
68
+ if (parents.length === 0) {
69
+ return { parentType: null, path: [] };
70
+ }
71
+ const theParent = addressSpace.findNode(parents[0].nodeId);
72
+ if (theParent && (theParent.nodeClass === node_opcua_data_model_1.NodeClass.VariableType || theParent.nodeClass === node_opcua_data_model_1.NodeClass.ObjectType)) {
73
+ return { parentType: theParent, path: [originalObject.browseName] };
74
+ }
75
+ // walk up
76
+ const { parentType, path } = _get_parent_type_and_path(theParent);
77
+ return { parentType, path: [...path, originalObject.browseName] };
78
+ }
79
+ function followPath(node, path) {
80
+ let current = node;
81
+ for (const qn of path) {
82
+ const ref = current
83
+ .findReferencesExAsObject("HierarchicalReferences", node_opcua_data_model_1.BrowseDirection.Forward)
84
+ .find((r) => r.browseName.toString() === qn.toString());
85
+ if (!ref) {
86
+ return null;
87
+ }
88
+ current = ref;
89
+ }
90
+ return current;
91
+ }
92
+ class CloneHelper {
93
+ constructor() {
94
+ this.level = 0;
95
+ this.mapOrgToClone = new Map();
96
+ }
97
+ pad() {
98
+ return " ".padEnd(this.level * 2, " ");
99
+ }
100
+ registerClonedObject(clonedNode, originalNode) {
101
+ this.mapOrgToClone.set(originalNode.nodeId.toString(), {
102
+ cloned: clonedNode,
103
+ original: originalNode
104
+ });
105
+ //
106
+ const { parentType, path } = _get_parent_type_and_path(originalNode);
107
+ if (parentType) {
108
+ let base = parentType.subtypeOfObj;
109
+ while (base) {
110
+ const shadowChild = followPath(base, path);
111
+ if (shadowChild) {
112
+ this.mapOrgToClone.set(shadowChild.nodeId.toString(), {
113
+ cloned: clonedNode,
114
+ original: shadowChild
115
+ });
116
+ }
117
+ base = base.subtypeOfObj;
118
+ }
119
+ }
120
+ else {
121
+ }
122
+ // find subTypeOf
123
+ }
124
+ getCloned(originalNode) {
125
+ const info = this.mapOrgToClone.get(originalNode.nodeId.toString());
126
+ if (info) {
127
+ return info.cloned;
128
+ }
129
+ return null;
130
+ }
131
+ }
132
+ exports.CloneHelper = CloneHelper;
133
+ const hasTypeDefinitionNodeId = (0, node_opcua_nodeid_1.makeNodeId)(node_opcua_constants_1.ReferenceTypeIds.HasTypeDefinition);
134
+ const hasModellingRuleNodeId = (0, node_opcua_nodeid_1.makeNodeId)(node_opcua_constants_1.ReferenceTypeIds.HasModellingRule);
135
+ /**
136
+ * remove unwanted reference such as HasTypeDefinition and HasModellingRule
137
+ * from the list
138
+ */
139
+ function _remove_unwanted_ref(references) {
140
+ // filter out HasTypeDefinition (i=40) , HasModellingRule (i=37);
141
+ references = references.filter((reference) => !(0, node_opcua_nodeid_1.sameNodeId)(reference.referenceType, hasTypeDefinitionNodeId) &&
142
+ !(0, node_opcua_nodeid_1.sameNodeId)(reference.referenceType, hasModellingRuleNodeId));
143
+ return references;
144
+ }
145
+ /**
146
+ *
147
+ */
148
+ function findNonHierarchicalReferences(originalObject) {
149
+ // todo: MEMOIZE this method
150
+ const addressSpace = originalObject.addressSpace;
151
+ // we need to explore the non hierarchical references backwards
152
+ let references = originalObject.findReferencesEx("NonHierarchicalReferences", node_opcua_data_model_1.BrowseDirection.Inverse);
153
+ references = [].concat(references, originalObject.findReferencesEx("HasEventSource", node_opcua_data_model_1.BrowseDirection.Inverse));
154
+ const { parentType, path } = _get_parent_type_and_path(originalObject);
155
+ if (parentType && parentType.subtypeOfObj) {
156
+ // parent is a ObjectType or VariableType and is not a root type
157
+ (0, node_opcua_assert_1.assert)(parentType.nodeClass === node_opcua_data_model_1.NodeClass.VariableType || parentType.nodeClass === node_opcua_data_model_1.NodeClass.ObjectType);
158
+ // let investigate the same child base child
159
+ const child = followPath(parentType.subtypeOfObj, path);
160
+ if (child) {
161
+ const baseRef = findNonHierarchicalReferences(child);
162
+ references = [].concat(references, baseRef);
163
+ }
164
+ }
165
+ // perform some cleanup
166
+ references = _remove_unwanted_ref(references);
167
+ return references;
168
+ }
169
+ function reconstructNonHierarchicalReferences(extraInfo) {
170
+ const extraInfo_ = extraInfo;
171
+ const findImplementedObject = (ref) => extraInfo_.mapOrgToClone.get(ref.nodeId.toString()) || null;
172
+ // navigate through original objects to find those that are being references by node that
173
+ // have been cloned .
174
+ // this could be node organized by some FunctionalGroup
175
+ for (const { original, cloned } of extraInfo_.mapOrgToClone.values()) {
176
+ apply(original, cloned);
177
+ }
178
+ function apply(original, cloned) {
179
+ const addressSpace = original.addressSpace;
180
+ // find NonHierarchical References on original object
181
+ const originalNonHierarchical = findNonHierarchicalReferences(original);
182
+ if (originalNonHierarchical.length === 0) {
183
+ return;
184
+ }
185
+ // istanbul ignore next
186
+ if (doDebug) {
187
+ debugLog(" investigation ", original.browseName.toString(), cloned.nodeClass.toString(), original.nodeClass.toString(), original.nodeId.toString(), cloned.nodeId.toString());
188
+ }
189
+ for (const ref of originalNonHierarchical) {
190
+ const info = findImplementedObject(ref);
191
+ // if the object pointed by this reference is also cloned ...
192
+ if (info) {
193
+ const originalDest = info.original;
194
+ const cloneDest = info.cloned;
195
+ // istanbul ignore next
196
+ if (doDebug) {
197
+ debugLog(" adding reference ", ref.referenceType, addressSpace.findNode(ref.referenceType).browseName.toString(), " from cloned ", cloned.nodeId.toString(), cloned.browseName.toString(), " to cloned ", cloneDest.nodeId.toString(), cloneDest.browseName.toString());
198
+ }
199
+ // restore reference
200
+ cloned.addReference({
201
+ isForward: false,
202
+ nodeId: cloneDest.nodeId,
203
+ referenceType: ref.referenceType
204
+ });
205
+ }
206
+ else {
207
+ // // restore reference
208
+ // cloned.addReference({
209
+ // isForward: false,
210
+ // nodeId: ref.nodeId,
211
+ // referenceType: ref.referenceType
212
+ // });
213
+ }
214
+ }
215
+ }
216
+ }
217
+ exports.reconstructNonHierarchicalReferences = reconstructNonHierarchicalReferences;
218
+ /**
219
+ * recreate functional group types according to type definition
220
+ *
221
+ * @method reconstructFunctionalGroupType
222
+ * @param baseType
223
+ */
224
+ /* @example:
225
+ *
226
+ * MyDeviceType
227
+ * |
228
+ * +----------|- ParameterSet(BaseObjectType)
229
+ * | |
230
+ * | +-----------------|- Parameter1
231
+ * | ^
232
+ * +----------|- Config(FunctionalGroupType) |
233
+ * | |
234
+ * +-------- Organizes---+
235
+ */
236
+ function reconstructFunctionalGroupType(extraInfo) {
237
+ const extraInfo_ = extraInfo;
238
+ // navigate through original objects to find those that are being organized by some FunctionalGroup
239
+ for (const { original, cloned } of extraInfo_.mapOrgToClone.values()) {
240
+ const organizedByArray = original.findReferencesEx("Organizes", node_opcua_data_model_1.BrowseDirection.Inverse);
241
+ for (const ref of organizedByArray) {
242
+ const info = extraInfo_.mapOrgToClone.get(ref.nodeId.toString());
243
+ if (!info)
244
+ continue;
245
+ const folder = info.original;
246
+ if (folder.nodeClass !== node_opcua_data_model_1.NodeClass.Object)
247
+ continue;
248
+ if (!folder.typeDefinitionObj)
249
+ continue;
250
+ (0, node_opcua_assert_1.assert)(folder.typeDefinitionObj.browseName.name.toString() === "FunctionalGroupType");
251
+ // now create the same reference with the instantiated function group
252
+ const destFolder = info.cloned;
253
+ (0, node_opcua_assert_1.assert)(ref.referenceType);
254
+ // may be we should check that the referenceType is a subtype of Organizes
255
+ const alreadyExist = destFolder
256
+ .findReferences(ref.referenceType, !ref.isForward)
257
+ .find((r) => r.nodeId === cloned.nodeId);
258
+ if (alreadyExist) {
259
+ continue;
260
+ }
261
+ destFolder.addReference({
262
+ isForward: !ref.isForward,
263
+ nodeId: cloned.nodeId,
264
+ referenceType: ref.referenceType
265
+ });
266
+ }
267
+ }
268
+ }
269
+ exports.reconstructFunctionalGroupType = reconstructFunctionalGroupType;
270
+ //# sourceMappingURL=clone_helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone_helper.js","sourceRoot":"","sources":["../source/clone_helper.ts"],"names":[],"mappings":"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"}
@@ -16,13 +16,10 @@ export declare const defaultCloneFilter: CloneFilter;
16
16
  export interface CloneExtraInfo {
17
17
  level: number;
18
18
  pad(): string;
19
- registerClonedObject(clonedObject: BaseNode, originalObject: BaseNode): void;
20
- getCloned(node: BaseNode): BaseNode | null;
19
+ registerClonedObject(clonedNode: BaseNode, originalNode: BaseNode): void;
20
+ getCloned(originalObject: BaseNode): BaseNode | null;
21
21
  }
22
- interface CloneExtraInfoEx extends CloneExtraInfo {
23
- _cloned: Map<BaseNode, BaseNode>;
24
- }
25
- export declare const defaultCloneExtraInfo: CloneExtraInfoEx;
22
+ export declare const makeDefaultCloneExtraInfo: () => CloneExtraInfo;
26
23
  export interface CloneOptions {
27
24
  namespace: INamespace;
28
25
  references?: UAReference[];
@@ -46,4 +43,3 @@ export interface CloneOptions {
46
43
  copyAlsoModellingRules?: boolean;
47
44
  ignoreChildren?: boolean;
48
45
  }
49
- export {};
@@ -1,25 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultCloneExtraInfo = exports.defaultCloneFilter = void 0;
3
+ exports.makeDefaultCloneExtraInfo = exports.defaultCloneFilter = void 0;
4
+ const clone_helper_1 = require("./clone_helper");
4
5
  exports.defaultCloneFilter = {
5
6
  shouldKeep: () => true,
6
7
  filterFor(node) {
7
8
  return this;
8
9
  }
9
10
  };
10
- exports.defaultCloneExtraInfo = {
11
- level: 0,
12
- _cloned: new Map(),
13
- pad() {
14
- return " ".padEnd(this.level * 2);
15
- },
16
- registerClonedObject(_clonedObject, _originalObject) {
17
- if (this.getCloned(_originalObject))
18
- throw new Error("cloned object is already registered.");
19
- this._cloned.set(_originalObject, _clonedObject);
20
- },
21
- getCloned(node) {
22
- return this._cloned.get(node) || null;
23
- }
24
- };
11
+ const makeDefaultCloneExtraInfo = () => new clone_helper_1.CloneHelper();
12
+ exports.makeDefaultCloneExtraInfo = makeDefaultCloneExtraInfo;
25
13
  //# sourceMappingURL=clone_options.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clone_options.js","sourceRoot":"","sources":["../source/clone_options.ts"],"names":[],"mappings":";;;AAgBa,QAAA,kBAAkB,GAAgB;IAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI;IACtB,SAAS,CAAC,IAAc;QACpB,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAC;AAYW,QAAA,qBAAqB,GAAqB;IACnD,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,IAAI,GAAG,EAAsB;IACtC,GAAG;QACC,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,oBAAoB,CAAC,aAAuB,EAAE,eAAyB;QACnE,IAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC5F,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;IACrD,CAAC;IACD,SAAS,CAAC,IAAc;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IAC1C,CAAC;CACJ,CAAC"}
1
+ {"version":3,"file":"clone_options.js","sourceRoot":"","sources":["../source/clone_options.ts"],"names":[],"mappings":";;;AAWA,iDAA6C;AAMhC,QAAA,kBAAkB,GAAgB;IAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI;IACtB,SAAS,CAAC,IAAc;QACpB,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAC;AAUK,MAAM,yBAAyB,GAAG,GAAmB,EAAE,CAAG,IAAI,0BAAW,EAAE,CAAC;AAAtE,QAAA,yBAAyB,6BAA6C"}
package/dist/index.d.ts CHANGED
@@ -21,3 +21,4 @@ export * from "./ua_variable_t";
21
21
  export * from "./ua_variable_type";
22
22
  export * from "./ua_variable";
23
23
  export * from "./ua_view";
24
+ export * from "./clone_helper";
package/dist/index.js CHANGED
@@ -37,4 +37,5 @@ __exportStar(require("./ua_variable_t"), exports);
37
37
  __exportStar(require("./ua_variable_type"), exports);
38
38
  __exportStar(require("./ua_variable"), exports);
39
39
  __exportStar(require("./ua_view"), exports);
40
+ __exportStar(require("./clone_helper"), exports);
40
41
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,uDAAqC;AACrC,yDAAuC;AACvC,iDAA+B;AAC/B,wDAAsC;AACtC,8CAA4B;AAC5B,oDAAkC;AAClC,iDAA+B;AAC/B,8DAA4C;AAC5C,kDAAgC;AAChC,8CAA4B;AAC5B,mDAAiC;AACjC,8CAA4B;AAC5B,gDAA8B;AAC9B,sDAAoC;AACpC,iDAA+B;AAC/B,kDAAgC;AAChC,qDAAmC;AACnC,gDAA8B;AAC9B,4CAA0B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,uDAAqC;AACrC,yDAAuC;AACvC,iDAA+B;AAC/B,wDAAsC;AACtC,8CAA4B;AAC5B,oDAAkC;AAClC,iDAA+B;AAC/B,8DAA4C;AAC5C,kDAAgC;AAChC,8CAA4B;AAC5B,mDAAiC;AACjC,8CAA4B;AAC5B,gDAA8B;AAC9B,sDAAoC;AACpC,iDAA+B;AAC/B,kDAAgC;AAChC,qDAAmC;AACnC,gDAA8B;AAC9B,4CAA0B;AAC1B,iDAA+B"}
@@ -217,8 +217,8 @@ export interface UAVariable extends BaseNode, VariableAttributes, IPropertyAndCo
217
217
  writeValue(context: ISessionContext, dataValue: DataValue, indexRange: string | NumericRange | null, callback: StatusCodeCallback): void;
218
218
  writeValue(context: ISessionContext, dataValue: DataValue, callback: StatusCodeCallback): void;
219
219
  writeValue(context: ISessionContext, dataValue: DataValue, indexRange?: string | NumericRange | null): Promise<StatusCode>;
220
- asyncRefresh(oldestDate: Date, callback: CallbackT<DataValue>): void;
221
- asyncRefresh(oldestDate: Date): Promise<DataValue>;
220
+ asyncRefresh(oldestDate: PreciseClock, callback: CallbackT<DataValue>): void;
221
+ asyncRefresh(oldestDate: PreciseClock): Promise<DataValue>;
222
222
  /**
223
223
  * write a variable attribute (callback version)
224
224
  * @param context
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space-base",
3
- "version": "2.98.2",
3
+ "version": "2.100.0",
4
4
  "description": "pure nodejs OPCUA SDK - module address-space-base",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -13,22 +13,24 @@
13
13
  "lint": "eslint source",
14
14
  "format": "prettier --write source",
15
15
  "clean": "npx rimraf node_modules dist *.tsbuildinfo",
16
- "c": "mocha --version"
16
+ "mocha:version": "mocha --version"
17
17
  },
18
18
  "dependencies": {
19
- "node-opcua-basic-types": "2.98.1",
19
+ "node-opcua-assert": "2.98.1",
20
+ "node-opcua-basic-types": "2.99.0",
20
21
  "node-opcua-constants": "2.98.1",
21
22
  "node-opcua-crypto": "^2.1.2",
22
- "node-opcua-data-model": "2.98.1",
23
- "node-opcua-data-value": "2.98.1",
24
- "node-opcua-date-time": "2.98.1",
25
- "node-opcua-extension-object": "2.98.1",
26
- "node-opcua-nodeid": "2.98.1",
27
- "node-opcua-numeric-range": "2.98.1",
28
- "node-opcua-schemas": "2.98.2",
23
+ "node-opcua-data-model": "2.99.0",
24
+ "node-opcua-data-value": "2.99.0",
25
+ "node-opcua-date-time": "2.99.0",
26
+ "node-opcua-debug": "2.99.0",
27
+ "node-opcua-extension-object": "2.99.0",
28
+ "node-opcua-nodeid": "2.99.0",
29
+ "node-opcua-numeric-range": "2.99.0",
30
+ "node-opcua-schemas": "2.99.0",
29
31
  "node-opcua-status-code": "2.98.1",
30
- "node-opcua-types": "2.98.2",
31
- "node-opcua-variant": "2.98.1"
32
+ "node-opcua-types": "2.99.0",
33
+ "node-opcua-variant": "2.99.0"
32
34
  },
33
35
  "author": "Etienne Rossignon",
34
36
  "license": "MIT",
@@ -45,7 +47,7 @@
45
47
  "internet of things"
46
48
  ],
47
49
  "homepage": "http://node-opcua.github.io/",
48
- "gitHead": "6df8aa25475ba1235e585566cb2dec68b7e7a85f",
50
+ "gitHead": "e143ff72418bb3db8c0a2cb8d4b7e54a90521a73",
49
51
  "files": [
50
52
  "dist",
51
53
  "source"
@@ -0,0 +1,343 @@
1
+ import { assert } from "node-opcua-assert";
2
+ import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
3
+ import { BrowseDirection, NodeClass, QualifiedName } from "node-opcua-data-model";
4
+ import { UAObject } from "./ua_object";
5
+ import { UAVariable } from "./ua_variable";
6
+ import { UAMethod } from "./ua_method";
7
+ import { UAObjectType } from "./ua_object_type";
8
+ import { UAVariableType } from "./ua_variable_type";
9
+ import { BaseNode } from "./base_node";
10
+ import { makeNodeId, sameNodeId } from "node-opcua-nodeid";
11
+ import { ReferenceTypeIds } from "node-opcua-constants";
12
+ import { UAReference } from "./ua_reference";
13
+ import { IAddressSpace } from "./address_space";
14
+
15
+ const debugLog = make_debugLog("CLONE");
16
+ const doDebug = checkDebugFlag("CLONE");
17
+ const warningLog = make_warningLog("CLONE");
18
+
19
+ type UAConcrete = UAVariable | UAObject | UAMethod;
20
+
21
+ //
22
+ // case 1:
23
+ // /-----------------------------\
24
+ // | AcknowledgeableConditionType |
25
+ // \-----------------------------/
26
+ // ^ |
27
+ // | +---------------------|- (EnabledState) (shadow element)
28
+ // |
29
+ // /-----------------------------\
30
+ // | AlarmConditionType |
31
+ // \-----------------------------/
32
+ // |
33
+ // +-------------------------------|- EnabledState <
34
+ //
35
+ // find also child object with the same browse name that are
36
+ // overridden in the SuperType
37
+
38
+ // case 2:
39
+ //
40
+ // /-----------------------------\
41
+ // | MyDeviceType |
42
+ // \-----------------------------/
43
+ // ^ |
44
+ // | | +----------+
45
+ // | +-------| Folder1  |
46
+ // | +----------+
47
+ // | |
48
+ // | +--------------|- (EnabledState) (shadow element)
49
+ // |
50
+ // /-----------------------------\
51
+ // | MyDeriveDeviceType |
52
+ // \-----------------------------/
53
+ // |
54
+ // | | +----------+
55
+ // | +-------| Folder1  |
56
+ // | +----------+
57
+ // | |
58
+ // | +--------------|- (EnabledState)
59
+ //
60
+ // find also child object with the same browse name that are
61
+
62
+ function _get_parent_type_and_path(originalObject: BaseNode): {
63
+ parentType: null | UAVariableType | UAObjectType;
64
+ path: QualifiedName[];
65
+ } {
66
+ if (originalObject.nodeClass === NodeClass.Method) {
67
+ return { parentType: null, path: [] };
68
+ }
69
+
70
+ const addressSpace = originalObject.addressSpace;
71
+
72
+ const parents = originalObject.findReferencesEx("HasChild", BrowseDirection.Inverse);
73
+ // istanbul ignore next
74
+ if (parents.length > 1) {
75
+ warningLog(" object ", originalObject.browseName.toString(), " has more than one parent !");
76
+ warningLog(originalObject.toString());
77
+ warningLog(" parents : ");
78
+ for (const parent of parents) {
79
+ warningLog(" ", parent.toString(), addressSpace.findNode(parent.nodeId)!.browseName.toString());
80
+ }
81
+ return { parentType: null, path: [] };
82
+ }
83
+
84
+ assert(parents.length === 0 || parents.length === 1);
85
+ if (parents.length === 0) {
86
+ return { parentType: null, path: [] };
87
+ }
88
+ const theParent = addressSpace.findNode(parents[0]!.nodeId)!;
89
+ if (theParent && (theParent.nodeClass === NodeClass.VariableType || theParent.nodeClass === NodeClass.ObjectType)) {
90
+ return { parentType: theParent as UAVariableType | UAObjectType, path: [originalObject.browseName] };
91
+ }
92
+ // walk up
93
+ const { parentType, path } = _get_parent_type_and_path(theParent!);
94
+ return { parentType, path: [...path, originalObject.browseName] };
95
+ }
96
+
97
+ interface CloneInfo {
98
+ cloned: UAObject | UAVariable | UAMethod;
99
+ original: UAObject | UAVariable | UAMethod | UAVariableType | UAObjectType;
100
+ }
101
+
102
+ function followPath(node: BaseNode, path: QualifiedName[]): UAConcrete | null {
103
+ let current = node;
104
+ for (const qn of path) {
105
+ const ref = current
106
+ .findReferencesExAsObject("HierarchicalReferences", BrowseDirection.Forward)
107
+ .find((r) => r.browseName.toString() === qn.toString());
108
+ if (!ref) {
109
+ return null;
110
+ }
111
+ current = ref;
112
+ }
113
+ return current as UAConcrete;
114
+ }
115
+
116
+ export class CloneHelper {
117
+ public level = 0;
118
+ private readonly mapOrgToClone: Map<string, CloneInfo> = new Map();
119
+
120
+ public pad(): string {
121
+ return " ".padEnd(this.level * 2, " ");
122
+ }
123
+ public registerClonedObject<
124
+ TO extends UAObject | UAVariable | UAMethod | UAObjectType | UAVariableType,
125
+ TC extends UAObject | UAVariable | UAMethod
126
+ >(clonedNode: TC, originalNode: TO) {
127
+ this.mapOrgToClone.set(originalNode.nodeId.toString(), {
128
+ cloned: clonedNode,
129
+ original: originalNode
130
+ });
131
+
132
+ //
133
+ const { parentType, path } = _get_parent_type_and_path(originalNode);
134
+
135
+ if (parentType) {
136
+ let base = parentType.subtypeOfObj;
137
+ while (base) {
138
+ const shadowChild = followPath(base, path);
139
+ if (shadowChild) {
140
+ this.mapOrgToClone.set(shadowChild.nodeId.toString(), {
141
+ cloned: clonedNode,
142
+ original: shadowChild
143
+ });
144
+ }
145
+ base = base.subtypeOfObj;
146
+ }
147
+ } else {
148
+ }
149
+ // find subTypeOf
150
+ }
151
+ public getCloned(originalNode: UAVariableType | UAObjectType): UAObject | UAVariable | UAMethod | null {
152
+ const info = this.mapOrgToClone.get(originalNode.nodeId.toString());
153
+ if (info) {
154
+ return info.cloned;
155
+ }
156
+ return null;
157
+ }
158
+ }
159
+
160
+ const hasTypeDefinitionNodeId = makeNodeId(ReferenceTypeIds.HasTypeDefinition);
161
+ const hasModellingRuleNodeId = makeNodeId(ReferenceTypeIds.HasModellingRule);
162
+
163
+ /**
164
+ * remove unwanted reference such as HasTypeDefinition and HasModellingRule
165
+ * from the list
166
+ */
167
+ function _remove_unwanted_ref(references: UAReference[]): UAReference[] {
168
+ // filter out HasTypeDefinition (i=40) , HasModellingRule (i=37);
169
+ references = references.filter(
170
+ (reference: UAReference) =>
171
+ !sameNodeId(reference.referenceType, hasTypeDefinitionNodeId) &&
172
+ !sameNodeId(reference.referenceType, hasModellingRuleNodeId)
173
+ );
174
+ return references;
175
+ }
176
+
177
+ /**
178
+ *
179
+ */
180
+ function findNonHierarchicalReferences(originalObject: BaseNode): UAReference[] {
181
+ // todo: MEMOIZE this method
182
+ const addressSpace: IAddressSpace = originalObject.addressSpace;
183
+
184
+ // we need to explore the non hierarchical references backwards
185
+ let references = originalObject.findReferencesEx("NonHierarchicalReferences", BrowseDirection.Inverse);
186
+
187
+ references = ([] as UAReference[]).concat(
188
+ references,
189
+ originalObject.findReferencesEx("HasEventSource", BrowseDirection.Inverse)
190
+ );
191
+
192
+ const { parentType, path } = _get_parent_type_and_path(originalObject);
193
+
194
+ if (parentType && parentType.subtypeOfObj) {
195
+ // parent is a ObjectType or VariableType and is not a root type
196
+ assert(parentType.nodeClass === NodeClass.VariableType || parentType.nodeClass === NodeClass.ObjectType);
197
+
198
+ // let investigate the same child base child
199
+ const child = followPath(parentType.subtypeOfObj, path);
200
+ if (child) {
201
+ const baseRef = findNonHierarchicalReferences(child);
202
+ references = ([] as UAReference[]).concat(references, baseRef);
203
+ }
204
+ }
205
+ // perform some cleanup
206
+ references = _remove_unwanted_ref(references);
207
+
208
+ return references;
209
+ }
210
+
211
+ export function reconstructNonHierarchicalReferences(extraInfo: CloneHelper): void {
212
+ const extraInfo_ = extraInfo as unknown as { mapOrgToClone: Map<string, CloneInfo> };
213
+
214
+ const findImplementedObject = (ref: UAReference): CloneInfo | null =>
215
+ extraInfo_.mapOrgToClone.get(ref.nodeId.toString()) || null;
216
+
217
+ // navigate through original objects to find those that are being references by node that
218
+ // have been cloned .
219
+ // this could be node organized by some FunctionalGroup
220
+
221
+ for (const { original, cloned } of extraInfo_.mapOrgToClone.values()) {
222
+ apply(original, cloned);
223
+ }
224
+ function apply(original: BaseNode, cloned: BaseNode) {
225
+ const addressSpace = original.addressSpace;
226
+ // find NonHierarchical References on original object
227
+ const originalNonHierarchical = findNonHierarchicalReferences(original);
228
+
229
+ if (originalNonHierarchical.length === 0) {
230
+ return;
231
+ }
232
+
233
+ // istanbul ignore next
234
+ if (doDebug) {
235
+ debugLog(
236
+ " investigation ",
237
+ original.browseName.toString(),
238
+ cloned.nodeClass.toString(),
239
+ original.nodeClass.toString(),
240
+ original.nodeId.toString(),
241
+ cloned.nodeId.toString()
242
+ );
243
+ }
244
+
245
+ for (const ref of originalNonHierarchical) {
246
+ const info = findImplementedObject(ref);
247
+
248
+ // if the object pointed by this reference is also cloned ...
249
+ if (info) {
250
+ const originalDest = info.original;
251
+ const cloneDest = info.cloned;
252
+
253
+ // istanbul ignore next
254
+ if (doDebug) {
255
+ debugLog(
256
+ " adding reference ",
257
+ ref.referenceType,
258
+ addressSpace.findNode(ref.referenceType)!.browseName.toString(),
259
+ " from cloned ",
260
+ cloned.nodeId.toString(),
261
+ cloned.browseName.toString(),
262
+ " to cloned ",
263
+ cloneDest.nodeId.toString(),
264
+ cloneDest.browseName.toString()
265
+ );
266
+ }
267
+
268
+ // restore reference
269
+ cloned.addReference({
270
+ isForward: false,
271
+ nodeId: cloneDest.nodeId,
272
+ referenceType: ref.referenceType
273
+ });
274
+ } else {
275
+ // // restore reference
276
+ // cloned.addReference({
277
+ // isForward: false,
278
+ // nodeId: ref.nodeId,
279
+ // referenceType: ref.referenceType
280
+ // });
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ /**
287
+ * recreate functional group types according to type definition
288
+ *
289
+ * @method reconstructFunctionalGroupType
290
+ * @param baseType
291
+ */
292
+
293
+ /* @example:
294
+ *
295
+ * MyDeviceType
296
+ * |
297
+ * +----------|- ParameterSet(BaseObjectType)
298
+ * | |
299
+ * | +-----------------|- Parameter1
300
+ * | ^
301
+ * +----------|- Config(FunctionalGroupType) |
302
+ * | |
303
+ * +-------- Organizes---+
304
+ */
305
+ export function reconstructFunctionalGroupType(extraInfo: CloneHelper) {
306
+ const extraInfo_ = extraInfo as unknown as { mapOrgToClone: Map<string, CloneInfo> };
307
+
308
+ // navigate through original objects to find those that are being organized by some FunctionalGroup
309
+ for (const { original, cloned } of extraInfo_.mapOrgToClone.values()) {
310
+ const organizedByArray = original.findReferencesEx("Organizes", BrowseDirection.Inverse);
311
+
312
+ for (const ref of organizedByArray) {
313
+ const info = extraInfo_.mapOrgToClone.get(ref.nodeId.toString());
314
+ if (!info) continue;
315
+
316
+ const folder = info.original;
317
+ if (folder.nodeClass !== NodeClass.Object) continue;
318
+
319
+ if (!folder.typeDefinitionObj) continue;
320
+
321
+ assert(folder.typeDefinitionObj.browseName.name!.toString() === "FunctionalGroupType");
322
+
323
+ // now create the same reference with the instantiated function group
324
+ const destFolder = info.cloned as BaseNode;
325
+
326
+ assert(ref.referenceType);
327
+
328
+ // may be we should check that the referenceType is a subtype of Organizes
329
+ const alreadyExist = destFolder
330
+ .findReferences(ref.referenceType, !ref.isForward)
331
+ .find((r) => r.nodeId === cloned.nodeId);
332
+ if (alreadyExist) {
333
+ continue;
334
+ }
335
+
336
+ destFolder.addReference({
337
+ isForward: !ref.isForward,
338
+ nodeId: cloned.nodeId,
339
+ referenceType: ref.referenceType
340
+ });
341
+ }
342
+ }
343
+ }
@@ -9,6 +9,7 @@ import { UAObject } from "./ua_object";
9
9
  import { UAObjectType } from "./ua_object_type";
10
10
  import { UAReference } from "./ua_reference";
11
11
  import { UAVariable } from "./ua_variable";
12
+ import { CloneHelper } from "./clone_helper";
12
13
 
13
14
  export interface CloneFilter {
14
15
  shouldKeep(node: BaseNode): boolean;
@@ -25,26 +26,11 @@ export interface CloneExtraInfo {
25
26
  /* */
26
27
  level: number;
27
28
  pad(): string;
28
- registerClonedObject(clonedObject: BaseNode, originalObject: BaseNode): void;
29
- getCloned(node: BaseNode): BaseNode | null;
29
+ registerClonedObject(clonedNode: BaseNode, originalNode: BaseNode): void;
30
+ getCloned(originalObject: BaseNode): BaseNode | null;
30
31
  }
31
- interface CloneExtraInfoEx extends CloneExtraInfo {
32
- _cloned: Map<BaseNode, BaseNode>;
33
- }
34
- export const defaultCloneExtraInfo: CloneExtraInfoEx = {
35
- level: 0,
36
- _cloned: new Map<BaseNode, BaseNode>(),
37
- pad(this: CloneExtraInfo) {
38
- return " ".padEnd(this.level * 2);
39
- },
40
- registerClonedObject(_clonedObject: BaseNode, _originalObject: BaseNode): void {
41
- if(this.getCloned(_originalObject)) throw new Error("cloned object is already registered.");
42
- this._cloned.set(_originalObject, _clonedObject);
43
- },
44
- getCloned(node: BaseNode): BaseNode | null {
45
- return this._cloned.get(node) || null;
46
- }
47
- };
32
+
33
+ export const makeDefaultCloneExtraInfo = (): CloneExtraInfo => new CloneHelper();
48
34
 
49
35
  export interface CloneOptions /* extends ConstructNodeIdOptions */ {
50
36
  namespace: INamespace;
package/source/index.ts CHANGED
@@ -21,3 +21,4 @@ export * from "./ua_variable_t";
21
21
  export * from "./ua_variable_type";
22
22
  export * from "./ua_variable";
23
23
  export * from "./ua_view";
24
+ export * from "./clone_helper";
@@ -281,9 +281,9 @@ export interface UAVariable extends BaseNode, VariableAttributes, IPropertyAndCo
281
281
 
282
282
  writeValue(context: ISessionContext, dataValue: DataValue, indexRange?: string | NumericRange | null): Promise<StatusCode>;
283
283
 
284
- asyncRefresh(oldestDate: Date, callback: CallbackT<DataValue>): void;
284
+ asyncRefresh(oldestDate: PreciseClock, callback: CallbackT<DataValue>): void;
285
285
 
286
- asyncRefresh(oldestDate: Date): Promise<DataValue>;
286
+ asyncRefresh(oldestDate: PreciseClock): Promise<DataValue>;
287
287
 
288
288
  /**
289
289
  * write a variable attribute (callback version)