node-opcua-address-space 2.181.0 → 2.182.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/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_acknowledgeable_condition_impl.ts +4 -4
- package/impl/alarms_and_conditions/ua_alarm_condition_impl.ts +19 -9
- package/impl/alarms_and_conditions/ua_base_event_impl.ts +9 -9
- package/impl/alarms_and_conditions/ua_certificate_expiration_alarm_impl.ts +17 -0
- package/impl/alarms_and_conditions/ua_condition_impl.ts +18 -18
- package/impl/alarms_and_conditions/ua_exclusive_deviation_alarm_impl.ts +2 -2
- package/impl/alarms_and_conditions/ua_exclusive_limit_alarm_impl.ts +1 -1
- package/impl/alarms_and_conditions/ua_limit_alarm_impl.ts +16 -16
- package/impl/alarms_and_conditions/ua_non_exclusive_deviation_alarm_impl.ts +2 -2
- package/impl/alarms_and_conditions/ua_non_exclusive_limit_alarm_impl.ts +4 -4
- package/impl/alarms_and_conditions/ua_off_normal_alarm_impl.ts +1 -1
- package/impl/base_node_impl.ts +15 -0
- package/impl/base_node_private.ts +97 -146
- package/impl/data_access/ua_multistate_discrete_impl.ts +1 -1
- package/impl/data_access/ua_multistate_value_discrete_impl.ts +2 -2
- package/impl/data_access/ua_two_state_discrete_impl.ts +2 -2
- 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/state_machine/finite_state_machine.ts +3 -3
- package/impl/state_machine/ua_shelving_state_machine_ex.ts +20 -20
- package/impl/ua_data_type_impl.ts +42 -4
- package/impl/ua_method_impl.ts +1 -1
- 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 +49 -3
- package/package.json +29 -27
- package/source_nodejs/generate_address_space.ts +7 -1
|
@@ -23,12 +23,29 @@ import { type LocalizedText, makeAccessLevelFlag, NodeClass, QualifiedName } fro
|
|
|
23
23
|
import { make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
24
24
|
import type { ExtensionObject } from "node-opcua-extension-object";
|
|
25
25
|
import { NodeId, NodeIdType } from "node-opcua-nodeid";
|
|
26
|
+
import { StatusCodes } from "node-opcua-status-code";
|
|
26
27
|
import { EnumDefinition, StructureDefinition, StructureType } from "node-opcua-types";
|
|
27
28
|
import { isNullOrUndefined, lowerFirstLetter } from "node-opcua-utils";
|
|
28
29
|
import { DataType, Variant, VariantArrayType } from "node-opcua-variant";
|
|
29
30
|
import XMLWriter from "xml-writer";
|
|
30
31
|
import { makeDefinitionMap } from "../../api/loader/decode_xml_extension_object.js";
|
|
31
32
|
import type { DefinitionMap2 } from "../../api/loader/make_xml_extension_object_parser.js";
|
|
33
|
+
import {
|
|
34
|
+
_dumpLocalizedText,
|
|
35
|
+
_dumpNodeId,
|
|
36
|
+
_dumpQualifiedName,
|
|
37
|
+
_dumpXmlElement,
|
|
38
|
+
b,
|
|
39
|
+
coerceInt64ToInt32,
|
|
40
|
+
findXsdNamespaceUri,
|
|
41
|
+
getPrefix,
|
|
42
|
+
initXmlWriterEx,
|
|
43
|
+
int64ToDecimalString,
|
|
44
|
+
makeTypeXsd,
|
|
45
|
+
n,
|
|
46
|
+
restoreDefaultNamespace,
|
|
47
|
+
startElementEx
|
|
48
|
+
} from "../../api/loader/nodeset_xml_primitives.js";
|
|
32
49
|
import { SessionContext } from "../../api/session_context.js";
|
|
33
50
|
import type { XmlWriter } from "../../api/xml_writer.js";
|
|
34
51
|
import { BaseNodeImpl, getReferenceType } from "../base_node_impl.js";
|
|
@@ -46,6 +63,8 @@ import {
|
|
|
46
63
|
} from "./construct_namespace_dependency.js";
|
|
47
64
|
import { type NodesetWalkEvent, namespaceToWalkEvents, nodeToWalkEvents, sortByNodeId } from "./nodeset_to_records.js";
|
|
48
65
|
|
|
66
|
+
export { coerceInt64ToInt32, initXmlWriterEx, makeTypeXsd } from "../../api/loader/nodeset_xml_primitives.js";
|
|
67
|
+
|
|
49
68
|
const debugLog = make_debugLog("nodeset_to_xml");
|
|
50
69
|
const warningLog = make_warningLog("nodeset_to_xml");
|
|
51
70
|
const errorLog = make_errorLog("nodeset_to_xml");
|
|
@@ -70,28 +89,6 @@ function _dumpDescription(xw: XmlWriter, node: { description?: LocalizedText }):
|
|
|
70
89
|
}
|
|
71
90
|
}
|
|
72
91
|
|
|
73
|
-
function translateNodeId(xw: XmlWriter, nodeId: NodeId): NodeId {
|
|
74
|
-
assert(nodeId instanceof NodeId);
|
|
75
|
-
const nn = xw.translationTable.get(nodeId.namespace);
|
|
76
|
-
const translatedNode = new NodeId(nodeId.identifierType, nodeId.value, nn);
|
|
77
|
-
return translatedNode;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function n(xw: XmlWriter, nodeId: NodeId): string {
|
|
81
|
-
return translateNodeId(xw, nodeId).toString().replace("ns=0;", "");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function translateBrowseName(xw: XmlWriter, browseName: QualifiedName): QualifiedName {
|
|
85
|
-
assert(browseName instanceof QualifiedName);
|
|
86
|
-
const nn = xw.translationTable.get(browseName.namespaceIndex);
|
|
87
|
-
const translatedBrowseName = new QualifiedName({ namespaceIndex: nn, name: browseName.name });
|
|
88
|
-
return translatedBrowseName;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function b(xw: XmlWriter, browseName: QualifiedName): string {
|
|
92
|
-
return translateBrowseName(xw, browseName).toString().replace("ns=0;", "");
|
|
93
|
-
}
|
|
94
|
-
|
|
95
92
|
function hasHigherPriorityThan(namespaceIndex1: number, namespaceIndex2: number, priorityTable: number[]) {
|
|
96
93
|
const order1 = priorityTable[namespaceIndex1];
|
|
97
94
|
const order2 = priorityTable[namespaceIndex2];
|
|
@@ -129,6 +126,7 @@ function _dumpReferences(xw: XmlWriter, node: BaseNode) {
|
|
|
129
126
|
// below already tolerates it being absent.
|
|
130
127
|
const connectsToReferenceType = addressSpace.findReferenceType("ConnectsTo");
|
|
131
128
|
const hasEventSourceReferenceType = _mustFindReferenceType(addressSpace, "HasEventSource");
|
|
129
|
+
const hierarchicalReferencesType = _mustFindReferenceType(addressSpace, "HierarchicalReferences");
|
|
132
130
|
|
|
133
131
|
function referenceToKeep(reference: UAReference): boolean {
|
|
134
132
|
// resolved here: a reference nobody has looked at since the load carries only the NodeId of its type
|
|
@@ -165,10 +163,26 @@ function _dumpReferences(xw: XmlWriter, node: BaseNode) {
|
|
|
165
163
|
} else if (referenceType.isSubtypeOf(organizesReferencesType) && !reference.isForward) {
|
|
166
164
|
// Organizes inverse — the current node is organized by an external folder
|
|
167
165
|
return true;
|
|
166
|
+
} else if (referenceType.isSubtypeOf(organizesReferencesType) && reference.isForward) {
|
|
167
|
+
// Organizes forward into another namespace: the target lives in a document this export
|
|
168
|
+
// does not write, so nothing else will ever declare this reference and dropping it
|
|
169
|
+
// loses it outright. Within our own namespace the target declares the inverse and this
|
|
170
|
+
// end stays silent, exactly as the Aggregates branch above decides it
|
|
171
|
+
return targetedNamespaceIndex !== node.nodeId.namespace;
|
|
168
172
|
} else if (connectsToReferenceType && referenceType.isSubtypeOf(connectsToReferenceType) && reference.isForward) {
|
|
169
173
|
return true;
|
|
170
174
|
} else if (referenceType.isSubtypeOf(hasEventSourceReferenceType) && reference.isForward) {
|
|
171
175
|
return true;
|
|
176
|
+
} else if (referenceType.isSubtypeOf(hierarchicalReferencesType)) {
|
|
177
|
+
// a hierarchical reference type the branches above do not name: a companion
|
|
178
|
+
// specification's own, such as Robotics' Requires, Controls and HasSafetyStates. Those
|
|
179
|
+
// fell through to `return false` and were dropped in both directions, so a nodeset that
|
|
180
|
+
// defines its own hierarchical reference type lost every reference that used it.
|
|
181
|
+
// Decided the way Aggregates is decided just above: this end writes the reference
|
|
182
|
+
// unless the other end has the higher priority and will write it instead
|
|
183
|
+
return reference.isForward
|
|
184
|
+
? !_hasHigherPriorityThan(xw, targetedNamespaceIndex, node.nodeId.namespace)
|
|
185
|
+
: targetedNamespaceIndex !== node.nodeId.namespace;
|
|
172
186
|
}
|
|
173
187
|
return false;
|
|
174
188
|
}
|
|
@@ -192,36 +206,6 @@ function _dumpReferences(xw: XmlWriter, node: BaseNode) {
|
|
|
192
206
|
}
|
|
193
207
|
xw.endElement();
|
|
194
208
|
}
|
|
195
|
-
function _dumpLocalizedText(xw: XmlWriter, v: LocalizedText) {
|
|
196
|
-
const uax = getPrefix(xw, "http://opcfoundation.org/UA/2008/02/Types.xsd");
|
|
197
|
-
if (v.locale?.length) {
|
|
198
|
-
xw.startElement(`${uax}Locale`);
|
|
199
|
-
xw.text(v.locale);
|
|
200
|
-
xw.endElement();
|
|
201
|
-
}
|
|
202
|
-
xw.startElement(`${uax}Text`);
|
|
203
|
-
if (v.text) {
|
|
204
|
-
xw.text(v.text);
|
|
205
|
-
}
|
|
206
|
-
xw.endElement();
|
|
207
|
-
}
|
|
208
|
-
function _dumpQualifiedName(xw: XmlWriter, v: QualifiedName) {
|
|
209
|
-
const uax = getPrefix(xw, "http://opcfoundation.org/UA/2008/02/Types.xsd");
|
|
210
|
-
const t = translateBrowseName(xw, v);
|
|
211
|
-
if (t.name) {
|
|
212
|
-
xw.startElement(`${uax}Name`);
|
|
213
|
-
xw.text(t.name);
|
|
214
|
-
xw.endElement();
|
|
215
|
-
}
|
|
216
|
-
if (t.namespaceIndex) {
|
|
217
|
-
xw.startElement(`${uax}NamespaceIndex`);
|
|
218
|
-
xw.text(t.namespaceIndex.toString());
|
|
219
|
-
xw.endElement();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
function _dumpXmlElement(xw: XmlWriter, v: string) {
|
|
223
|
-
xw.text(v);
|
|
224
|
-
}
|
|
225
209
|
/*
|
|
226
210
|
<uax:ExtensionObject>
|
|
227
211
|
<uax:TypeId>
|
|
@@ -239,78 +223,6 @@ function _dumpXmlElement(xw: XmlWriter, v: string) {
|
|
|
239
223
|
</uax:Body>
|
|
240
224
|
</uax:ExtensionObject>
|
|
241
225
|
*/
|
|
242
|
-
type XmlNamespaceUri = string;
|
|
243
|
-
type NamespaceUri = string;
|
|
244
|
-
type XmlNs = string;
|
|
245
|
-
interface XmlWriterEx extends XmlWriter {
|
|
246
|
-
map: Record<XmlNamespaceUri, XmlNs>;
|
|
247
|
-
stackMap: Record<XmlNamespaceUri, XmlNs>[];
|
|
248
|
-
namespaceArray: NamespaceUri[];
|
|
249
|
-
}
|
|
250
|
-
export function initXmlWriterEx(xw: XmlWriter, map: Record<XmlNamespaceUri, XmlNs>, namespaceArray: NamespaceUri[]): void {
|
|
251
|
-
const xwe = xw as XmlWriterEx;
|
|
252
|
-
xwe.map = map;
|
|
253
|
-
xwe.stackMap = [];
|
|
254
|
-
xwe.namespaceArray = namespaceArray;
|
|
255
|
-
}
|
|
256
|
-
function findXsdNamespaceUri(xw: XmlWriter, nodeId: NodeId): string {
|
|
257
|
-
const xwe = xw as XmlWriterEx;
|
|
258
|
-
if (!xwe.namespaceArray) {
|
|
259
|
-
return "";
|
|
260
|
-
}
|
|
261
|
-
const namespace = xwe.namespaceArray[nodeId.namespace];
|
|
262
|
-
if (namespace === "http://opcfoundation.org/UA/") {
|
|
263
|
-
return "http://opcfoundation.org/UA/2008/02/Types.xsd";
|
|
264
|
-
}
|
|
265
|
-
// c8 ignore next
|
|
266
|
-
if (!namespace) {
|
|
267
|
-
return "";
|
|
268
|
-
}
|
|
269
|
-
return `${namespace.replace(/\/$/, "")}/Types.xsd`;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function getPrefix(xw: XmlWriter, namespace: XmlNamespaceUri): XmlNs {
|
|
273
|
-
const xwe = xw as XmlWriterEx;
|
|
274
|
-
if (!xwe.map) return "";
|
|
275
|
-
const p = xwe.map[namespace] || "";
|
|
276
|
-
return p ? `${p}:` : "";
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function restoreDefaultNamespace(xw: XmlWriter) {
|
|
280
|
-
const xwe = xw as XmlWriterEx;
|
|
281
|
-
if (!xwe.map) return;
|
|
282
|
-
const previousMap = xwe.stackMap.pop();
|
|
283
|
-
if (previousMap) {
|
|
284
|
-
xwe.map = previousMap;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function setDefaultNamespace(xw: XmlWriter, namespace: XmlNamespaceUri): void {
|
|
289
|
-
const xwe = xw as XmlWriterEx;
|
|
290
|
-
if (!xwe.map) return;
|
|
291
|
-
if (xwe.map[namespace] !== "") {
|
|
292
|
-
xw.writeAttribute("xmlns", namespace);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
xwe.stackMap.push({
|
|
296
|
-
...xwe.map
|
|
297
|
-
});
|
|
298
|
-
xwe.map[namespace] = "";
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function startElementEx(xw: XmlWriter, _ns: XmlNs, name: string, defaultNamespace: XmlNamespaceUri) {
|
|
302
|
-
const _xwe = xw as XmlWriterEx;
|
|
303
|
-
xw.startElement(name);
|
|
304
|
-
setDefaultNamespace(xw, defaultNamespace);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function _dumpNodeId(xw: XmlWriter, v: NodeId) {
|
|
308
|
-
const xmlns = getPrefix(xw, "http://opcfoundation.org/UA/2008/02/Types.xsd");
|
|
309
|
-
xw.startElement(`${xmlns}Identifier`);
|
|
310
|
-
xw.text(n(xw, v));
|
|
311
|
-
xw.endElement();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
226
|
function _dumpVariantValue(xw: XmlWriter, dataTypeNodeId: NodeId, dataType: DataType, addressSpace: IAddressSpace, value: unknown) {
|
|
315
227
|
if (value === undefined || value === null) {
|
|
316
228
|
return;
|
|
@@ -449,7 +361,7 @@ function _dumpVariantInnerValue(
|
|
|
449
361
|
break;
|
|
450
362
|
case DataType.Int64:
|
|
451
363
|
case DataType.UInt64:
|
|
452
|
-
xw.text((value as
|
|
364
|
+
xw.text(int64ToDecimalString(value as Int64, dataType === DataType.Int64));
|
|
453
365
|
break;
|
|
454
366
|
case DataType.Boolean:
|
|
455
367
|
case DataType.SByte:
|
|
@@ -662,7 +574,6 @@ function _dumpValue(xw: XmlWriter, node: UAVariable | UAVariableType, variant: V
|
|
|
662
574
|
return;
|
|
663
575
|
}
|
|
664
576
|
|
|
665
|
-
const dataTypeName = dataTypeNode.browseName.name?.toString();
|
|
666
577
|
const baseDataTypeName = DataType[variant.dataType];
|
|
667
578
|
|
|
668
579
|
if (baseDataTypeName === "Null") {
|
|
@@ -673,9 +584,13 @@ function _dumpValue(xw: XmlWriter, node: UAVariable | UAVariableType, variant: V
|
|
|
673
584
|
// determine if dataTypeName is a ExtensionObject
|
|
674
585
|
const isExtensionObject = variant.dataType === DataType.ExtensionObject;
|
|
675
586
|
|
|
676
|
-
|
|
587
|
+
// nothing to serialize: a scalar with no value, or an array that is null rather than empty.
|
|
588
|
+
// This is the one thing _isDefaultValue used to catch here that still needs catching -- it is
|
|
589
|
+
// a test for the absence of a value, not for a value that happens to equal a type's default
|
|
590
|
+
if (variant.value === null || variant.value === undefined) {
|
|
677
591
|
return;
|
|
678
592
|
}
|
|
593
|
+
|
|
679
594
|
xw.startElement("Value");
|
|
680
595
|
|
|
681
596
|
const uax = getPrefix(xw, "http://opcfoundation.org/UA/2008/02/Types.xsd");
|
|
@@ -702,7 +617,11 @@ function _dumpValue(xw: XmlWriter, node: UAVariable | UAVariableType, variant: V
|
|
|
702
617
|
switch (variant.arrayType) {
|
|
703
618
|
case VariantArrayType.Matrix:
|
|
704
619
|
case VariantArrayType.Array:
|
|
705
|
-
|
|
620
|
+
// the built-in type, not the DataType's browse name: the uax schema defines
|
|
621
|
+
// ListOfInt32 and ListOfString, and nothing named after a nodeset's own DataType.
|
|
622
|
+
// A `ListOfIdType` is not an element any reader knows, so the reader that meets it
|
|
623
|
+
// walks straight past into the first child and takes the array for a scalar
|
|
624
|
+
startElementEx(xw, uax, `ListOf${baseDataTypeName}`, "http://opcfoundation.org/UA/2008/02/Types.xsd");
|
|
706
625
|
variant.value.forEach(encodeXml);
|
|
707
626
|
restoreDefaultNamespace(xw);
|
|
708
627
|
xw.endElement();
|
|
@@ -720,12 +639,15 @@ function _dumpValue(xw: XmlWriter, node: UAVariable | UAVariableType, variant: V
|
|
|
720
639
|
}
|
|
721
640
|
|
|
722
641
|
function _dumpArrayDimensionsAttribute(xw: XmlWriter, node: UAVariableType | UAVariable) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
642
|
+
// ArrayDimensions="0" is written only when the document declared it: node-opcua synthesizes [0]
|
|
643
|
+
// on the variables it generates, so writing it unconditionally would invent the attribute on
|
|
644
|
+
// every generated node. See arrayDimensionsWereDeclared in nodeset_record_applier
|
|
645
|
+
if (!node.arrayDimensions || node.valueRank <= 0) return;
|
|
646
|
+
// all-zero dimensions are what node-opcua synthesizes when nobody declared any, at whatever
|
|
647
|
+
// rank: [0] for a one-dimensional value, [0,0] for a matrix
|
|
648
|
+
const degenerate = node.arrayDimensions.every((d) => d === 0);
|
|
649
|
+
if (degenerate && !(node as unknown as { arrayDimensionsWereDeclared?: boolean }).arrayDimensionsWereDeclared) return;
|
|
650
|
+
xw.writeAttribute("ArrayDimensions", node.arrayDimensions.join(","));
|
|
729
651
|
}
|
|
730
652
|
|
|
731
653
|
function getParent(node: BaseNode): BaseNode | null {
|
|
@@ -749,6 +671,10 @@ function dumpCommonAttributes(xw: XmlWriter, node: BaseNode) {
|
|
|
749
671
|
if (Object.hasOwn(node, "symbolicName")) {
|
|
750
672
|
xw.writeAttribute("SymbolicName", (node as unknown as { symbolicName: string }).symbolicName);
|
|
751
673
|
}
|
|
674
|
+
// Released is the default and is left unwritten; the other two the document declared
|
|
675
|
+
if (node.releaseStatus) {
|
|
676
|
+
xw.writeAttribute("ReleaseStatus", node.releaseStatus);
|
|
677
|
+
}
|
|
752
678
|
if (Object.hasOwn(node, "isAbstract")) {
|
|
753
679
|
const isAbstract = (node as unknown as { isAbstract: boolean }).isAbstract;
|
|
754
680
|
if (isAbstract) {
|
|
@@ -773,8 +699,11 @@ function dumpCommonAttributes(xw: XmlWriter, node: BaseNode) {
|
|
|
773
699
|
}
|
|
774
700
|
// access policy: undefined means "inherit from the namespace", an empty rolePermissions array
|
|
775
701
|
// means "this node deliberately grants nothing".
|
|
776
|
-
|
|
777
|
-
|
|
702
|
+
// what the document declared, which survives whatever the loader was asked to enforce; the
|
|
703
|
+
// enforced flag is the fallback for a node built in code rather than loaded
|
|
704
|
+
const accessRestrictions = node.declaredAccessRestrictions ?? node.accessRestrictions?.toString();
|
|
705
|
+
if (accessRestrictions !== undefined) {
|
|
706
|
+
xw.writeAttribute("AccessRestrictions", accessRestrictions);
|
|
778
707
|
}
|
|
779
708
|
if (node.rolePermissions !== undefined && node.rolePermissions.length === 0) {
|
|
780
709
|
xw.writeAttribute("HasNoPermissions", "true");
|
|
@@ -785,6 +714,19 @@ function dumpCommonAttributes(xw: XmlWriter, node: BaseNode) {
|
|
|
785
714
|
xw.writeAttribute("MinimumSamplingInterval", minimumSamplingInterval);
|
|
786
715
|
}
|
|
787
716
|
}
|
|
717
|
+
// EventNotifier lives on UAObject, UAObjectType and UAView in the XSD. 0 is the default and is
|
|
718
|
+
// left unwritten; anything else the document declared. It was written nowhere at all until now,
|
|
719
|
+
// so every node that declared one lost it on the way out
|
|
720
|
+
if (node.nodeClass === NodeClass.Object || node.nodeClass === NodeClass.ObjectType || node.nodeClass === NodeClass.View) {
|
|
721
|
+
// typeof, not truthiness: a node with a child called "EventNotifier" resolves the name to
|
|
722
|
+
// that child through the shared child accessors, so `node.eventNotifier` is a BaseNode
|
|
723
|
+
// there and not the attribute. PublishedEventsType is one, and stringifying it wrote a
|
|
724
|
+
// whole node dump into the attribute
|
|
725
|
+
const eventNotifier = (node as unknown as { eventNotifier?: unknown }).eventNotifier;
|
|
726
|
+
if (typeof eventNotifier === "number" && eventNotifier !== 0) {
|
|
727
|
+
xw.writeAttribute("EventNotifier", eventNotifier.toString());
|
|
728
|
+
}
|
|
729
|
+
}
|
|
788
730
|
// Historizing exists in the XSD on UAVariable only: UAVariableType is restricted to
|
|
789
731
|
// DataType/ValueRank/ArrayDimensions. UAVariableTypeImpl nevertheless owns a `historizing`
|
|
790
732
|
// property, so the node class must be tested here rather than the presence of the property.
|
|
@@ -819,19 +761,6 @@ function dumpCommonElements(xw: XmlWriter, node: BaseNode) {
|
|
|
819
761
|
_dumpRolePermissions(xw, node);
|
|
820
762
|
}
|
|
821
763
|
|
|
822
|
-
export function coerceInt64ToInt32(int64: Int64): number {
|
|
823
|
-
if (typeof int64 === "number") {
|
|
824
|
-
return int64 as number;
|
|
825
|
-
}
|
|
826
|
-
if (int64[0] === 0xffffffff && int64[1] === 0xffffffff) {
|
|
827
|
-
return 0xffffffff;
|
|
828
|
-
}
|
|
829
|
-
if (int64[0] !== 0) {
|
|
830
|
-
warningLog("coerceInt64ToInt32 , loosing high word in conversion");
|
|
831
|
-
}
|
|
832
|
-
return int64[1];
|
|
833
|
-
}
|
|
834
|
-
|
|
835
764
|
function _dumpEnumDefinition(xw: XmlWriter, enumDefinition: EnumDefinition) {
|
|
836
765
|
enumDefinition.fields = enumDefinition.fields || [];
|
|
837
766
|
|
|
@@ -860,6 +789,12 @@ function _dumpStructureDefinition(
|
|
|
860
789
|
// do not repeat elements that are already defined in base structure in the xml ouput!
|
|
861
790
|
const fields = structureDefinition.fields || [];
|
|
862
791
|
const nbFieldsInBase: number = baseStructureDefinition ? baseStructureDefinition.fields?.length || 0 : 0;
|
|
792
|
+
// Part 3 8.51: in a *WithSubtypedValues structure, isOptional is where "subtyping allowed" is
|
|
793
|
+
// held, and the document spells that AllowSubTypes. Written as IsOptional it said the opposite
|
|
794
|
+
// of what it meant, and the AllowSubTypes the document had was simply gone
|
|
795
|
+
const subtypedValues =
|
|
796
|
+
structureDefinition.structureType === StructureType.StructureWithSubtypedValues ||
|
|
797
|
+
structureDefinition.structureType === StructureType.UnionWithSubtypedValues;
|
|
863
798
|
|
|
864
799
|
for (let index = nbFieldsInBase; index < fields.length; index++) {
|
|
865
800
|
const defItem = fields[index];
|
|
@@ -872,8 +807,8 @@ function _dumpStructureDefinition(
|
|
|
872
807
|
if (defItem.valueRank !== undefined && defItem.valueRank !== -1) {
|
|
873
808
|
xw.writeAttribute("ValueRank", defItem.valueRank);
|
|
874
809
|
}
|
|
875
|
-
if (defItem.isOptional
|
|
876
|
-
xw.writeAttribute("IsOptional",
|
|
810
|
+
if (defItem.isOptional) {
|
|
811
|
+
xw.writeAttribute(subtypedValues ? "AllowSubTypes" : "IsOptional", "true");
|
|
877
812
|
}
|
|
878
813
|
if (defItem.maxStringLength !== undefined && defItem.maxStringLength !== 0) {
|
|
879
814
|
xw.writeAttribute("MaxStringLength", defItem.maxStringLength);
|
|
@@ -892,9 +827,37 @@ function _dumpStructureDefinition(
|
|
|
892
827
|
function _dumpUADataTypeDefinition(xw: XmlWriter, uaDataType: UADataType) {
|
|
893
828
|
const uaDataTypeBase = uaDataType.subtypeOfObj;
|
|
894
829
|
|
|
830
|
+
// an OptionSet first: node-opcua builds neither an enumeration nor a structure for one, so
|
|
831
|
+
// neither branch below would fire and the whole <Definition> would be dropped. The fields are
|
|
832
|
+
// the ones the loader kept, see UADataTypeImpl.isOptionSetDataType
|
|
833
|
+
const asImpl = uaDataType as unknown as {
|
|
834
|
+
isOptionSetDataType?: boolean;
|
|
835
|
+
declaredDefinitionFields?: Array<{ name?: string | null; value?: number; description?: unknown }>;
|
|
836
|
+
declaredDefinitionName?: string;
|
|
837
|
+
};
|
|
838
|
+
// what the document called this definition, or -- for a DataType built here, which never had a
|
|
839
|
+
// declaration -- the browse name, which is the only name available
|
|
840
|
+
const definitionName = asImpl.declaredDefinitionName ?? b(xw, uaDataType.browseName);
|
|
841
|
+
if (asImpl.isOptionSetDataType && asImpl.declaredDefinitionFields) {
|
|
842
|
+
xw.startElement("Definition");
|
|
843
|
+
xw.writeAttribute("Name", definitionName);
|
|
844
|
+
xw.writeAttribute("IsOptionSet", "true");
|
|
845
|
+
for (const field of asImpl.declaredDefinitionFields) {
|
|
846
|
+
xw.startElement("Field");
|
|
847
|
+
xw.writeAttribute("Name", field.name || "");
|
|
848
|
+
if (field.value !== undefined && field.value !== null) {
|
|
849
|
+
xw.writeAttribute("Value", field.value);
|
|
850
|
+
}
|
|
851
|
+
_dumpDescription(xw, field as { description?: LocalizedText });
|
|
852
|
+
xw.endElement();
|
|
853
|
+
}
|
|
854
|
+
xw.endElement();
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
|
|
895
858
|
if (uaDataType.isEnumeration()) {
|
|
896
859
|
xw.startElement("Definition");
|
|
897
|
-
xw.writeAttribute("Name",
|
|
860
|
+
xw.writeAttribute("Name", definitionName);
|
|
898
861
|
_dumpEnumDefinition(xw, uaDataType.getEnumDefinition());
|
|
899
862
|
xw.endElement();
|
|
900
863
|
return;
|
|
@@ -909,9 +872,11 @@ function _dumpUADataTypeDefinition(xw: XmlWriter, uaDataType: UADataType) {
|
|
|
909
872
|
const t = true;
|
|
910
873
|
if (t || dataValue.statusCode.isGood()) {
|
|
911
874
|
const definition = uaDataType.getStructureDefinition();
|
|
912
|
-
|
|
875
|
+
// a structure's supertype need not be a structure: `Structure` itself subtypes BaseDataType,
|
|
876
|
+
// which has no definition at all. Asking it for one threw, and took the whole export with it
|
|
877
|
+
const baseDefinition = uaDataTypeBase?.isStructure() ? uaDataTypeBase.getStructureDefinition() : null;
|
|
913
878
|
xw.startElement("Definition");
|
|
914
|
-
xw.writeAttribute("Name",
|
|
879
|
+
xw.writeAttribute("Name", definitionName);
|
|
915
880
|
if (definition.structureType === StructureType.Union) {
|
|
916
881
|
xw.writeAttribute("IsUnion", "true");
|
|
917
882
|
}
|
|
@@ -993,8 +958,14 @@ function dumpUAVariable(xw: XmlWriter, node: UAVariable) {
|
|
|
993
958
|
// sub elements
|
|
994
959
|
dumpCommonElements(xw, node);
|
|
995
960
|
|
|
996
|
-
|
|
997
|
-
|
|
961
|
+
// a value the loader made up for a variable the document left unvalued is not written
|
|
962
|
+
// back out; see valueWasSynthesized in nodeset_record_applier. What used to stand here was
|
|
963
|
+
// _isDefaultValue, which dropped every zero and every empty string alike -- suppressing the
|
|
964
|
+
// made-up ones at the cost of the ones the document really did declare
|
|
965
|
+
const synthesized = (node as unknown as { valueWasSynthesized?: boolean }).valueWasSynthesized;
|
|
966
|
+
const dataValue = (node as UAVariableImpl).$dataValue;
|
|
967
|
+
const value = dataValue.value;
|
|
968
|
+
if (value && !synthesized && !dataValue.statusCode.equals(StatusCodes.BadWaitingForInitialData)) {
|
|
998
969
|
_dumpValue(xw, node, value);
|
|
999
970
|
}
|
|
1000
971
|
}
|
|
@@ -1236,10 +1207,6 @@ BaseNodeImpl.prototype.dumpXML = function (this: BaseNodeImpl, xw: XmlWriter) {
|
|
|
1236
1207
|
writeWalkEvents(xw, this.addressSpace, translationTable, events);
|
|
1237
1208
|
};
|
|
1238
1209
|
|
|
1239
|
-
export function makeTypeXsd(namespaceUri: string): string {
|
|
1240
|
-
return `${namespaceUri.replace(/\/$/, "")}/Type.xsd`;
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
1210
|
NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
|
|
1244
1211
|
const namespaceArrayNode = this.addressSpace.findNode(VariableIds.Server_NamespaceArray);
|
|
1245
1212
|
const namespaceArray: string[] = namespaceArrayNode
|
|
@@ -38,7 +38,7 @@ const debugLog = make_debugLog("finite_state_machine");
|
|
|
38
38
|
|
|
39
39
|
export class UATransitionImplBase extends UAObjectImpl implements UATransitionEx {
|
|
40
40
|
/** installed as a child node by the address space, not assigned here - hence `declare` */
|
|
41
|
-
public
|
|
41
|
+
declare public readonly transitionNumber: UAProperty<UInt32, DataType.UInt32>;
|
|
42
42
|
/* intentionnaly empty */
|
|
43
43
|
}
|
|
44
44
|
export type UATransitionImpl = UATransitionImplBase;
|
|
@@ -137,8 +137,8 @@ export class UAStateMachineImplBase extends UAObjectImpl implements UAStateMachi
|
|
|
137
137
|
* cached state this class maintains. Neither is assigned by the constructor - hence
|
|
138
138
|
* `declare`, which emits nothing.
|
|
139
139
|
*/
|
|
140
|
-
public
|
|
141
|
-
public
|
|
140
|
+
declare public readonly currentState: UAStateVariable<LocalizedText>;
|
|
141
|
+
declare public _currentStateNode: UAState | null;
|
|
142
142
|
|
|
143
143
|
public getStates(): UAState[] {
|
|
144
144
|
const typeDef = this.typeDefinitionObj;
|
|
@@ -55,26 +55,26 @@ export class UAShelvedStateMachineExImplBase extends UAStateMachineImpl implemen
|
|
|
55
55
|
* shelving timer this class keeps. None is assigned by the constructor - hence `declare`,
|
|
56
56
|
* which emits nothing.
|
|
57
57
|
*/
|
|
58
|
-
public
|
|
59
|
-
public
|
|
60
|
-
public
|
|
61
|
-
public
|
|
62
|
-
public
|
|
63
|
-
public
|
|
64
|
-
public
|
|
65
|
-
public
|
|
66
|
-
public
|
|
67
|
-
public
|
|
68
|
-
public
|
|
69
|
-
public
|
|
70
|
-
public
|
|
71
|
-
public
|
|
72
|
-
public
|
|
73
|
-
public
|
|
74
|
-
public
|
|
75
|
-
public
|
|
76
|
-
public
|
|
77
|
-
public
|
|
58
|
+
declare public readonly unshelveTime: UAProperty<number, DataType.Double>;
|
|
59
|
+
declare public readonly unshelved: UAState;
|
|
60
|
+
declare public readonly timedShelved: UAState;
|
|
61
|
+
declare public readonly oneShotShelved: UAState;
|
|
62
|
+
declare public readonly unshelvedToTimedShelved: UATransitionEx;
|
|
63
|
+
declare public readonly unshelvedToOneShotShelved: UATransitionEx;
|
|
64
|
+
declare public readonly timedShelvedToUnshelved: UATransitionEx;
|
|
65
|
+
declare public readonly timedShelvedToOneShotShelved: UATransitionEx;
|
|
66
|
+
declare public readonly oneShotShelvedToUnshelved: UATransitionEx;
|
|
67
|
+
declare public readonly oneShotShelvedToTimedShelved: UATransitionEx;
|
|
68
|
+
declare public readonly timedShelve: UAMethod;
|
|
69
|
+
declare public readonly timedShelve2?: UAMethod;
|
|
70
|
+
declare public readonly unshelve: UAMethod;
|
|
71
|
+
declare public readonly unshelve2?: UAMethod;
|
|
72
|
+
declare public readonly oneShotShelve: UAMethod;
|
|
73
|
+
declare public readonly oneShotShelve2?: UAMethod;
|
|
74
|
+
declare public _timer: NodeJS.Timeout | null;
|
|
75
|
+
declare public _shelvedTime: Date;
|
|
76
|
+
declare public _unshelvedTime: Date;
|
|
77
|
+
declare public _duration: number;
|
|
78
78
|
|
|
79
79
|
public static promote(object: UAObject): UAShelvedStateMachineEx {
|
|
80
80
|
const shelvingState = object as UAShelvedStateMachineExImpl;
|
|
@@ -52,6 +52,10 @@ export interface EnumerationInfo {
|
|
|
52
52
|
export interface UADataTypeOptions extends InternalBaseNodeOptions {
|
|
53
53
|
partialDefinition: StructureFieldOptions[] | EnumFieldOptions[];
|
|
54
54
|
isUnion?: boolean;
|
|
55
|
+
/** the DataType is a bit mask, not an enumeration; see UADataTypeImpl.isOptionSet */
|
|
56
|
+
isOptionSet?: boolean;
|
|
57
|
+
/** the <Definition> Name as declared; see UADataTypeImpl.declaredDefinitionName */
|
|
58
|
+
definitionName?: string;
|
|
55
59
|
isAbstract?: boolean;
|
|
56
60
|
symbolicName?: string;
|
|
57
61
|
}
|
|
@@ -89,16 +93,42 @@ export class UADataTypeImpl extends BaseNodeImpl implements UADataType {
|
|
|
89
93
|
// the EnumStrings / EnumValues children, reached through the child accessors: declared for the
|
|
90
94
|
// type checker only, since an emitted class field would sit on the instance and hide the
|
|
91
95
|
// accessor inherited from the prototype
|
|
92
|
-
private
|
|
93
|
-
private
|
|
96
|
+
declare private enumStrings?: UAVariable;
|
|
97
|
+
declare private enumValues?: UAVariable;
|
|
94
98
|
private $partialDefinition?: StructureFieldOptionsEx[] | EnumFieldOptions[];
|
|
95
99
|
private $fullDefinition?: StructureDefinition | EnumDefinition;
|
|
96
100
|
|
|
101
|
+
/**
|
|
102
|
+
* whether the nodeset declared this DataType with `IsOptionSet="true"`: a bit mask whose fields
|
|
103
|
+
* are bit positions rather than an enumeration whose fields are values. node-opcua builds no
|
|
104
|
+
* enumeration and no structure for one -- it is a plain UInt16 or UInt32 subtype -- so without
|
|
105
|
+
* this flag and the fields kept in $partialDefinition, an OptionSet that goes into the address
|
|
106
|
+
* space cannot come out again as the DataType the document declared.
|
|
107
|
+
*/
|
|
108
|
+
public isOptionSetDataType = false;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* the Name attribute of the <Definition> element as the nodeset spelled it. The published
|
|
112
|
+
* catalogue uses both spellings -- 467 bare names and 211 namespace-prefixed ones -- so there
|
|
113
|
+
* is no form to normalise to: recomputing it from the browse name rewrote every bare one.
|
|
114
|
+
* Undefined for a DataType this address space built itself, which has no declaration to keep.
|
|
115
|
+
*/
|
|
116
|
+
public declaredDefinitionName?: string;
|
|
117
|
+
|
|
118
|
+
/** the fields of the <Definition> as declared, for a DataType the address space models no further */
|
|
119
|
+
public get declaredDefinitionFields(): StructureFieldOptionsEx[] | EnumFieldOptions[] | undefined {
|
|
120
|
+
return this.$partialDefinition;
|
|
121
|
+
}
|
|
122
|
+
|
|
97
123
|
constructor(options: UADataTypeOptions) {
|
|
98
124
|
super(options);
|
|
99
125
|
if (options.partialDefinition) {
|
|
100
126
|
this.$partialDefinition = options.partialDefinition;
|
|
101
127
|
}
|
|
128
|
+
this.isOptionSetDataType = !!options.isOptionSet;
|
|
129
|
+
if (options.definitionName) {
|
|
130
|
+
this.declaredDefinitionName = options.definitionName;
|
|
131
|
+
}
|
|
102
132
|
this.isAbstract = options.isAbstract === undefined || options.isAbstract === null ? false : options.isAbstract;
|
|
103
133
|
this.symbolicName = options.symbolicName || this.browseName.name || "";
|
|
104
134
|
}
|
|
@@ -261,7 +291,12 @@ export class UADataTypeImpl extends BaseNodeImpl implements UADataType {
|
|
|
261
291
|
}
|
|
262
292
|
getStructureDefinition(): StructureDefinition {
|
|
263
293
|
const definition = this._getDefinition();
|
|
264
|
-
assert
|
|
294
|
+
// named: a bare assert here threw an Error with an empty message, which told a caller
|
|
295
|
+
// nothing at all about which DataType had refused and what it had instead
|
|
296
|
+
assert(
|
|
297
|
+
definition instanceof StructureDefinition,
|
|
298
|
+
`${this.browseName.toString()} (${this.nodeId.toString()}) has no StructureDefinition: ${definition ? definition.constructor.name : "none"}`
|
|
299
|
+
);
|
|
265
300
|
return definition as StructureDefinition;
|
|
266
301
|
}
|
|
267
302
|
|
|
@@ -271,7 +306,10 @@ export class UADataTypeImpl extends BaseNodeImpl implements UADataType {
|
|
|
271
306
|
}
|
|
272
307
|
getEnumDefinition(): EnumDefinition {
|
|
273
308
|
const definition = this._getDefinition();
|
|
274
|
-
assert(
|
|
309
|
+
assert(
|
|
310
|
+
definition instanceof EnumDefinition,
|
|
311
|
+
`${this.browseName.toString()} (${this.nodeId.toString()}) has no EnumDefinition: ${definition ? definition.constructor.name : "none"}`
|
|
312
|
+
);
|
|
275
313
|
return definition as EnumDefinition;
|
|
276
314
|
}
|
|
277
315
|
|
package/impl/ua_method_impl.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class UAMethodImpl extends BaseNodeImpl<UAMethodEvents> implements UAMeth
|
|
|
64
64
|
return super.parent as UAObject;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
public
|
|
67
|
+
declare public value?: unknown;
|
|
68
68
|
public methodDeclarationId: NodeId;
|
|
69
69
|
public _getExecutableFlag?: (this: UAMethod, context: ISessionContext | null) => boolean;
|
|
70
70
|
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
AddObjectOptions,
|
|
7
|
+
AddReferenceOpts,
|
|
7
8
|
BaseNodeEvents,
|
|
8
9
|
InstantiateObjectOptions,
|
|
9
10
|
ISessionContext,
|
|
10
11
|
UAObject,
|
|
11
|
-
UAObjectType
|
|
12
|
-
UAReference
|
|
12
|
+
UAObjectType
|
|
13
13
|
} from "node-opcua-address-space-base";
|
|
14
14
|
import { assert } from "node-opcua-assert";
|
|
15
15
|
import { AttributeIds, type LocalizedTextLike, NodeClass } from "node-opcua-data-model";
|
|
@@ -28,11 +28,20 @@ import { assertUnusedChildBrowseName, topMostParentIsObjectTypeOrVariableType }
|
|
|
28
28
|
|
|
29
29
|
export interface UAObjectTypeOptions extends InternalBaseNodeOptions {
|
|
30
30
|
isAbstract?: boolean | null;
|
|
31
|
+
/** the EventNotifier the nodeset declared; see UAObjectTypeImpl.eventNotifier */
|
|
32
|
+
eventNotifier?: number;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export class UAObjectTypeImpl extends BaseNodeImpl<BaseNodeEvents> implements UAObjectType {
|
|
34
36
|
public readonly nodeClass = NodeClass.ObjectType;
|
|
35
37
|
public readonly isAbstract: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* the EventNotifier the nodeset declared. The XSD allows it on a UAObjectType and nodesets use
|
|
40
|
+
* it, but nothing here held it: the attribute was dropped at load, and -- because the name was
|
|
41
|
+
* then free -- a child called EventNotifier claimed `eventNotifier` through the shared child
|
|
42
|
+
* accessors, so reading it handed back a BaseNode. PublishedEventsType is such a type.
|
|
43
|
+
*/
|
|
44
|
+
public readonly eventNotifier: number;
|
|
36
45
|
/**
|
|
37
46
|
* returns true if the object has some opcua methods
|
|
38
47
|
*/
|
|
@@ -54,6 +63,7 @@ export class UAObjectTypeImpl extends BaseNodeImpl<BaseNodeEvents> implements UA
|
|
|
54
63
|
constructor(options: UAObjectTypeOptions) {
|
|
55
64
|
super(options);
|
|
56
65
|
this.isAbstract = options.isAbstract ?? false;
|
|
66
|
+
this.eventNotifier = options.eventNotifier ?? 0;
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
public readAttribute(context: ISessionContext, attributeId: AttributeIds): DataValue {
|
|
@@ -118,7 +128,10 @@ export class UAObjectTypeImpl extends BaseNodeImpl<BaseNodeEvents> implements UA
|
|
|
118
128
|
const baseObjectType = addressSpace.findObjectType("BaseObjectType") as UAObjectType;
|
|
119
129
|
assert(baseObjectType, "BaseObjectType must be defined in the address space");
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
// caller-supplied references (typically an inverse aggregate reference to a
|
|
132
|
+
// parent that has no dedicated option, e.g. HasOrderedComponent) are created
|
|
133
|
+
// with the node, so the NodeIdManager sees the parent when naming it.
|
|
134
|
+
const references: AddReferenceOpts[] = options.references ? [...options.references] : [];
|
|
122
135
|
|
|
123
136
|
const copyAlsoModellingRules = topMostParentIsObjectTypeOrVariableType(addressSpace, options);
|
|
124
137
|
|