node-opcua-address-space 2.186.15 → 2.187.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.
- package/api/address_space_public.ts +16 -0
- package/api/helpers/resolve_opaque_on_address_space.ts +13 -1
- package/api/index.ts +14 -3
- package/api/loader/store_record_applier.ts +267 -0
- package/api/session_context.ts +116 -27
- package/dist/api/address_space_public.d.ts +14 -0
- package/dist/api/address_space_public.d.ts.map +1 -1
- package/dist/api/address_space_public.js +3 -0
- package/dist/api/address_space_public.js.map +1 -1
- package/dist/api/helpers/resolve_opaque_on_address_space.d.ts +6 -0
- package/dist/api/helpers/resolve_opaque_on_address_space.d.ts.map +1 -1
- package/dist/api/helpers/resolve_opaque_on_address_space.js +12 -1
- package/dist/api/helpers/resolve_opaque_on_address_space.js.map +1 -1
- package/dist/api/index.d.ts +4 -3
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +4 -3
- package/dist/api/index.js.map +1 -1
- package/dist/api/loader/store_record_applier.d.ts +49 -0
- package/dist/api/loader/store_record_applier.d.ts.map +1 -0
- package/dist/api/loader/store_record_applier.js +235 -0
- package/dist/api/loader/store_record_applier.js.map +1 -0
- package/dist/api/session_context.d.ts +10 -0
- package/dist/api/session_context.d.ts.map +1 -1
- package/dist/api/session_context.js +100 -27
- package/dist/api/session_context.js.map +1 -1
- package/dist/impl/address_space.d.ts +2 -0
- package/dist/impl/address_space.d.ts.map +1 -1
- package/dist/impl/address_space.js +12 -2
- package/dist/impl/address_space.js.map +1 -1
- package/dist/impl/base_node_impl.d.ts +12 -0
- package/dist/impl/base_node_impl.d.ts.map +1 -1
- package/dist/impl/base_node_impl.js +35 -29
- package/dist/impl/base_node_impl.js.map +1 -1
- package/dist/impl/base_node_private.d.ts +5 -5
- package/dist/impl/base_node_private.d.ts.map +1 -1
- package/dist/impl/base_node_private.js +11 -5
- package/dist/impl/base_node_private.js.map +1 -1
- package/dist/impl/extension_object_array_node.d.ts +4 -2
- package/dist/impl/extension_object_array_node.d.ts.map +1 -1
- package/dist/impl/extension_object_array_node.js +5 -2
- package/dist/impl/extension_object_array_node.js.map +1 -1
- package/dist/impl/historical_access/address_space_historical_data_node.d.ts +26 -2
- package/dist/impl/historical_access/address_space_historical_data_node.d.ts.map +1 -1
- package/dist/impl/historical_access/address_space_historical_data_node.js +39 -0
- package/dist/impl/historical_access/address_space_historical_data_node.js.map +1 -1
- package/dist/impl/namespace_impl.d.ts.map +1 -1
- package/dist/impl/namespace_impl.js +3 -1
- package/dist/impl/namespace_impl.js.map +1 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.d.ts.map +1 -1
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js +28 -0
- package/dist/impl/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/impl/reference_impl.d.ts +2 -1
- package/dist/impl/reference_impl.d.ts.map +1 -1
- package/dist/impl/reference_impl.js +6 -5
- package/dist/impl/reference_impl.js.map +1 -1
- package/dist/impl/reference_index.d.ts +22 -0
- package/dist/impl/reference_index.d.ts.map +1 -0
- package/dist/impl/reference_index.js +104 -0
- package/dist/impl/reference_index.js.map +1 -0
- package/dist/impl/ua_variable_impl.d.ts +8 -0
- package/dist/impl/ua_variable_impl.d.ts.map +1 -1
- package/dist/impl/ua_variable_impl.js +121 -84
- package/dist/impl/ua_variable_impl.js.map +1 -1
- package/dist/tsconfig_base.tsbuildinfo +1 -1
- package/distNodeJS/generate_address_space.d.ts +6 -1
- package/distNodeJS/generate_address_space.d.ts.map +1 -1
- package/distNodeJS/generate_address_space.js +33 -1
- package/distNodeJS/generate_address_space.js.map +1 -1
- package/impl/address_space.ts +16 -2
- package/impl/base_node_impl.ts +52 -30
- package/impl/base_node_private.ts +16 -10
- package/impl/extension_object_array_node.ts +12 -3
- package/impl/historical_access/address_space_historical_data_node.ts +64 -1
- package/impl/namespace_impl.ts +3 -1
- package/impl/nodeset_tools/construct_namespace_dependency.ts +23 -1
- package/impl/reference_impl.ts +6 -5
- package/impl/reference_index.ts +116 -0
- package/impl/ua_variable_impl.ts +161 -94
- package/package.json +34 -33
- package/source_nodejs/generate_address_space.ts +46 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IAddressSpace } from "node-opcua-address-space-base";
|
|
2
|
-
import { type NamedNodesetSource, type NodeSetLoaderOptions, type NodesetSource, type NodesetToImageOptions } from "../dist/api/index.js";
|
|
2
|
+
import { type CompactAddressSpace, type NamedNodesetSource, type NodeSetLoaderOptions, type NodesetSource, type NodesetToImageOptions, type StoreRecordApplierOptions } from "../dist/api/index.js";
|
|
3
3
|
export declare function readNodeSet2XmlFile(xmlFile: string): Promise<string>;
|
|
4
4
|
/**
|
|
5
5
|
* a NodeSet2 file as a source the loader reads in chunks, opened when the loader gets to it
|
|
@@ -35,4 +35,9 @@ export declare function addressSpacePackageVersion(): string;
|
|
|
35
35
|
export declare function generateAddressSpace(addressSpace: IAddressSpace, xmlFiles: string | Array<string | NodesetSource>, options?: NodeSetLoaderOptions): Promise<void>;
|
|
36
36
|
/** the precompiled image of a NodeSet2 file or source, stamped with this package's version */
|
|
37
37
|
export declare function nodesetFileToImage(source: NodesetSource | string, options?: NodesetToImageOptions): Promise<Uint8Array>;
|
|
38
|
+
/**
|
|
39
|
+
* the NodeSet2 XML files loaded into a compact address space, in the order given, each
|
|
40
|
+
* streamed in chunks: no node object is created, the records go straight into the columns
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateCompactAddressSpace(addressSpace: CompactAddressSpace, documents: string | NodesetSource | Array<string | NodesetSource>, options?: StoreRecordApplierOptions): Promise<void>;
|
|
38
43
|
//# sourceMappingURL=generate_address_space.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate_address_space.d.ts","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,
|
|
1
|
+
{"version":3,"file":"generate_address_space.d.ts","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE,OAAO,EACH,KAAK,mBAAmB,EAGxB,KAAK,kBAAkB,EAEvB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAK1B,KAAK,yBAAyB,EAKjC,MAAM,sBAAsB,CAAC;AA0B9B,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO1E;AAKD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAWzE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAQ9E;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAG9E;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAuED,oFAAoF;AACpF,wBAAgB,0BAA0B,IAAI,MAAM,CAOnD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACtC,YAAY,EAAE,aAAa,EAC3B,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,EAChD,OAAO,CAAC,EAAE,oBAAoB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,8FAA8F;AAC9F,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,UAAU,CAAC,CAIjI;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC7C,YAAY,EAAE,mBAAmB,EACjC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,EACjE,OAAO,GAAE,yBAA8B,GACxC,OAAO,CAAC,IAAI,CAAC,CAmBf"}
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import zlib, { gunzip, gzip as gzipCb } from "node:zlib";
|
|
5
5
|
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
|
|
6
|
-
import { generateAddressSpaceRaw, nodesetImageProblem, nodesetToImage as nodesetToImageRaw, readNodesetImageInfo, setImageDeflater, setImageInflater, sha256Hex } from "../dist/api/index.js";
|
|
6
|
+
import { compactRecordConsumer, generateAddressSpaceRaw, NODESET2_XML_FORMAT, nodesetImageProblem, nodesetToImage as nodesetToImageRaw, openNodesetSource, readNodesetImageInfo, setImageDeflater, setImageInflater, sha256Hex, xmlNodesetRecords } from "../dist/api/index.js";
|
|
7
7
|
import { FileNodesetImageStore } from "./nodeset_image_file_store.js";
|
|
8
8
|
// an image given whole inflates through zlib here: a third of the cost of DecompressionStream on
|
|
9
9
|
// a 200 KB image, and in the thread pool, so that the XML hash runs alongside
|
|
@@ -197,4 +197,36 @@ export async function nodesetFileToImage(source, options = {}) {
|
|
|
197
197
|
const resolved = typeof source === "string" && !source.trimStart().startsWith("<") ? nodesetSourceFromFileWhole(source) : source;
|
|
198
198
|
return nodesetToImageRaw(resolved, { addressSpaceVersion: addressSpacePackageVersion(), ...options });
|
|
199
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* the NodeSet2 XML files loaded into a compact address space, in the order given, each
|
|
202
|
+
* streamed in chunks: no node object is created, the records go straight into the columns
|
|
203
|
+
*/
|
|
204
|
+
export async function generateCompactAddressSpace(addressSpace, documents, options = {}) {
|
|
205
|
+
const list = Array.isArray(documents) ? documents : [documents];
|
|
206
|
+
const consumer = compactRecordConsumer(addressSpace, options);
|
|
207
|
+
for (const [index, document] of list.entries()) {
|
|
208
|
+
const source = typeof document === "string" ? nodesetSourceFromFile(document) : document;
|
|
209
|
+
const reader = openNodesetSource(source, index);
|
|
210
|
+
if ((await reader.probe()) !== NODESET2_XML_FORMAT) {
|
|
211
|
+
throw new Error(`generateCompactAddressSpace: ${reader.name} is not a NodeSet2 XML document (images are not loaded into a compact space yet)`);
|
|
212
|
+
}
|
|
213
|
+
for await (const record of xmlNodesetRecords(textChunks(reader.chunks()))) {
|
|
214
|
+
consumer.apply(record);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const { unresolved } = consumer.finish();
|
|
218
|
+
if (unresolved > 0) {
|
|
219
|
+
debugLog(`generateCompactAddressSpace: ${unresolved} references point at nodes no document declares`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/** the chunks of a source as text, whatever the stream yields */
|
|
223
|
+
async function* textChunks(chunks) {
|
|
224
|
+
const decoder = new TextDecoder();
|
|
225
|
+
for await (const chunk of chunks) {
|
|
226
|
+
yield typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
227
|
+
}
|
|
228
|
+
const tail = decoder.decode();
|
|
229
|
+
if (tail)
|
|
230
|
+
yield tail;
|
|
231
|
+
}
|
|
200
232
|
//# sourceMappingURL=generate_address_space.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate_address_space.js","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,
|
|
1
|
+
{"version":3,"file":"generate_address_space.js","sourceRoot":"","sources":["../source_nodejs/generate_address_space.ts"],"names":[],"mappings":"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"}
|
package/impl/address_space.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
UAVariableType,
|
|
25
25
|
UAView
|
|
26
26
|
} from "node-opcua-address-space-base";
|
|
27
|
+
import { StoreAddressSpace, type StoreAddressSpaceOptions } from "node-opcua-address-space-store";
|
|
27
28
|
import { assert } from "node-opcua-assert";
|
|
28
29
|
import type { ExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
29
30
|
import { DataTypeIds, VariableTypeIds } from "node-opcua-constants";
|
|
@@ -63,7 +64,10 @@ import { UAAcknowledgeableConditionImplBase, UAConditionImplBase } from "./alarm
|
|
|
63
64
|
import { BaseNodeImpl, defineSharedChildAccessors } from "./base_node_impl.js";
|
|
64
65
|
import { EventData } from "./event_data.js";
|
|
65
66
|
import { getEventLayout } from "./event_layout.js";
|
|
66
|
-
import {
|
|
67
|
+
import {
|
|
68
|
+
AddressSpace_installHistoricalDataNode,
|
|
69
|
+
createDetachedHistorian
|
|
70
|
+
} from "./historical_access/address_space_historical_data_node.js";
|
|
67
71
|
import { historizerFactoryHolder } from "./historizer_factory.js";
|
|
68
72
|
import { isNonEmptyQualifiedName, NamespaceImpl } from "./namespace_impl.js";
|
|
69
73
|
import type { NamespacePrivate } from "./namespace_private.js";
|
|
@@ -83,6 +87,9 @@ import Dequeue from "dequeue";
|
|
|
83
87
|
|
|
84
88
|
const regexNumberColumnString = /^([0-9]+):(.*)/;
|
|
85
89
|
const enumerationTypeNodeId = coerceNodeId(DataTypeIds.Enumeration);
|
|
90
|
+
// "RootFolder" is a name of namespace 0, never a "<index>:<alias>" string, so it resolves the same
|
|
91
|
+
// way in every address space. rootFolder is read on every permission check, i.e. on every Read.
|
|
92
|
+
const rootFolderNodeId = resolveNodeId("RootFolder");
|
|
86
93
|
/**
|
|
87
94
|
* Extracts the namespace and browse name as a string from the given input.
|
|
88
95
|
*
|
|
@@ -160,7 +167,7 @@ function isNodeIdString(str: unknown): boolean {
|
|
|
160
167
|
*/
|
|
161
168
|
export class AddressSpaceImpl implements AddressSpacePrivate {
|
|
162
169
|
public get rootFolder(): UARootFolder {
|
|
163
|
-
const rootFolder = this.findNode(
|
|
170
|
+
const rootFolder = this.findNode(rootFolderNodeId);
|
|
164
171
|
if (!rootFolder) {
|
|
165
172
|
// throw new Error("AddressSpace doesn't contain rootFolder object");
|
|
166
173
|
return null as unknown as UARootFolder;
|
|
@@ -186,6 +193,13 @@ export class AddressSpaceImpl implements AddressSpacePrivate {
|
|
|
186
193
|
return new AddressSpaceImpl();
|
|
187
194
|
}
|
|
188
195
|
|
|
196
|
+
public static createCompact(options?: StoreAddressSpaceOptions): StoreAddressSpace {
|
|
197
|
+
const space = new StoreAddressSpace(options);
|
|
198
|
+
// installHistoricalDataNode without a historian of its own: the values in memory, as for a node object
|
|
199
|
+
space.historianFactory = (variable, historianOptions) => createDetachedHistorian(variable, historianOptions);
|
|
200
|
+
return space;
|
|
201
|
+
}
|
|
202
|
+
|
|
189
203
|
private static registry = new ObjectRegistry();
|
|
190
204
|
|
|
191
205
|
/***
|
package/impl/base_node_impl.ts
CHANGED
|
@@ -89,13 +89,8 @@ import {
|
|
|
89
89
|
reservedChildAccessorNames,
|
|
90
90
|
resolveChildInIndex
|
|
91
91
|
} from "./child_accessors.js";
|
|
92
|
-
import {
|
|
93
|
-
|
|
94
|
-
type MinimalistAddressSpace,
|
|
95
|
-
nodeIdKey,
|
|
96
|
-
ReferenceImpl,
|
|
97
|
-
type ReferenceKey
|
|
98
|
-
} from "./reference_impl.js";
|
|
92
|
+
import { isMassivelyUsedReferenceType, type MinimalistAddressSpace, nodeIdKey, ReferenceImpl } from "./reference_impl.js";
|
|
93
|
+
import type { ReferenceIndex } from "./reference_index.js";
|
|
99
94
|
import { referenceTypeVersion } from "./reference_type_version.js";
|
|
100
95
|
import { coerceRolePermissions } from "./role_permissions.js";
|
|
101
96
|
|
|
@@ -230,17 +225,17 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
230
225
|
|
|
231
226
|
/** see BaseNode.releaseStatus; only set when the nodeset declared one, so that it costs
|
|
232
227
|
* nothing on the overwhelming majority of nodes, which are Released */
|
|
233
|
-
public releaseStatus?: "Draft" | "Deprecated";
|
|
228
|
+
declare public releaseStatus?: "Draft" | "Deprecated";
|
|
234
229
|
/** see BaseNode.nodesetDocumentation; only set when the nodeset declared one */
|
|
235
|
-
public nodesetDocumentation?: string;
|
|
230
|
+
declare public nodesetDocumentation?: string;
|
|
236
231
|
/** see BaseNode.nodesetCategory; only set when the nodeset declared at least one */
|
|
237
|
-
public nodesetCategory?: string[];
|
|
232
|
+
declare public nodesetCategory?: string[];
|
|
238
233
|
/** see BaseNode.designToolOnly; only set when the nodeset declared it */
|
|
239
|
-
public designToolOnly?: boolean;
|
|
234
|
+
declare public designToolOnly?: boolean;
|
|
240
235
|
/** see BaseNode.declaredAccessRestrictions */
|
|
241
|
-
public declaredAccessRestrictions?: string;
|
|
242
|
-
private _accessRestrictions?: AccessRestrictionsFlag;
|
|
243
|
-
private _rolePermissions?: RolePermissionType[];
|
|
236
|
+
declare public declaredAccessRestrictions?: string;
|
|
237
|
+
declare private _accessRestrictions?: AccessRestrictionsFlag;
|
|
238
|
+
declare private _rolePermissions?: RolePermissionType[];
|
|
244
239
|
|
|
245
240
|
// public onFirstBrowseAction?: (this: BaseNode<T>) => Promise<void>;
|
|
246
241
|
|
|
@@ -307,9 +302,12 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
307
302
|
/**
|
|
308
303
|
* returns the nodeId of this node's Type Definition
|
|
309
304
|
*/
|
|
305
|
+
/** the type definition, remembered on the node: a cache object for it alone was 56 bytes per node */
|
|
306
|
+
declare private _typeDefinition?: NodeId;
|
|
307
|
+
declare private _typeDefinitionObj?: UAObjectType | UAVariableType | null;
|
|
308
|
+
|
|
310
309
|
public get typeDefinition(): NodeId {
|
|
311
|
-
|
|
312
|
-
if (!_cache.typeDefinition) {
|
|
310
|
+
if (!this._typeDefinition) {
|
|
313
311
|
const has_type_definition_ref = this.findReference("HasTypeDefinition", true);
|
|
314
312
|
let nodeId = has_type_definition_ref ? has_type_definition_ref.nodeId : null;
|
|
315
313
|
if (!nodeId) {
|
|
@@ -323,21 +321,20 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
323
321
|
default:
|
|
324
322
|
}
|
|
325
323
|
}
|
|
326
|
-
|
|
324
|
+
this._typeDefinition = nodeId as NodeId;
|
|
327
325
|
}
|
|
328
|
-
return
|
|
326
|
+
return this._typeDefinition;
|
|
329
327
|
}
|
|
330
328
|
|
|
331
329
|
/**
|
|
332
330
|
* returns the nodeId of this node's Type Definition
|
|
333
331
|
*/
|
|
334
332
|
public get typeDefinitionObj(): UAObjectType | UAVariableType {
|
|
335
|
-
|
|
336
|
-
if (undefined === _cache.typeDefinitionObj) {
|
|
333
|
+
if (undefined === this._typeDefinitionObj) {
|
|
337
334
|
const nodeId = this.typeDefinition;
|
|
338
|
-
|
|
335
|
+
this._typeDefinitionObj = nodeId ? (this.addressSpace.findNode(nodeId) as UAObjectType | UAVariableType) : null;
|
|
339
336
|
}
|
|
340
|
-
if (!
|
|
337
|
+
if (!this._typeDefinitionObj) {
|
|
341
338
|
warningLog(
|
|
342
339
|
this.nodeClass,
|
|
343
340
|
"cannot find typeDefinitionObj ",
|
|
@@ -346,7 +343,7 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
346
343
|
NodeClass[this.nodeClass]
|
|
347
344
|
);
|
|
348
345
|
}
|
|
349
|
-
return
|
|
346
|
+
return this._typeDefinitionObj as UAObjectType | UAVariableType;
|
|
350
347
|
}
|
|
351
348
|
|
|
352
349
|
public get parentNodeId(): NodeId | undefined {
|
|
@@ -397,7 +394,7 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
397
394
|
public readonly nodeId: NodeId;
|
|
398
395
|
public readonly browseName: QualifiedName;
|
|
399
396
|
|
|
400
|
-
protected _postInstantiateFunc?: (instance: BaseNode, instanceType: BaseNode, options?: unknown) => void;
|
|
397
|
+
declare protected _postInstantiateFunc?: (instance: BaseNode, instanceType: BaseNode, options?: unknown) => void;
|
|
401
398
|
|
|
402
399
|
/**
|
|
403
400
|
* @internal
|
|
@@ -405,6 +402,10 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
405
402
|
*/
|
|
406
403
|
constructor(options: InternalBaseNodeOptions) {
|
|
407
404
|
super();
|
|
405
|
+
// EventEmitter allocates its listener table in its constructor, although every one of
|
|
406
|
+
// its methods also creates it on first use. Few nodes ever get a listener, and the
|
|
407
|
+
// table is 185 bytes: on a large model that is a tenth of the address space
|
|
408
|
+
(this as unknown as { _events?: unknown })._events = undefined;
|
|
408
409
|
|
|
409
410
|
assert(this.nodeClass === NodeClass.Unspecified, "must not be specify a nodeClass");
|
|
410
411
|
assert(options.addressSpace); // expecting an address space
|
|
@@ -551,7 +552,7 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
551
552
|
const results: UAReference[] = [];
|
|
552
553
|
const addressSpace = this.addressSpace;
|
|
553
554
|
let unresolved = false;
|
|
554
|
-
const process = (referenceIdx:
|
|
555
|
+
const process = (referenceIdx: ReferenceIndex) => {
|
|
555
556
|
for (const ref of referenceIdx.values()) {
|
|
556
557
|
if (ref.isForward === isForward && referenceTypeNode.checkHasSubtype(ref.referenceType)) {
|
|
557
558
|
// callers read ref.node: resolved here, once per reference, for the references a
|
|
@@ -596,14 +597,21 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
596
597
|
}
|
|
597
598
|
|
|
598
599
|
public findReferences(referenceType: string | NodeId | UAReferenceType, isForward = true): UAReference[] {
|
|
599
|
-
const _cache = BaseNode_getCache(this);
|
|
600
600
|
const referenceTypeNode = this._coerceReferenceType(referenceType);
|
|
601
601
|
if (!referenceTypeNode) {
|
|
602
602
|
// note: when loading nodeset2.xml files, reference type may not exit yet
|
|
603
603
|
// throw new Error("expecting valid reference name " + strReference);
|
|
604
604
|
return [];
|
|
605
605
|
}
|
|
606
|
-
|
|
606
|
+
// the memo is for the nodes a scan is worth remembering on (see findReferencesEx): on a
|
|
607
|
+
// leaf node, scanning three references costs less than the memo would, and the memo
|
|
608
|
+
// (a cache object, a Map, a key string and a result array per question) was the single
|
|
609
|
+
// largest part of what a node weighed: every node is asked its type definition once
|
|
610
|
+
const _private = BaseNode_getPrivate(this);
|
|
611
|
+
if (_private._referenceIdx.size + _private._back_referenceIdx.size <= referenceScanMemoThreshold) {
|
|
612
|
+
return this.findReferences_no_cache(referenceTypeNode, isForward);
|
|
613
|
+
}
|
|
614
|
+
const _cache = BaseNode_getCache(this);
|
|
607
615
|
_cache._ref = _cache._ref || new Map();
|
|
608
616
|
|
|
609
617
|
const hash = `r|${referenceTypeNode.nodeId.toString()}|${isForward ? "f" : "b"}`;
|
|
@@ -1074,7 +1082,7 @@ export abstract class BaseNodeImpl<T extends BaseNodeEvents & ListenerSignature<
|
|
|
1074
1082
|
if (do_debug) {
|
|
1075
1083
|
// c8 ignore next
|
|
1076
1084
|
doDebug && debugLog("all references :", this.nodeId.toString(), this.browseName.toString());
|
|
1077
|
-
dumpReferences(addressSpace, _private._referenceIdx.values());
|
|
1085
|
+
dumpReferences(addressSpace, [..._private._referenceIdx.values()]);
|
|
1078
1086
|
}
|
|
1079
1087
|
|
|
1080
1088
|
// filter out references not matching referenceType
|
|
@@ -1758,8 +1766,8 @@ function toString_ReferenceDescription(ref: UAReference, options: { addressSpace
|
|
|
1758
1766
|
return str;
|
|
1759
1767
|
}
|
|
1760
1768
|
|
|
1761
|
-
function _setup_parent_item(this: BaseNode, referencesMap:
|
|
1762
|
-
let references: UAReference[]
|
|
1769
|
+
function _setup_parent_item(this: BaseNode, referencesMap: ReferenceIndex): BaseNode | null {
|
|
1770
|
+
let references: UAReference[];
|
|
1763
1771
|
|
|
1764
1772
|
const _private = BaseNode_getPrivate(this);
|
|
1765
1773
|
assert(!_private._parent, "_setup_parent_item has been already called");
|
|
@@ -2180,6 +2188,9 @@ export function defineSharedChildAccessors(browseNames: string[]): void {
|
|
|
2180
2188
|
*
|
|
2181
2189
|
* This is the runtime fallback of child_accessors.ts, for names no loaded nodeset declared.
|
|
2182
2190
|
*/
|
|
2191
|
+
/** see install_child_as_object_property */
|
|
2192
|
+
export const maxOwnChildAccessorsPerParent = 1000;
|
|
2193
|
+
|
|
2183
2194
|
/** the child an own accessor was installed for, kept on the getter itself */
|
|
2184
2195
|
const installedFor = Symbol("installedFor");
|
|
2185
2196
|
type OwnChildAccessor = { [installedFor]?: BaseNode };
|
|
@@ -2193,6 +2204,15 @@ function install_child_as_object_property(parentObj: BaseNode | null, child: Bas
|
|
|
2193
2204
|
if (!name || isReservedChildAccessorName(name) || hasSharedChildAccessor(name) || name in parentObj) {
|
|
2194
2205
|
return;
|
|
2195
2206
|
}
|
|
2207
|
+
// a parent with a thousand runtime-named children (a folder of tags) is not addressed as
|
|
2208
|
+
// `folder.tag123` by anyone; past that many, the children stay reachable by getChildByName
|
|
2209
|
+
// and browse, and the parent is spared an accessor (170 bytes) per child and dictionary mode
|
|
2210
|
+
const parentPrivate = BaseNode_getPrivate(parentObj);
|
|
2211
|
+
const installed = parentPrivate._ownChildAccessors ?? 0;
|
|
2212
|
+
if (installed >= maxOwnChildAccessorsPerParent) {
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
parentPrivate._ownChildAccessors = installed + 1;
|
|
2196
2216
|
doDebug && debugLog(`Installing property ${name}`, " on ", parentObj.browseName.toString());
|
|
2197
2217
|
const get: (() => BaseNode | undefined) & OwnChildAccessor = () =>
|
|
2198
2218
|
// an own property wins over the prototype: should the name get a shared getter later
|
|
@@ -2220,6 +2240,8 @@ function uninstall_child_object_property(parentObj: BaseNode, child: BaseNode):
|
|
|
2220
2240
|
return;
|
|
2221
2241
|
}
|
|
2222
2242
|
delete (parentObj as unknown as Record<string, unknown>)[name];
|
|
2243
|
+
const parentPrivate = BaseNode_getPrivate(parentObj);
|
|
2244
|
+
parentPrivate._ownChildAccessors = Math.max(0, (parentPrivate._ownChildAccessors ?? 1) - 1);
|
|
2223
2245
|
}
|
|
2224
2246
|
|
|
2225
2247
|
export function getReferenceType(reference: UAReference): UAReferenceType {
|
|
@@ -40,7 +40,8 @@ import { ReferenceDescription, type ReferenceDescriptionOptions } from "node-opc
|
|
|
40
40
|
import type { AddressSpacePrivate } from "./address_space_private.js";
|
|
41
41
|
import { BaseNodeImpl, getReferenceType } from "./base_node_impl.js";
|
|
42
42
|
import { UANamespace_process_modelling_rule } from "./namespace_private.js";
|
|
43
|
-
import { ReferenceImpl
|
|
43
|
+
import { ReferenceImpl } from "./reference_impl.js";
|
|
44
|
+
import { ReferenceIndex } from "./reference_index.js";
|
|
44
45
|
import { referenceTypeVersion, typeHierarchyVersion } from "./reference_type_version.js";
|
|
45
46
|
import { wipeMemorizedStuff } from "./tool_isSubtypeOf.js";
|
|
46
47
|
|
|
@@ -58,8 +59,6 @@ const PRIVATE = Symbol("BaseNodePrivate");
|
|
|
58
59
|
type WithPrivate = { [PRIVATE]?: BaseNodeCache };
|
|
59
60
|
|
|
60
61
|
interface BaseNodeCacheInner {
|
|
61
|
-
typeDefinition?: NodeId;
|
|
62
|
-
typeDefinitionObj?: UAVariableType | UAObjectType | null;
|
|
63
62
|
_children?: BaseNode[];
|
|
64
63
|
_versionNode?: UAVariableT<string, DataType.String> | null;
|
|
65
64
|
|
|
@@ -118,23 +117,25 @@ interface BaseNodeCache {
|
|
|
118
117
|
* the references other nodes hold to this one; `EMPTY_REFERENCE_INDEX` until the first one
|
|
119
118
|
* arrives, since a nodeset declares most references from both ends and most nodes never get one
|
|
120
119
|
*/
|
|
121
|
-
_back_referenceIdx:
|
|
122
|
-
_referenceIdx:
|
|
120
|
+
_back_referenceIdx: ReferenceIndex;
|
|
121
|
+
_referenceIdx: ReferenceIndex;
|
|
123
122
|
/** the property name this node is exposed as on its parents (see child_accessors.ts) */
|
|
124
123
|
_accessorName?: string;
|
|
124
|
+
/** how many children this node exposes through an own accessor (see install_child_as_object_property) */
|
|
125
|
+
_ownChildAccessors?: number;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
/**
|
|
128
129
|
* shared by every node without back references; read like any map, never written to: the first
|
|
129
130
|
* back reference replaces it with a map of the node's own (BaseNode_add_backward_reference)
|
|
130
131
|
*/
|
|
131
|
-
const EMPTY_REFERENCE_INDEX:
|
|
132
|
+
const EMPTY_REFERENCE_INDEX: ReferenceIndex = new ReferenceIndex();
|
|
132
133
|
|
|
133
134
|
export function BaseNode_initPrivate(self: BaseNode): BaseNodeCache {
|
|
134
135
|
const _private: BaseNodeCache = {
|
|
135
136
|
__address_space: null,
|
|
136
137
|
|
|
137
|
-
_referenceIdx: new
|
|
138
|
+
_referenceIdx: new ReferenceIndex(),
|
|
138
139
|
_back_referenceIdx: EMPTY_REFERENCE_INDEX,
|
|
139
140
|
|
|
140
141
|
_browseFilter: undefined,
|
|
@@ -157,7 +158,7 @@ export function BaseNode_removePrivate(self: BaseNode): void {
|
|
|
157
158
|
_private._cache = undefined;
|
|
158
159
|
_private.__address_space = null;
|
|
159
160
|
_private._back_referenceIdx = EMPTY_REFERENCE_INDEX;
|
|
160
|
-
_private._referenceIdx = new
|
|
161
|
+
_private._referenceIdx = new ReferenceIndex();
|
|
161
162
|
_private._childByNameMap = undefined;
|
|
162
163
|
_private._description = undefined;
|
|
163
164
|
_private._descriptionRaw = undefined;
|
|
@@ -195,6 +196,10 @@ export function BaseNode_clearCache(node: BaseNode): void {
|
|
|
195
196
|
if (_private?._cache) {
|
|
196
197
|
_private._cache = undefined;
|
|
197
198
|
}
|
|
199
|
+
// the type definition is remembered on the node itself (see BaseNodeImpl#typeDefinition)
|
|
200
|
+
const typed = node as unknown as { _typeDefinition?: unknown; _typeDefinitionObj?: unknown };
|
|
201
|
+
typed._typeDefinition = undefined;
|
|
202
|
+
typed._typeDefinitionObj = undefined;
|
|
198
203
|
wipeMemorizedStuff(node);
|
|
199
204
|
}
|
|
200
205
|
const hasTypeDefinition_ReferenceTypeNodeId = resolveNodeId("HasTypeDefinition");
|
|
@@ -1367,8 +1372,9 @@ export function BaseNode_remove_backward_reference(this: BaseNodeImpl, reference
|
|
|
1367
1372
|
if (_private._back_referenceIdx.has(h)) {
|
|
1368
1373
|
// note : h may not exist in _back_referenceIdx since we are not indexing
|
|
1369
1374
|
// _back_referenceIdx to UAObjectType and UAVariableType for performance reasons
|
|
1370
|
-
|
|
1375
|
+
const backward = <ReferenceImpl>_private._back_referenceIdx.get(h);
|
|
1371
1376
|
_private._back_referenceIdx.delete(h);
|
|
1377
|
+
backward.dispose();
|
|
1372
1378
|
// the memoized reference scans of this node listed the reference just removed
|
|
1373
1379
|
BaseNode_clearCache(this);
|
|
1374
1380
|
noteReferenceTypeChange(this, reference);
|
|
@@ -1421,7 +1427,7 @@ export function BaseNode_add_backward_reference(this: BaseNodeImpl, reference: U
|
|
|
1421
1427
|
}
|
|
1422
1428
|
// assert(reference._referenceType instanceof ReferenceType);
|
|
1423
1429
|
if (_private._back_referenceIdx === EMPTY_REFERENCE_INDEX) {
|
|
1424
|
-
_private._back_referenceIdx = new
|
|
1430
|
+
_private._back_referenceIdx = new ReferenceIndex();
|
|
1425
1431
|
}
|
|
1426
1432
|
_private._back_referenceIdx.set(h, reference);
|
|
1427
1433
|
noteReferenceTypeChange(this, reference);
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
* @module node-opcua-address-space.Private
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
BindVariableOptionsVariation1,
|
|
7
|
+
INamespace,
|
|
8
|
+
UADynamicVariableArray,
|
|
9
|
+
UAObject,
|
|
10
|
+
UAVariable
|
|
11
|
+
} from "node-opcua-address-space-base";
|
|
6
12
|
import { assert } from "node-opcua-assert";
|
|
7
13
|
import { BrowseDirection, NodeClass, type QualifiedName, type QualifiedNameLike } from "node-opcua-data-model";
|
|
8
14
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
@@ -238,7 +244,9 @@ export function bindExtObjArrayNode<T extends ExtensionObject>(
|
|
|
238
244
|
*/
|
|
239
245
|
export function addElement<T extends ExtensionObject>(
|
|
240
246
|
options: UAVariable | ExtensionObject | Record<string, unknown>,
|
|
241
|
-
uaArrayVariableNode: UADynamicVariableArray<T
|
|
247
|
+
uaArrayVariableNode: UADynamicVariableArray<T>,
|
|
248
|
+
/** where the element's Variable is created when one is made for it; the address space's own namespace by default */
|
|
249
|
+
namespace?: INamespace
|
|
242
250
|
): UAVariable {
|
|
243
251
|
assert(uaArrayVariableNode, " must provide an UAVariable containing the array");
|
|
244
252
|
// verify that arr has been created correctly
|
|
@@ -287,7 +295,8 @@ export function addElement<T extends ExtensionObject>(
|
|
|
287
295
|
elVar = uaArrayVariableNode.$$variableType.instantiate({
|
|
288
296
|
browseName,
|
|
289
297
|
componentOf: uaArrayVariableNode.nodeId,
|
|
290
|
-
value: { dataType: DataType.ExtensionObject, value: extensionObject }
|
|
298
|
+
value: { dataType: DataType.ExtensionObject, value: extensionObject },
|
|
299
|
+
...(namespace ? { namespace } : {})
|
|
291
300
|
}) as UAVariableImpl;
|
|
292
301
|
elVar.bindExtensionObject(extensionObject, { force: true });
|
|
293
302
|
}
|
|
@@ -13,10 +13,11 @@ import type {
|
|
|
13
13
|
UAVariable
|
|
14
14
|
} from "node-opcua-address-space-base";
|
|
15
15
|
import { assert } from "node-opcua-assert";
|
|
16
|
-
import { AccessLevelFlag, NodeClass, type QualifiedNameLike } from "node-opcua-data-model";
|
|
16
|
+
import { AccessLevelFlag, NodeClass, type QualifiedName, type QualifiedNameLike } from "node-opcua-data-model";
|
|
17
17
|
import { DataValue } from "node-opcua-data-value";
|
|
18
18
|
import { isMinDate, minDate } from "node-opcua-date-time";
|
|
19
19
|
import { make_warningLog } from "node-opcua-debug";
|
|
20
|
+
import type { NodeId } from "node-opcua-nodeid";
|
|
20
21
|
import type { UAHistoricalDataConfiguration } from "node-opcua-nodeset-ua";
|
|
21
22
|
import type { NumericRange } from "node-opcua-numeric-range";
|
|
22
23
|
import {
|
|
@@ -1033,3 +1034,65 @@ export function AddressSpace_installHistoricalDataNode(
|
|
|
1033
1034
|
|
|
1034
1035
|
node.addressSpace.onHistorizingNodeAdded?.(node);
|
|
1035
1036
|
}
|
|
1037
|
+
|
|
1038
|
+
// ---------------------------------------------------------------- Variables that are not node objects
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* what HistoryRead needs of a Variable that is not a node object (a node of the compact address
|
|
1042
|
+
* space): the historian that holds its values, and the session's right to read them
|
|
1043
|
+
*/
|
|
1044
|
+
export interface IHistoryReadTarget {
|
|
1045
|
+
nodeId: NodeId;
|
|
1046
|
+
browseName: QualifiedName;
|
|
1047
|
+
varHistorian: IVariableHistorian;
|
|
1048
|
+
canUserReadHistory(context: ISessionContext): boolean;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* HistoryRead on such a Variable, with the logic of the node objects (raw and modified values,
|
|
1053
|
+
* values at a time, continuation points). Processed values (aggregates) answer
|
|
1054
|
+
* BadHistoryOperationUnsupported: they are computed on the node objects.
|
|
1055
|
+
*/
|
|
1056
|
+
export function historyReadThrough(
|
|
1057
|
+
target: IHistoryReadTarget,
|
|
1058
|
+
context: ISessionContext,
|
|
1059
|
+
historyReadDetails: ReadRawModifiedDetails | ReadEventDetails | ReadProcessedDetails | ReadAtTimeDetails,
|
|
1060
|
+
indexRange: NumericRange | null,
|
|
1061
|
+
dataEncoding: QualifiedNameLike | null,
|
|
1062
|
+
continuationData: ContinuationData
|
|
1063
|
+
): Promise<HistoryReadResult> {
|
|
1064
|
+
// the members the functions of the node objects read through `this`
|
|
1065
|
+
const node = {
|
|
1066
|
+
nodeId: target.nodeId,
|
|
1067
|
+
browseName: target.browseName,
|
|
1068
|
+
varHistorian: target.varHistorian,
|
|
1069
|
+
historizing: true,
|
|
1070
|
+
canUserReadHistory: (c: ISessionContext) => target.canUserReadHistory(c),
|
|
1071
|
+
addressSpace: undefined,
|
|
1072
|
+
$historicalDataConfiguration: undefined,
|
|
1073
|
+
_historyReadRaw,
|
|
1074
|
+
_historyReadRawAsync,
|
|
1075
|
+
_historyReadModify,
|
|
1076
|
+
_historyReadRawModify
|
|
1077
|
+
} as unknown as UAVariableImpl;
|
|
1078
|
+
return new Promise<HistoryReadResult>((resolve, reject) => {
|
|
1079
|
+
_historyRead.call(node, context, historyReadDetails, indexRange, dataEncoding, continuationData, (err, result) => {
|
|
1080
|
+
if (err || !result) reject(err ?? new Error("historyReadThrough: no result"));
|
|
1081
|
+
else resolve(result);
|
|
1082
|
+
});
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/** the historian a Variable that is not a node object gets by default: its last values in memory */
|
|
1087
|
+
export function createDetachedHistorian(
|
|
1088
|
+
variable: { nodeId: NodeId; browseName: QualifiedName },
|
|
1089
|
+
options: IVariableHistorianOptions = {}
|
|
1090
|
+
): IVariableHistorian {
|
|
1091
|
+
// the archive dates of a node object's HistoricalDataConfiguration: such a Variable has none
|
|
1092
|
+
const node = {
|
|
1093
|
+
nodeId: variable.nodeId,
|
|
1094
|
+
browseName: variable.browseName,
|
|
1095
|
+
_update_startOfOnlineArchive: () => undefined
|
|
1096
|
+
} as unknown as UAVariable;
|
|
1097
|
+
return new VariableHistorian(node, options);
|
|
1098
|
+
}
|
package/impl/namespace_impl.ts
CHANGED
|
@@ -1996,7 +1996,9 @@ export class NamespaceImpl implements NamespacePrivate {
|
|
|
1996
1996
|
// ------------- set display name
|
|
1997
1997
|
if (!options.displayName) {
|
|
1998
1998
|
assert(typeof options.browseName.name === "string");
|
|
1999
|
-
|
|
1999
|
+
// kept as a string: the node builds the LocalizedText on first read, and most
|
|
2000
|
+
// nodes are never asked for their display name
|
|
2001
|
+
options.displayName = options.browseName.name || "";
|
|
2000
2002
|
}
|
|
2001
2003
|
if (!options.nodeClass || options.nodeClass === undefined) {
|
|
2002
2004
|
throw new Error("nodeclass must be specified");
|
|
@@ -3,7 +3,8 @@ import assert from "node-opcua-assert";
|
|
|
3
3
|
import { DataType } from "node-opcua-basic-types";
|
|
4
4
|
import { NodeClass } from "node-opcua-data-model";
|
|
5
5
|
import { make_debugLog, make_warningLog } from "node-opcua-debug";
|
|
6
|
-
import
|
|
6
|
+
import { ExtensionObject } from "node-opcua-extension-object";
|
|
7
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
7
8
|
import type { StructureField } from "node-opcua-types";
|
|
8
9
|
import { Variant } from "node-opcua-variant";
|
|
9
10
|
import type { TranslationTable } from "../../api/xml_writer.js";
|
|
@@ -11,6 +12,7 @@ import type { BaseNodeImpl } from "../base_node_impl.js";
|
|
|
11
12
|
import type { NamespacePrivate } from "../namespace_private.js";
|
|
12
13
|
import { ReferenceImpl } from "../reference_impl.js";
|
|
13
14
|
import type { UAVariableImpl } from "../ua_variable_impl.js";
|
|
15
|
+
import type { UAVariableTypeImpl } from "../ua_variable_type_impl.js";
|
|
14
16
|
|
|
15
17
|
const warningLog = make_warningLog("construct_namespace_dependency");
|
|
16
18
|
const _debugLog = make_debugLog("construct_namespace_dependency");
|
|
@@ -212,11 +214,31 @@ export function _getCompleteRequiredModelsFromValuesAndReferences(
|
|
|
212
214
|
}
|
|
213
215
|
};
|
|
214
216
|
|
|
217
|
+
// the exporter translates every NodeId a value holds (an Argument's DataType, a NodeId field of
|
|
218
|
+
// a structure, a NodeId variable), so each of their namespaces is a dependency whatever its priority
|
|
219
|
+
const exploreValue = (value: unknown): void => {
|
|
220
|
+
if (value === null || value === undefined) return;
|
|
221
|
+
if (value instanceof NodeId) {
|
|
222
|
+
consider(value.namespace);
|
|
223
|
+
} else if (value instanceof Variant) {
|
|
224
|
+
exploreValue(value.value);
|
|
225
|
+
} else if (Array.isArray(value)) {
|
|
226
|
+
for (const element of value) exploreValue(element);
|
|
227
|
+
} else if (value instanceof ExtensionObject) {
|
|
228
|
+
for (const fieldValue of Object.values(value)) exploreValue(fieldValue);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
215
232
|
const addressSpace = namespace.addressSpace;
|
|
216
233
|
const nonHierarchicalReferencesType = addressSpace.findReferenceType("NonHierarchicalReferences");
|
|
217
234
|
|
|
218
235
|
//const maxIndex = Math.max(...requiredNamespaceIndexes);
|
|
219
236
|
for (const node of namespace_.nodeIterator()) {
|
|
237
|
+
if (node.nodeClass === NodeClass.Variable) {
|
|
238
|
+
exploreValue((node as UAVariableImpl).$dataValue?.value);
|
|
239
|
+
} else if (node.nodeClass === NodeClass.VariableType) {
|
|
240
|
+
exploreValue((node as UAVariableTypeImpl).value);
|
|
241
|
+
}
|
|
220
242
|
const references = (<BaseNodeImpl>node).allReferences();
|
|
221
243
|
for (const reference of references) {
|
|
222
244
|
// check referenceId
|