node-opcua-address-space 2.66.2 → 2.68.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/dist/source/address_space_ts.d.ts +0 -2
- package/dist/source/address_space_ts.js.map +1 -1
- package/dist/source/continuation_points/continuation_point_manager.js +6 -3
- package/dist/source/continuation_points/continuation_point_manager.js.map +1 -1
- package/dist/source/loader/make_xml_extension_object_parser.js +28 -9
- package/dist/source/loader/make_xml_extension_object_parser.js.map +1 -1
- package/dist/src/base_node_impl.js +1 -1
- package/dist/src/base_node_impl.js.map +1 -1
- package/dist/src/extension_object_array_node.js +31 -22
- package/dist/src/extension_object_array_node.js.map +1 -1
- package/dist/src/historical_access/address_space_historical_data_node.js +3 -3
- package/dist/src/historical_access/address_space_historical_data_node.js.map +1 -1
- package/dist/src/reference_impl.js +1 -1
- package/dist/src/reference_impl.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +9 -8
- package/dist/src/ua_variable_impl.js +56 -313
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/dist/src/ua_variable_impl_ext_obj.d.ts +17 -0
- package/dist/src/ua_variable_impl_ext_obj.js +393 -0
- package/dist/src/ua_variable_impl_ext_obj.js.map +1 -0
- package/distNodeJS/generate_address_space.js +1 -1
- package/package.json +36 -36
- package/source/address_space_ts.ts +0 -2
- package/source/continuation_points/continuation_point_manager.ts +11 -9
- package/source/loader/make_xml_extension_object_parser.ts +32 -11
- package/source_nodejs/generate_address_space.ts +1 -1
- package/src/base_node_impl.ts +1 -1
- package/src/extension_object_array_node.ts +43 -28
- package/src/historical_access/address_space_historical_data_node.ts +3 -3
- package/src/reference_impl.ts +1 -1
- package/src/ua_variable_impl.ts +68 -381
- package/src/ua_variable_impl_ext_obj.ts +472 -0
- package/test_helpers/test_fixtures/issue_1132_variable_with_nodeid_value.xml +68 -0
- package/test_helpers/test_fixtures/nodeset_with_utf8_special_characters.xml +20 -0
package/src/ua_variable_impl.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import * as chalk from "chalk";
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
BindExtensionObjectOptions,
|
|
12
13
|
CloneExtraInfo,
|
|
13
14
|
ContinuationData,
|
|
14
15
|
defaultCloneExtraInfo,
|
|
@@ -80,7 +81,7 @@ import {
|
|
|
80
81
|
BaseNode,
|
|
81
82
|
UAVariableT
|
|
82
83
|
} from "node-opcua-address-space-base";
|
|
83
|
-
import { UAHistoricalDataConfiguration } from "node-opcua-nodeset-ua";
|
|
84
|
+
import { EnumFilterOperator, UAHistoricalDataConfiguration } from "node-opcua-nodeset-ua";
|
|
84
85
|
|
|
85
86
|
import { SessionContext } from "../source/session_context";
|
|
86
87
|
import { convertToCallbackFunction1 } from "../source/helpers/multiform_func";
|
|
@@ -88,6 +89,7 @@ import { BaseNodeImpl, InternalBaseNodeOptions } from "./base_node_impl";
|
|
|
88
89
|
import { _clone, ToStringBuilder, UAVariable_toString, valueRankToString } from "./base_node_private";
|
|
89
90
|
import { EnumerationInfo, IEnumItem, UADataTypeImpl } from "./ua_data_type_impl";
|
|
90
91
|
import { apply_condition_refresh, ConditionRefreshCache } from "./apply_condition_refresh";
|
|
92
|
+
import { extractPartialData, propagateTouchValueUpward, setExtensionObjectValue, _bindExtensionObject, _installExtensionObjectBindingOnProperties, _setExtensionObject, _touchValue } from "./ua_variable_impl_ext_obj";
|
|
91
93
|
|
|
92
94
|
const debugLog = make_debugLog(__filename);
|
|
93
95
|
const warningLog = make_warningLog(__filename);
|
|
@@ -157,7 +159,6 @@ function _dataType_toUADataType(addressSpace: IAddressSpace, dataType: DataType)
|
|
|
157
159
|
}
|
|
158
160
|
return dataTypeNode as UADataType;
|
|
159
161
|
}
|
|
160
|
-
|
|
161
162
|
/*=
|
|
162
163
|
*
|
|
163
164
|
* @param addressSpace
|
|
@@ -681,7 +682,8 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
681
682
|
if (
|
|
682
683
|
this.dataType.namespace === 0 &&
|
|
683
684
|
this.dataType.value === DataType.LocalizedText &&
|
|
684
|
-
variant.dataType !== DataType.LocalizedText &&
|
|
685
|
+
variant.dataType !== DataType.LocalizedText &&
|
|
686
|
+
variant.dataType !== DataType.Null
|
|
685
687
|
) {
|
|
686
688
|
throw new Error(
|
|
687
689
|
"Variant must provide a valid LocalizedText : variant = " +
|
|
@@ -699,7 +701,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
699
701
|
if (basicType === DataType.ByteString && variant.dataType === DataType.String) {
|
|
700
702
|
return; // this is allowed
|
|
701
703
|
}
|
|
702
|
-
|
|
704
|
+
|
|
703
705
|
if (
|
|
704
706
|
basicType !== DataType.Null &&
|
|
705
707
|
basicType !== DataType.Variant &&
|
|
@@ -757,7 +759,22 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
757
759
|
dataValue.sourceTimestamp = now.timestamp;
|
|
758
760
|
dataValue.statusCode = statusCode;
|
|
759
761
|
dataValue.value = variant1;
|
|
760
|
-
|
|
762
|
+
|
|
763
|
+
if (dataValue.value.dataType === DataType.ExtensionObject) {
|
|
764
|
+
this.$dataValue = dataValue;
|
|
765
|
+
assert(this.checkExtensionObjectIsCorrect(dataValue.value.value));
|
|
766
|
+
// ----------------------------------
|
|
767
|
+
if (this.$extensionObject) {
|
|
768
|
+
// we have an extension object already bound to this node
|
|
769
|
+
// the client is asking us to replace the object entierly by a new one
|
|
770
|
+
const ext = dataValue.value.value;
|
|
771
|
+
_setExtensionObject(this, ext);
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
} else {
|
|
775
|
+
this._internal_set_dataValue(dataValue);
|
|
776
|
+
}
|
|
777
|
+
|
|
761
778
|
} catch (err) {
|
|
762
779
|
errorLog("UAVariable#setValueFromString Error : ", this.browseName.toString(), this.nodeId.toString());
|
|
763
780
|
errorLog((err as Error).message);
|
|
@@ -981,32 +998,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
981
998
|
}
|
|
982
999
|
|
|
983
1000
|
/**
|
|
984
|
-
* @method touchValue
|
|
985
1001
|
* touch the source timestamp of a Variable and cascade up the change
|
|
986
1002
|
* to the parent variable if any.
|
|
987
|
-
*
|
|
988
|
-
* @param [optionalNow=null] {Object}
|
|
989
|
-
* @param optionalNow.timestamp {Date}
|
|
990
|
-
* @param optionalNow.picoseconds {Number}
|
|
991
1003
|
*/
|
|
992
1004
|
public touchValue(optionalNow?: PreciseClock): void {
|
|
993
1005
|
const now = optionalNow || getCurrentClock();
|
|
994
|
-
this
|
|
995
|
-
this.$dataValue.sourcePicoseconds = now.picoseconds;
|
|
996
|
-
this.$dataValue.serverTimestamp = now.timestamp;
|
|
997
|
-
this.$dataValue.serverPicoseconds = now.picoseconds;
|
|
998
|
-
|
|
999
|
-
this.$dataValue.statusCode = StatusCodes.Good;
|
|
1000
|
-
|
|
1001
|
-
if (this.minimumSamplingInterval === 0) {
|
|
1002
|
-
if (this.listenerCount("value_changed") > 0) {
|
|
1003
|
-
const clonedDataValue = this.readValue();
|
|
1004
|
-
this.emit("value_changed", clonedDataValue);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
if (this.parent && this.parent.nodeClass === NodeClass.Variable) {
|
|
1008
|
-
(this.parent as UAVariable).touchValue(now);
|
|
1009
|
-
}
|
|
1006
|
+
propagateTouchValueUpward(this, now);
|
|
1010
1007
|
}
|
|
1011
1008
|
|
|
1012
1009
|
/**
|
|
@@ -1170,7 +1167,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1170
1167
|
if (!context) {
|
|
1171
1168
|
context = SessionContext.defaultContext;
|
|
1172
1169
|
}
|
|
1173
|
-
assert(callback
|
|
1170
|
+
assert(typeof callback === 'function');
|
|
1174
1171
|
|
|
1175
1172
|
this.__waiting_callbacks = this.__waiting_callbacks || [];
|
|
1176
1173
|
this.__waiting_callbacks.push(callback);
|
|
@@ -1263,6 +1260,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1263
1260
|
|
|
1264
1261
|
assert(newVariable.dataType === this.dataType);
|
|
1265
1262
|
newVariable.$dataValue = this.$dataValue.clone();
|
|
1263
|
+
|
|
1264
|
+
// also bind extension object
|
|
1265
|
+
const v = newVariable.$dataValue.value;
|
|
1266
|
+
if (v.dataType === DataType.ExtensionObject && v.value && v.arrayType === VariantArrayType.Scalar) {
|
|
1267
|
+
newVariable.bindExtensionObject(newVariable.$dataValue.value.value);
|
|
1268
|
+
}
|
|
1266
1269
|
return newVariable;
|
|
1267
1270
|
}
|
|
1268
1271
|
|
|
@@ -1318,281 +1321,35 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1318
1321
|
return false;
|
|
1319
1322
|
}
|
|
1320
1323
|
}
|
|
1324
|
+
|
|
1321
1325
|
/**
|
|
1322
|
-
* @
|
|
1323
|
-
*
|
|
1326
|
+
* @private
|
|
1327
|
+
* install UAVariable to exposed th
|
|
1328
|
+
*
|
|
1329
|
+
* precondition:
|
|
1324
1330
|
*/
|
|
1325
|
-
public
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
// bindExtensionObject cannot be performed and shall finish here.
|
|
1333
|
-
return null;
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
// istanbul ignore next
|
|
1337
|
-
if (doDebug) {
|
|
1338
|
-
debugLog(" ------------------------------ binding ", this.browseName.toString(), this.nodeId.toString());
|
|
1339
|
-
}
|
|
1340
|
-
assert(structure && structure.browseName.toString() === "Structure", "expecting DataType Structure to be in IAddressSpace");
|
|
1341
|
-
|
|
1342
|
-
const dt = this.getDataTypeNode() as UADataTypeImpl;
|
|
1343
|
-
if (!dt.isSupertypeOf(structure)) {
|
|
1344
|
-
return null;
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
// the namespace for the structure browse name elements
|
|
1348
|
-
const structureNamespace = dt.nodeId.namespace;
|
|
1349
|
-
|
|
1350
|
-
// -------------------- make sure we do not bind a variable twice ....
|
|
1351
|
-
if (this.$extensionObject) {
|
|
1352
|
-
// istanbul ignore next
|
|
1353
|
-
// if (!force && !utils.isNullOrUndefined(optionalExtensionObject)) {
|
|
1354
|
-
// throw new Error(
|
|
1355
|
-
// "bindExtensionObject: unsupported case : $extensionObject already exists on " +
|
|
1356
|
-
// this.browseName.toString() +
|
|
1357
|
-
// " " +
|
|
1358
|
-
// this.nodeId.toString()
|
|
1359
|
-
// );
|
|
1360
|
-
// }
|
|
1361
|
-
// istanbul ignore next
|
|
1362
|
-
if (!this.checkExtensionObjectIsCorrect(this.$extensionObject!)) {
|
|
1363
|
-
warningLog(
|
|
1364
|
-
"on node : ",
|
|
1365
|
-
this.browseName.toString(),
|
|
1366
|
-
this.nodeId.toString(),
|
|
1367
|
-
"dataType=",
|
|
1368
|
-
this.dataType.toString({ addressSpace: this.addressSpace })
|
|
1369
|
-
);
|
|
1370
|
-
warningLog(this.$extensionObject?.toString());
|
|
1371
|
-
throw new Error(
|
|
1372
|
-
"bindExtensionObject: $extensionObject is incorrect: we are expecting a " +
|
|
1373
|
-
this.dataType.toString({ addressSpace: this.addressSpace }) +
|
|
1374
|
-
" but we got a " +
|
|
1375
|
-
this.$extensionObject?.constructor.name
|
|
1376
|
-
);
|
|
1377
|
-
}
|
|
1378
|
-
return this.$extensionObject;
|
|
1379
|
-
// throw new Error("Variable already bound");
|
|
1380
|
-
}
|
|
1381
|
-
this.$extensionObject = optionalExtensionObject;
|
|
1382
|
-
|
|
1383
|
-
// ------------------------------------------------------------------
|
|
1384
|
-
|
|
1385
|
-
function prepareVariantValue(dataType: DataType, value: VariantLike): VariantLike {
|
|
1386
|
-
if ((dataType === DataType.Int32 || dataType === DataType.UInt32) && value && (value as any).key) {
|
|
1387
|
-
value = value.value;
|
|
1388
|
-
}
|
|
1389
|
-
return value;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
const bindProperty = (propertyNode: UAVariableImpl, name: string, extensionObject: ExtensionObject, dataType: DataType) => {
|
|
1393
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1394
|
-
const self = this;
|
|
1395
|
-
propertyNode.bindVariable(
|
|
1396
|
-
{
|
|
1397
|
-
timestamped_get: () => {
|
|
1398
|
-
const propertyValue = self.$extensionObject[name];
|
|
1399
|
-
|
|
1400
|
-
if (propertyValue === undefined) {
|
|
1401
|
-
propertyNode.$dataValue.value.dataType = DataType.Null;
|
|
1402
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1403
|
-
propertyNode.$dataValue.value.value = null;
|
|
1404
|
-
return new DataValue(propertyNode.$dataValue);
|
|
1405
|
-
}
|
|
1406
|
-
const value = prepareVariantValue(dataType, propertyValue);
|
|
1407
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1408
|
-
propertyNode.$dataValue.value.dataType = dataType;
|
|
1409
|
-
propertyNode.$dataValue.value.value = value;
|
|
1410
|
-
return new DataValue(propertyNode.$dataValue);
|
|
1411
|
-
},
|
|
1412
|
-
timestamped_set: (dataValue: DataValue, callback: CallbackT<StatusCode>) => {
|
|
1413
|
-
dataValue;
|
|
1414
|
-
callback(null, StatusCodes.BadNotWritable);
|
|
1415
|
-
}
|
|
1416
|
-
},
|
|
1417
|
-
true
|
|
1418
|
-
);
|
|
1419
|
-
};
|
|
1420
|
-
const components = this.getComponents();
|
|
1421
|
-
|
|
1422
|
-
// ------------------------------------------------------
|
|
1423
|
-
// make sure we have a structure
|
|
1424
|
-
// ------------------------------------------------------
|
|
1425
|
-
const s = this.readValue();
|
|
1426
|
-
// istanbul ignore next
|
|
1427
|
-
if (this.dataTypeObj.isAbstract) {
|
|
1428
|
-
warningLog("Warning the DataType associated with this Variable is abstract ", this.dataTypeObj.browseName.toString());
|
|
1429
|
-
warningLog("You need to provide a extension object yourself ");
|
|
1430
|
-
throw new Error("bindExtensionObject requires a extensionObject as associated dataType is only abstract");
|
|
1431
|
-
}
|
|
1432
|
-
if (s.value && (s.value.dataType === DataType.Null || (s.value.dataType === DataType.ExtensionObject && !s.value.value))) {
|
|
1433
|
-
// create a structure and bind it
|
|
1434
|
-
extensionObject_ = this.$extensionObject || addressSpace.constructExtensionObject(this.dataType, {});
|
|
1435
|
-
extensionObject_ = new Proxy(extensionObject_, makeHandler(this));
|
|
1436
|
-
this.$extensionObject = extensionObject_;
|
|
1437
|
-
|
|
1438
|
-
const theValue = new Variant({
|
|
1439
|
-
dataType: DataType.ExtensionObject,
|
|
1440
|
-
value: this.$extensionObject
|
|
1441
|
-
});
|
|
1442
|
-
this.setValueFromSource(theValue, StatusCodes.Good);
|
|
1443
|
-
|
|
1444
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1445
|
-
const self = this;
|
|
1446
|
-
this.bindVariable(
|
|
1447
|
-
{
|
|
1448
|
-
timestamped_get() {
|
|
1449
|
-
self.$dataValue.value.value = self.$extensionObject;
|
|
1450
|
-
const d = new DataValue(self.$dataValue);
|
|
1451
|
-
d.value = new Variant(d.value);
|
|
1452
|
-
return d;
|
|
1453
|
-
},
|
|
1454
|
-
timestamped_set(dataValue: DataValue, callback: CallbackT<StatusCode>) {
|
|
1455
|
-
const ext = dataValue.value.value;
|
|
1456
|
-
if (!self.checkExtensionObjectIsCorrect(ext)) {
|
|
1457
|
-
return callback(null, StatusCodes.BadInvalidArgument);
|
|
1458
|
-
}
|
|
1459
|
-
self.$extensionObject = new Proxy(ext, makeHandler(self));
|
|
1460
|
-
self.touchValue();
|
|
1461
|
-
callback(null, StatusCodes.Good);
|
|
1462
|
-
}
|
|
1463
|
-
},
|
|
1464
|
-
true
|
|
1465
|
-
);
|
|
1466
|
-
} else {
|
|
1467
|
-
// verify that variant has the correct type
|
|
1468
|
-
assert(s.value.dataType === DataType.ExtensionObject);
|
|
1469
|
-
this.$extensionObject = s.value.value;
|
|
1470
|
-
assert(this.checkExtensionObjectIsCorrect(this.$extensionObject!));
|
|
1471
|
-
assert(s.statusCode.equals(StatusCodes.Good));
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// ------------------------------------------------------
|
|
1475
|
-
// now bind each member
|
|
1476
|
-
// ------------------------------------------------------
|
|
1477
|
-
const definition = dt._getDefinition() as StructureDefinition | null;
|
|
1478
|
-
|
|
1479
|
-
// istanbul ignore next
|
|
1480
|
-
if (!definition) {
|
|
1481
|
-
throw new Error("xx definition missing in " + dt.toString());
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
const getOrCreateProperty = (field: StructureField): UAVariableImpl => {
|
|
1485
|
-
let property: UAVariableImpl;
|
|
1486
|
-
const selectedComponents = components.filter(
|
|
1487
|
-
(f) => f instanceof UAVariableImpl && f.browseName.name!.toString() === field.name
|
|
1488
|
-
);
|
|
1489
|
-
|
|
1490
|
-
if (field.dataType.value === DataType.Variant) {
|
|
1491
|
-
warningLog("Warning : variant is not supported in ExtensionObject");
|
|
1492
|
-
}
|
|
1493
|
-
if (selectedComponents.length === 1) {
|
|
1494
|
-
property = selectedComponents[0] as UAVariableImpl;
|
|
1495
|
-
/* istanbul ignore next */
|
|
1496
|
-
} else {
|
|
1497
|
-
debugLog("adding missing array variable", field.name, this.browseName.toString(), this.nodeId.toString());
|
|
1498
|
-
// todo: Handle array appropriately...
|
|
1499
|
-
assert(selectedComponents.length === 0);
|
|
1500
|
-
// create a variable (Note we may use ns=1;s=parentName/0:PropertyName)
|
|
1501
|
-
property = this.namespace.addVariable({
|
|
1502
|
-
browseName: { namespaceIndex: structureNamespace, name: field.name!.toString() },
|
|
1503
|
-
componentOf: this,
|
|
1504
|
-
dataType: field.dataType,
|
|
1505
|
-
minimumSamplingInterval: this.minimumSamplingInterval
|
|
1506
|
-
}) as UAVariableImpl;
|
|
1507
|
-
assert(property.minimumSamplingInterval === this.minimumSamplingInterval);
|
|
1508
|
-
}
|
|
1509
|
-
return property;
|
|
1510
|
-
};
|
|
1511
|
-
|
|
1512
|
-
for (const field of definition.fields || []) {
|
|
1513
|
-
if (NodeId.sameNodeId(NodeId.nullNodeId, field.dataType)) {
|
|
1514
|
-
warningLog("field.dataType is null ! ", field.toString(), NodeId.nullNodeId.toString());
|
|
1515
|
-
warningLog(" dataType replaced with BaseDataType ");
|
|
1516
|
-
warningLog(definition.toString());
|
|
1517
|
-
field.dataType = this.resolveNodeId("BaseDataType");
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
const camelCaseName = lowerFirstLetter(field.name!);
|
|
1521
|
-
assert(Object.prototype.hasOwnProperty.call(this.$extensionObject, camelCaseName));
|
|
1522
|
-
|
|
1523
|
-
const propertyNode = getOrCreateProperty(field);
|
|
1524
|
-
|
|
1525
|
-
propertyNode.$dataValue.statusCode = StatusCodes.Good;
|
|
1526
|
-
propertyNode.touchValue();
|
|
1527
|
-
|
|
1528
|
-
const basicDataType = addressSpace.findCorrespondingBasicDataType(field.dataType);
|
|
1529
|
-
|
|
1530
|
-
// istanbul ignore next
|
|
1531
|
-
if (doDebug) {
|
|
1532
|
-
const x = addressSpace.findNode(field.dataType)!.browseName.toString();
|
|
1533
|
-
debugLog(
|
|
1534
|
-
chalk.cyan("xxx"),
|
|
1535
|
-
" dataType",
|
|
1536
|
-
w(field.dataType.toString(), 8),
|
|
1537
|
-
w(field.name!, 35),
|
|
1538
|
-
"valueRank",
|
|
1539
|
-
chalk.cyan(w(valueRankToString(field.valueRank), 10)),
|
|
1540
|
-
chalk.green(w(x, 25)),
|
|
1541
|
-
"basicType = ",
|
|
1542
|
-
chalk.yellow(w(basicDataType.toString(), 20)),
|
|
1543
|
-
propertyNode.nodeId.toString(),
|
|
1544
|
-
propertyNode.readValue().statusCode.toString()
|
|
1545
|
-
);
|
|
1546
|
-
}
|
|
1547
|
-
if (this.$extensionObject[camelCaseName] !== undefined && basicDataType === DataType.ExtensionObject) {
|
|
1548
|
-
assert(this.$extensionObject[camelCaseName] instanceof Object);
|
|
1549
|
-
this.$extensionObject[camelCaseName] = new Proxy(this.$extensionObject[camelCaseName], makeHandler(propertyNode));
|
|
1550
|
-
|
|
1551
|
-
propertyNode._internal_set_value(
|
|
1552
|
-
new Variant({
|
|
1553
|
-
dataType: DataType.ExtensionObject,
|
|
1554
|
-
value: this.$extensionObject[camelCaseName]
|
|
1555
|
-
})
|
|
1556
|
-
);
|
|
1557
|
-
|
|
1558
|
-
propertyNode.bindExtensionObject();
|
|
1559
|
-
propertyNode.$extensionObject = this.$extensionObject[camelCaseName];
|
|
1560
|
-
} else {
|
|
1561
|
-
const prop = this.$extensionObject[camelCaseName];
|
|
1562
|
-
if (prop === undefined) {
|
|
1563
|
-
propertyNode._internal_set_value(
|
|
1564
|
-
new Variant({
|
|
1565
|
-
dataType: DataType.Null
|
|
1566
|
-
})
|
|
1567
|
-
);
|
|
1568
|
-
} else {
|
|
1569
|
-
const preparedValue = prepareVariantValue(basicDataType, prop);
|
|
1570
|
-
propertyNode._internal_set_value(
|
|
1571
|
-
new Variant({
|
|
1572
|
-
dataType: basicDataType,
|
|
1573
|
-
value: preparedValue
|
|
1574
|
-
})
|
|
1575
|
-
);
|
|
1331
|
+
public installExtensionObjectVariables(): void {
|
|
1332
|
+
_installExtensionObjectBindingOnProperties(this, { createMissingProp: true });
|
|
1333
|
+
// now recursively install extension object on children
|
|
1334
|
+
for (const child of this.getComponents()) {
|
|
1335
|
+
if (child.nodeClass === NodeClass.Variable && child instanceof UAVariableImpl) {
|
|
1336
|
+
if (child.isExtensionObject()) {
|
|
1337
|
+
child.installExtensionObjectVariables();
|
|
1576
1338
|
}
|
|
1577
|
-
|
|
1578
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1579
|
-
const self = this;
|
|
1580
|
-
// property.camelCaseName = camelCaseName;
|
|
1581
|
-
propertyNode.setValueFromSource = function (this: UAVariableImpl, variant: VariantLike) {
|
|
1582
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1583
|
-
const inner_this = this;
|
|
1584
|
-
const variant1 = Variant.coerce(variant);
|
|
1585
|
-
inner_this.verifyVariantCompatibility(variant1);
|
|
1586
|
-
self.$extensionObject[camelCaseName] = variant1.value;
|
|
1587
|
-
self.touchValue();
|
|
1588
|
-
};
|
|
1589
1339
|
}
|
|
1590
|
-
assert(propertyNode.readValue().statusCode.equals(StatusCodes.Good));
|
|
1591
|
-
bindProperty(propertyNode, camelCaseName, this.$extensionObject, basicDataType);
|
|
1592
1340
|
}
|
|
1593
|
-
assert(this.$extensionObject instanceof Object);
|
|
1594
|
-
return this.$extensionObject;
|
|
1595
1341
|
}
|
|
1342
|
+
/**
|
|
1343
|
+
* @method bindExtensionObject
|
|
1344
|
+
* @return {ExtensionObject}
|
|
1345
|
+
*/
|
|
1346
|
+
public bindExtensionObject(
|
|
1347
|
+
optionalExtensionObject?: ExtensionObject,
|
|
1348
|
+
options?: BindExtensionObjectOptions
|
|
1349
|
+
): ExtensionObject | null {
|
|
1350
|
+
return _bindExtensionObject(this, optionalExtensionObject, options);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1596
1353
|
|
|
1597
1354
|
public updateExtensionObjectPartial(partialExtensionObject?: { [key: string]: any }): ExtensionObject {
|
|
1598
1355
|
setExtensionObjectValue(this, partialExtensionObject);
|
|
@@ -1600,43 +1357,11 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1600
1357
|
}
|
|
1601
1358
|
|
|
1602
1359
|
public incrementExtensionObjectPartial(path: string | string[]): void {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
path = path.split(".");
|
|
1606
|
-
}
|
|
1607
|
-
assert(path instanceof Array);
|
|
1608
|
-
const extensionObject = this.constructExtensionObjectFromComponents();
|
|
1609
|
-
let i;
|
|
1610
|
-
// read partial value
|
|
1611
|
-
const partialData: any = {};
|
|
1612
|
-
let p: any = partialData;
|
|
1613
|
-
for (i = 0; i < path.length - 1; i++) {
|
|
1614
|
-
name = path[i];
|
|
1615
|
-
p[name] = {};
|
|
1616
|
-
p = p[name];
|
|
1617
|
-
}
|
|
1618
|
-
name = path[path.length - 1];
|
|
1619
|
-
p[name] = 0;
|
|
1620
|
-
|
|
1621
|
-
let c1 = partialData;
|
|
1622
|
-
let c2 = extensionObject;
|
|
1623
|
-
|
|
1624
|
-
for (i = 0; i < path.length - 1; i++) {
|
|
1625
|
-
name = path[i];
|
|
1626
|
-
c1 = partialData[name];
|
|
1627
|
-
c2 = extensionObject[name];
|
|
1628
|
-
}
|
|
1629
|
-
name = path[path.length - 1];
|
|
1630
|
-
c1[name] = c2[name];
|
|
1631
|
-
c1[name] += 1;
|
|
1632
|
-
|
|
1360
|
+
const extensionObject = this.readValue().value.value as ExtensionObject;
|
|
1361
|
+
const partialData = extractPartialData(path, extensionObject);
|
|
1633
1362
|
setExtensionObjectValue(this, partialData);
|
|
1634
1363
|
}
|
|
1635
1364
|
|
|
1636
|
-
public constructExtensionObjectFromComponents(): any {
|
|
1637
|
-
return this.readValue().value.value;
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
1365
|
public toString(): string {
|
|
1641
1366
|
const options = new ToStringBuilder();
|
|
1642
1367
|
UAVariable_toString.call(this, options);
|
|
@@ -1687,7 +1412,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1687
1412
|
callback?: CallbackT<HistoryReadResult>
|
|
1688
1413
|
): any {
|
|
1689
1414
|
assert(context instanceof SessionContext);
|
|
1690
|
-
assert(callback
|
|
1415
|
+
assert(typeof callback === 'function');
|
|
1691
1416
|
if (typeof this._historyRead !== "function") {
|
|
1692
1417
|
return callback!(null, new HistoryReadResult({ statusCode: StatusCodes.BadNotReadable }));
|
|
1693
1418
|
}
|
|
@@ -1779,14 +1504,15 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1779
1504
|
}
|
|
1780
1505
|
this.$dataValue.value = value;
|
|
1781
1506
|
}
|
|
1507
|
+
|
|
1508
|
+
|
|
1782
1509
|
public _internal_set_dataValue(dataValue: DataValue, indexRange?: NumericRange | null): void {
|
|
1783
1510
|
assert(dataValue, "expecting a dataValue");
|
|
1784
1511
|
assert(dataValue instanceof DataValue, "expecting dataValue to be a DataValue");
|
|
1785
1512
|
assert(dataValue !== this.$dataValue, "expecting dataValue to be different from previous DataValue instance");
|
|
1786
|
-
|
|
1787
1513
|
|
|
1788
1514
|
const addressSpace = this.addressSpace;
|
|
1789
|
-
if(!addressSpace) {
|
|
1515
|
+
if (!addressSpace) {
|
|
1790
1516
|
warningLog("UAVariable#_internal_set_dataValue : no addressSpace ! may be node has already been deleted ?");
|
|
1791
1517
|
return;
|
|
1792
1518
|
}
|
|
@@ -1808,6 +1534,14 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
|
|
|
1808
1534
|
warningLog(dataValue.toString());
|
|
1809
1535
|
throw new Error("Invalid Extension Object on nodeId =" + this.nodeId.toString());
|
|
1810
1536
|
}
|
|
1537
|
+
// ----------------------------------
|
|
1538
|
+
// if (this.$extensionObject) {
|
|
1539
|
+
// // we have an extension object already bound to this node
|
|
1540
|
+
// // the client is asking us to replace the object entierly by a new one
|
|
1541
|
+
// const ext = dataValue.value.value;
|
|
1542
|
+
// _setExtensionObject(this, ext);
|
|
1543
|
+
// return;
|
|
1544
|
+
// }
|
|
1811
1545
|
}
|
|
1812
1546
|
// // istanbul ignore next
|
|
1813
1547
|
// if (this.dataType.namespace === 0) {
|
|
@@ -1952,6 +1686,7 @@ export interface UAVariableImpl {
|
|
|
1952
1686
|
$$indexPropertyName: any;
|
|
1953
1687
|
}
|
|
1954
1688
|
|
|
1689
|
+
|
|
1955
1690
|
function check_valid_array(dataType: DataType, array: any): boolean {
|
|
1956
1691
|
if (Array.isArray(array)) {
|
|
1957
1692
|
return true;
|
|
@@ -2307,54 +2042,6 @@ function bind_getter(this: UAVariableImpl, options: GetterOptions) {
|
|
|
2307
2042
|
}
|
|
2308
2043
|
}
|
|
2309
2044
|
|
|
2310
|
-
function w(str: string, n: number): string {
|
|
2311
|
-
return (str + " ").substr(0, n);
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
function _getter(target: any, key: string /*, receiver*/) {
|
|
2315
|
-
if (target[key] === undefined) {
|
|
2316
|
-
return undefined;
|
|
2317
|
-
}
|
|
2318
|
-
return target[key];
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
|
-
function _setter(variable: UAVariable, target: any, key: string, value: any /*, receiver*/) {
|
|
2322
|
-
target[key] = value;
|
|
2323
|
-
const child = (variable as any)[key] as UAVariable | null;
|
|
2324
|
-
if (child && child.touchValue) {
|
|
2325
|
-
child.touchValue();
|
|
2326
|
-
}
|
|
2327
|
-
return true; // true means the set operation has succeeded
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
|
-
function makeHandler(variable: UAVariable) {
|
|
2331
|
-
const handler = {
|
|
2332
|
-
get: _getter,
|
|
2333
|
-
set: _setter.bind(null, variable)
|
|
2334
|
-
};
|
|
2335
|
-
return handler;
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
|
-
function setExtensionObjectValue(node: UAVariableImpl, partialObject: any) {
|
|
2339
|
-
const extensionObject = node.$extensionObject;
|
|
2340
|
-
if (!extensionObject) {
|
|
2341
|
-
throw new Error("setExtensionObjectValue node has no extension object " + node.browseName.toString());
|
|
2342
|
-
}
|
|
2343
|
-
|
|
2344
|
-
function _update_extension_object(extObject: any, partialObject1: any) {
|
|
2345
|
-
const keys = Object.keys(partialObject1);
|
|
2346
|
-
for (const prop of keys) {
|
|
2347
|
-
if (extObject[prop] instanceof Object) {
|
|
2348
|
-
_update_extension_object(extObject[prop], partialObject1[prop]);
|
|
2349
|
-
} else {
|
|
2350
|
-
extObject[prop] = partialObject1[prop];
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
|
|
2355
|
-
_update_extension_object(extensionObject, partialObject);
|
|
2356
|
-
}
|
|
2357
|
-
|
|
2358
2045
|
export interface UAVariableImplT<T, DT extends DataType> extends UAVariableImpl, UAVariableT<T, DT> {
|
|
2359
2046
|
on(): any;
|
|
2360
2047
|
once(): any;
|