@machinemetrics/io-adapter-lib 2.33.0 → 2.34.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/CHANGELOG.md +5 -0
- package/lib/config/engineConfigV2.js +1 -1
- package/lib/config/transformConfigUtil.js +20 -9
- package/lib/engine/transformBuilderV2.js +5 -0
- package/lib/expressionService.js +9 -0
- package/lib/transform/expression.js +23 -1
- package/lib/transform/map.js +10 -0
- package/lib/transform/source.js +11 -2
- package/lib/transform/transformState.js +3 -0
- package/package.json +1 -1
- package/test/configFiles/transform/map.yml +5 -0
- package/test/configFiles/transform/source.yml +12 -0
- package/test/transform/map.test.js +18 -0
- package/test/transform/source.test.js +14 -0
- package/test/transform/state.test.js +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.34.0]
|
|
4
|
+
- Added support for initializing variables from constant source or expression ops
|
|
5
|
+
- Fixed map not recognizing external identifiers in sub-ops
|
|
6
|
+
- Allow string and bool constants in shorthand variable declarations
|
|
7
|
+
|
|
3
8
|
## [2.33.0]
|
|
4
9
|
- Added support for numeric indexing in expressions
|
|
5
10
|
- Fixed map not allowing any transforms to be chained beyond it
|
|
@@ -42,7 +42,7 @@ class EngineConfig {
|
|
|
42
42
|
// - source: composite.parts
|
|
43
43
|
|
|
44
44
|
this.config.variables = _.mapValues(this.config.variables, (variable) => {
|
|
45
|
-
if (_.isString(variable)) {
|
|
45
|
+
if (_.isString(variable) || _.isNumber(variable) || _.isBoolean(variable)) {
|
|
46
46
|
return [{ source: variable }];
|
|
47
47
|
}
|
|
48
48
|
return variable;
|
|
@@ -94,18 +94,22 @@ class TransformConfigUtil {
|
|
|
94
94
|
|
|
95
95
|
getExpressionsFromVariables(variables) {
|
|
96
96
|
return _(variables).map((defn, varName) => {
|
|
97
|
-
return
|
|
98
|
-
return _.map(transformContainer, (body, attribute) => {
|
|
99
|
-
if (this.transformMap[attribute]) {
|
|
100
|
-
return this.transformMap[attribute].getExpressions(this, body, { varName, index, attribute });
|
|
101
|
-
}
|
|
102
|
-
return [];
|
|
103
|
-
});
|
|
104
|
-
});
|
|
97
|
+
return this.getExpressionsFromChain(defn, varName);
|
|
105
98
|
}).flattenDeep().compact().value();
|
|
106
99
|
}
|
|
107
100
|
|
|
108
|
-
|
|
101
|
+
getExpressionsFromChain(chain, varName, ancestorVars = []) {
|
|
102
|
+
return _.map(chain, (transformContainer, index) => {
|
|
103
|
+
return _.map(transformContainer, (body, attribute) => {
|
|
104
|
+
if (this.transformMap[attribute]) {
|
|
105
|
+
return this.transformMap[attribute].getExpressions(this, body, { varName, index, attribute, ancestorVars });
|
|
106
|
+
}
|
|
107
|
+
return [];
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getExpressions(body, { varName, index, attribute, field, ancestorVars }, includeDefault = false) {
|
|
109
113
|
const parts = [];
|
|
110
114
|
|
|
111
115
|
let expression = '';
|
|
@@ -140,6 +144,13 @@ class TransformConfigUtil {
|
|
|
140
144
|
expression,
|
|
141
145
|
});
|
|
142
146
|
|
|
147
|
+
_.each(ancestorVars, (ancestorVar) => {
|
|
148
|
+
parts.push({
|
|
149
|
+
path: `variables.${ancestorVar}`,
|
|
150
|
+
expression,
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
143
154
|
return parts;
|
|
144
155
|
}
|
|
145
156
|
|
|
@@ -34,6 +34,11 @@ class TransformBuilderV2 {
|
|
|
34
34
|
engine.addVariable(varName, transform);
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
+
|
|
38
|
+
_.each(engine.variablePool, (chain, varName) => {
|
|
39
|
+
const context = { sourceType: 'init', trigger: varName };
|
|
40
|
+
chain.init(context, 0);
|
|
41
|
+
});
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
createTransformChain(engine, transformList, varName, base = false) {
|
package/lib/expressionService.js
CHANGED
|
@@ -9,6 +9,7 @@ class ExpressionService {
|
|
|
9
9
|
this.availableNamesByChannel = {};
|
|
10
10
|
this.referencedNamesByChannel = {};
|
|
11
11
|
this.referencedNamesByPath = {};
|
|
12
|
+
this.selfReferencedPaths = {};
|
|
12
13
|
this.pathsByReferenceName = {};
|
|
13
14
|
this.defaultValues = {};
|
|
14
15
|
this.channelsLookup = {};
|
|
@@ -117,6 +118,10 @@ class ExpressionService {
|
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
120
|
});
|
|
121
|
+
|
|
122
|
+
if (this.findName(expression, 'this')) {
|
|
123
|
+
this.selfReferencedPaths[path] = true;
|
|
124
|
+
}
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
addStringExpression({ string, path, withThis } = {}) {
|
|
@@ -298,6 +303,10 @@ class ExpressionService {
|
|
|
298
303
|
return this.referencedNamesByPath[path] || [];
|
|
299
304
|
}
|
|
300
305
|
|
|
306
|
+
expressionHasSelfReference(path) {
|
|
307
|
+
return !!this.selfReferencedPaths[path];
|
|
308
|
+
}
|
|
309
|
+
|
|
301
310
|
expressionsTriggeredBy(name) {
|
|
302
311
|
return this.pathsByReferenceName[name] || [];
|
|
303
312
|
}
|
|
@@ -30,6 +30,18 @@ class ExpressionFilter extends TransformState {
|
|
|
30
30
|
this.engine = engine;
|
|
31
31
|
this.compiledExpression = compiledExpression;
|
|
32
32
|
this.selfSources = engine.expressionService.expressionTriggers(path);
|
|
33
|
+
this.hasSelfReference = engine.expressionService.expressionHasSelfReference(path);
|
|
34
|
+
|
|
35
|
+
// If there's no variables in the expression, it's a constant that can be evaluated once
|
|
36
|
+
if (_.isEmpty(this.selfSources) && !this.hasSelfReference) {
|
|
37
|
+
try {
|
|
38
|
+
this.constantSource = true;
|
|
39
|
+
this.constantValue = this.compiledExpression.evaluate();
|
|
40
|
+
this.lastSuppliedValue = this.constantValue;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
// Oh well
|
|
43
|
+
}
|
|
44
|
+
}
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
static op = 'expression';
|
|
@@ -49,6 +61,12 @@ class ExpressionFilter extends TransformState {
|
|
|
49
61
|
return configUtil.getExpressions(body, info);
|
|
50
62
|
}
|
|
51
63
|
|
|
64
|
+
init(context, time) {
|
|
65
|
+
if (this.constantSource) {
|
|
66
|
+
this.update(context, this.lastSuppliedValue, time);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
52
70
|
update(context, value, time) {
|
|
53
71
|
if (value === 'UNAVAILABLE') {
|
|
54
72
|
this.setUnavailable(context, time);
|
|
@@ -58,7 +76,11 @@ class ExpressionFilter extends TransformState {
|
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
filter(context, value, time) {
|
|
61
|
-
if (this.constantSource
|
|
79
|
+
if (this.constantSource) {
|
|
80
|
+
this.commitValue(context, this.constantValue, time);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (this.simpleExpression) {
|
|
62
84
|
this.commitValue(context, value, time);
|
|
63
85
|
return;
|
|
64
86
|
}
|
package/lib/transform/map.js
CHANGED
|
@@ -72,6 +72,16 @@ class MapFilter extends TransformState {
|
|
|
72
72
|
defn.args = { transforms };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
static getExpressions(configUtil, body, info) {
|
|
76
|
+
const varName = `${info.varName}.${info.index}.${info.attribute}`;
|
|
77
|
+
const ancestorVars = [
|
|
78
|
+
...info.ancestorVars,
|
|
79
|
+
info.varName,
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
return configUtil.getExpressionsFromChain(body, varName, ancestorVars);
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
initReset() {
|
|
76
86
|
this.chainList = [];
|
|
77
87
|
this.value = [];
|
package/lib/transform/source.js
CHANGED
|
@@ -40,8 +40,9 @@ class SourceFilter extends TransformState {
|
|
|
40
40
|
// If there's no variables in the expression, it's a constant that can be evaluated once
|
|
41
41
|
if (_.isEmpty(this.selfSources)) {
|
|
42
42
|
try {
|
|
43
|
-
this.lastSuppliedValue = this.compiledExpression.evaluate();
|
|
44
43
|
this.constantSource = true;
|
|
44
|
+
this.constantValue = this.compiledExpression.evaluate();
|
|
45
|
+
this.lastSuppliedValue = this.constantValue;
|
|
45
46
|
} catch (err) {
|
|
46
47
|
// Oh well
|
|
47
48
|
}
|
|
@@ -77,6 +78,12 @@ class SourceFilter extends TransformState {
|
|
|
77
78
|
return configUtil.getExpressions(body, info);
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
init(context, time) {
|
|
82
|
+
if (this.constantSource) {
|
|
83
|
+
this.update(context, this.lastSuppliedValue, time);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
80
87
|
update(context, value, time) {
|
|
81
88
|
if (value === 'UNAVAILABLE') {
|
|
82
89
|
this.setUnavailable(context, time);
|
|
@@ -86,7 +93,9 @@ class SourceFilter extends TransformState {
|
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
filter(context, value, time) {
|
|
89
|
-
if (this.constantSource
|
|
96
|
+
if (this.constantSource) {
|
|
97
|
+
this.commitValue(context, this.constantValue, time);
|
|
98
|
+
} else if (this.simpleSource) {
|
|
90
99
|
this.commitValue(context, value, time);
|
|
91
100
|
} else {
|
|
92
101
|
const localState = {};
|
|
@@ -56,6 +56,9 @@ class TransformState extends EventEmitter {
|
|
|
56
56
|
return this.pendingChangeTime;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// Called after all varaibles have been added to the engine.
|
|
60
|
+
init(_context, _time) { }
|
|
61
|
+
|
|
59
62
|
update(context, value, time) {
|
|
60
63
|
if (!this.available) {
|
|
61
64
|
this.available = true;
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ declare-keys:
|
|
|
8
8
|
- program
|
|
9
9
|
- complex
|
|
10
10
|
- complex2
|
|
11
|
+
- complex3
|
|
11
12
|
variables:
|
|
12
13
|
var1:
|
|
13
14
|
- source: counter
|
|
@@ -23,3 +24,7 @@ variables:
|
|
|
23
24
|
- map:
|
|
24
25
|
- expression: this.subkey
|
|
25
26
|
- expression: this[1]
|
|
27
|
+
var4:
|
|
28
|
+
- source: complex3
|
|
29
|
+
- map:
|
|
30
|
+
- expression: this.subkey + counter
|
|
@@ -18,3 +18,15 @@ variables:
|
|
|
18
18
|
- expression: this + yact
|
|
19
19
|
var5:
|
|
20
20
|
- source: execution != 'MANUAL'
|
|
21
|
+
const1:
|
|
22
|
+
- source: 10
|
|
23
|
+
const2:
|
|
24
|
+
- source: true
|
|
25
|
+
const3:
|
|
26
|
+
- source: "'ACTIVE'"
|
|
27
|
+
const4:
|
|
28
|
+
- source: max(4, 5, 6)
|
|
29
|
+
var6:
|
|
30
|
+
- source: const1 + (const2 ? 20:30)
|
|
31
|
+
var7:
|
|
32
|
+
- source: xact + const1
|
|
@@ -54,4 +54,22 @@ describe('map full engine config file tests', function () {
|
|
|
54
54
|
[10, 0],
|
|
55
55
|
]);
|
|
56
56
|
});
|
|
57
|
+
|
|
58
|
+
it('subkey map with external ref', function () {
|
|
59
|
+
const engine = new EngineV2(config);
|
|
60
|
+
const builder = new Builder(config);
|
|
61
|
+
builder.build(engine);
|
|
62
|
+
|
|
63
|
+
const source = testUtils.valueSource();
|
|
64
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.var4, source);
|
|
65
|
+
|
|
66
|
+
source.sendValue('counter', 100, 0);
|
|
67
|
+
source.sendValue('complex3', [{ subkey: 10, xx: 15 }, { subkey: 20, xx: 30 }], 0);
|
|
68
|
+
source.sendValue('counter', 200, 2);
|
|
69
|
+
|
|
70
|
+
engine.validateFilter([
|
|
71
|
+
[[110, 120], 0],
|
|
72
|
+
[[210, 220], 2],
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
57
75
|
});
|
|
@@ -128,6 +128,20 @@ describe('source full engine config file tests', async function () {
|
|
|
128
128
|
[true, 0],
|
|
129
129
|
]);
|
|
130
130
|
});
|
|
131
|
+
|
|
132
|
+
it('calculates constant values correctly', async function () {
|
|
133
|
+
const engine = new EngineV2(config);
|
|
134
|
+
const builder = new Builder(config);
|
|
135
|
+
builder.build(engine);
|
|
136
|
+
|
|
137
|
+
const source = new ValueSource();
|
|
138
|
+
engine.addValueSource(source);
|
|
139
|
+
|
|
140
|
+
expect(engine.getState('const1').value).to.eq(10);
|
|
141
|
+
expect(engine.getState('const2').value).to.eq(true);
|
|
142
|
+
expect(engine.getState('const3').value).to.eq('ACTIVE');
|
|
143
|
+
expect(engine.getState('const4').value).to.eq(6);
|
|
144
|
+
});
|
|
131
145
|
});
|
|
132
146
|
|
|
133
147
|
class ValueSource extends EventEmitter {
|
|
@@ -136,6 +136,9 @@ describe('expression transform tests', function () {
|
|
|
136
136
|
const source = testUtils.valueSource();
|
|
137
137
|
testUtils.attachEngineTransformValidator(engine, engine.variablePool.test5, source);
|
|
138
138
|
|
|
139
|
+
// Set by const init
|
|
140
|
+
expect(engine.getState('test5').value).to.eq('READY');
|
|
141
|
+
|
|
139
142
|
source.sendValue('exec', 'ACTIVE', 0);
|
|
140
143
|
source.sendValue('in-fault', false, 2);
|
|
141
144
|
source.sendValue('in-fault', false, 4);
|
|
@@ -144,7 +147,7 @@ describe('expression transform tests', function () {
|
|
|
144
147
|
source.sendValue('in-fault', false, 10);
|
|
145
148
|
|
|
146
149
|
engine.validateFilter([
|
|
147
|
-
['READY', 0],
|
|
150
|
+
// ['READY', 0], // Initial value doesn't come through because chain starts with constant
|
|
148
151
|
['ACTIVE', 2],
|
|
149
152
|
['ACTIVE', 4],
|
|
150
153
|
['STOPPED', 6],
|