@machinemetrics/io-adapter-lib 2.37.0 → 2.38.1
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/.circleci/config.yml +19 -5
- package/CHANGELOG.md +6 -0
- package/lib/transform/index.js +4 -0
- package/lib/transform/objectKeys.js +28 -0
- package/lib/transform/objectValues.js +28 -0
- package/lib/transform/risingEdgeCounter.js +9 -9
- package/package.json +1 -1
- package/test/configFiles/repro/active-condition-codes-repro.yml +15 -0
- package/test/configFiles/transform/object-keys.yml +14 -0
- package/test/configFiles/transform/object-values.yml +14 -0
- package/test/configFiles/transform/risingEdgeCounter.yml +4 -0
- package/test/repro/active-condition-codes-repro.test.js +41 -0
- package/test/transform/objectKeys.test.js +63 -0
- package/test/transform/objectValues.test.js +63 -0
- package/test/transform/risingEdgeCounter.test.js +19 -0
package/.circleci/config.yml
CHANGED
|
@@ -27,31 +27,45 @@ jobs:
|
|
|
27
27
|
- lib
|
|
28
28
|
- index.js
|
|
29
29
|
- package.json
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
# Publish jobs use npm trusted publishing (OIDC): no stored NPM token.
|
|
32
|
+
# npm >= 11.5.1 reads NPM_ID_TOKEN and exchanges it for a short-lived publish
|
|
33
|
+
# token. Provenance is not generated on CircleCI, and is unavailable for
|
|
34
|
+
# private repos regardless of CI provider.
|
|
31
35
|
publish:
|
|
32
36
|
docker:
|
|
33
|
-
- image: cimg/node:22.
|
|
37
|
+
- image: cimg/node:22.14
|
|
34
38
|
steps:
|
|
35
39
|
- checkout
|
|
36
40
|
- attach_workspace:
|
|
37
41
|
at: .
|
|
42
|
+
- run:
|
|
43
|
+
name: Update npm for trusted publishing
|
|
44
|
+
command: sudo npm install -g npm@latest
|
|
38
45
|
- run:
|
|
39
46
|
name: Publish to NPM
|
|
40
47
|
command: |
|
|
41
|
-
echo "
|
|
48
|
+
echo "node $(node --version) / npm $(npm --version)"
|
|
49
|
+
export NPM_ID_TOKEN="$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}')"
|
|
50
|
+
test -n "$NPM_ID_TOKEN" || { echo "ERROR: empty OIDC token (NPM_ID_TOKEN) — cannot use trusted publishing"; exit 1; }
|
|
42
51
|
npm publish --access public
|
|
43
52
|
|
|
44
53
|
publish-beta:
|
|
45
54
|
docker:
|
|
46
|
-
- image: cimg/node:22.
|
|
55
|
+
- image: cimg/node:22.14
|
|
47
56
|
steps:
|
|
48
57
|
- checkout
|
|
49
58
|
- attach_workspace:
|
|
50
59
|
at: .
|
|
60
|
+
- run:
|
|
61
|
+
name: Update npm for trusted publishing
|
|
62
|
+
command: sudo npm install -g npm@latest
|
|
51
63
|
- run:
|
|
52
64
|
name: Publish Beta to NPM
|
|
53
65
|
command: |
|
|
54
|
-
echo "
|
|
66
|
+
echo "node $(node --version) / npm $(npm --version)"
|
|
67
|
+
export NPM_ID_TOKEN="$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}')"
|
|
68
|
+
test -n "$NPM_ID_TOKEN" || { echo "ERROR: empty OIDC token (NPM_ID_TOKEN) — cannot use trusted publishing"; exit 1; }
|
|
55
69
|
npm publish --access public --tag beta
|
|
56
70
|
|
|
57
71
|
validate-version:
|
package/CHANGELOG.md
CHANGED
package/lib/transform/index.js
CHANGED
|
@@ -21,6 +21,8 @@ const MaxFilter = require('./max');
|
|
|
21
21
|
const MaxLengthFilter = require('./maxLength');
|
|
22
22
|
const MinDeltaFilter = require('./minDelta');
|
|
23
23
|
const MinFilter = require('./min');
|
|
24
|
+
const ObjectKeysFilter = require('./objectKeys');
|
|
25
|
+
const ObjectValuesFilter = require('./objectValues');
|
|
24
26
|
const OffDelayFilter = require('./offDelay');
|
|
25
27
|
const OnDelayFilter = require('./onDelay');
|
|
26
28
|
const PatternEscapeFilter = require('./patternEscape');
|
|
@@ -68,6 +70,8 @@ module.exports = {
|
|
|
68
70
|
maxLength: MaxLengthFilter,
|
|
69
71
|
min: MinFilter,
|
|
70
72
|
minDelta: MinDeltaFilter,
|
|
73
|
+
objectKeys: ObjectKeysFilter,
|
|
74
|
+
objectValues: ObjectValuesFilter,
|
|
71
75
|
offDelay: OffDelayFilter,
|
|
72
76
|
onDelay: OnDelayFilter,
|
|
73
77
|
patternEscape: PatternEscapeFilter,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const TransformState = require('./transformState');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the keys of an object sample. Arrays return their numeric indexes;
|
|
8
|
+
* other values pass through unchanged.
|
|
9
|
+
*/
|
|
10
|
+
class ObjectKeysFilter extends TransformState {
|
|
11
|
+
static op = 'object-keys';
|
|
12
|
+
|
|
13
|
+
static create(_args) {
|
|
14
|
+
return new ObjectKeysFilter();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
filter(context, value, time) {
|
|
18
|
+
if (_.isArray(value)) {
|
|
19
|
+
this.commitValue(context, _.range(value.length), time);
|
|
20
|
+
} else if (_.isObject(value)) {
|
|
21
|
+
this.commitValue(context, Object.keys(value), time);
|
|
22
|
+
} else {
|
|
23
|
+
this.commitValue(context, value, time);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = ObjectKeysFilter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const TransformState = require('./transformState');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the values of an object sample. Arrays pass through unchanged;
|
|
8
|
+
* other non-object values also pass through unchanged.
|
|
9
|
+
*/
|
|
10
|
+
class ObjectValuesFilter extends TransformState {
|
|
11
|
+
static op = 'object-values';
|
|
12
|
+
|
|
13
|
+
static create(_args) {
|
|
14
|
+
return new ObjectValuesFilter();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
filter(context, value, time) {
|
|
18
|
+
if (_.isArray(value)) {
|
|
19
|
+
this.commitValue(context, value, time);
|
|
20
|
+
} else if (_.isObject(value)) {
|
|
21
|
+
this.commitValue(context, Object.values(value), time);
|
|
22
|
+
} else {
|
|
23
|
+
this.commitValue(context, value, time);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = ObjectValuesFilter;
|
|
@@ -10,13 +10,13 @@ const TransformState = require('./transformState');
|
|
|
10
10
|
* the counter will be incremented before the output value is emitted.
|
|
11
11
|
*/
|
|
12
12
|
class RisingEdgeCounterFilter extends TransformState {
|
|
13
|
-
constructor({ engine, path, args: { mergeWindow,
|
|
13
|
+
constructor({ engine, path, args: { mergeWindow, amount = {}, reset = {} } }) {
|
|
14
14
|
super();
|
|
15
15
|
|
|
16
16
|
this.mergeWindow = mergeWindow || 0;
|
|
17
17
|
this.engine = engine;
|
|
18
|
-
this.accumExpression =
|
|
19
|
-
this.accumSources = engine.expressionService.expressionTriggers(`${path}.
|
|
18
|
+
this.accumExpression = amount.compiledExpression;
|
|
19
|
+
this.accumSources = engine.expressionService.expressionTriggers(`${path}.amount`);
|
|
20
20
|
this.resetExpression = reset.compiledExpression;
|
|
21
21
|
this.resetSources = engine.expressionService.expressionTriggers(`${path}.reset`);
|
|
22
22
|
|
|
@@ -37,12 +37,12 @@ class RisingEdgeCounterFilter extends TransformState {
|
|
|
37
37
|
defaultAttribute: 'amount',
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
let
|
|
41
|
-
if (!_.isUndefined(
|
|
40
|
+
let amount = _.get(defn.args, 'amount', defn.args.count);
|
|
41
|
+
if (!_.isUndefined(amount)) {
|
|
42
42
|
try {
|
|
43
|
-
const expression =
|
|
43
|
+
const expression = amount.toString();
|
|
44
44
|
const compiledExpression = configUtil.compileExpression(expression, this.op);
|
|
45
|
-
|
|
45
|
+
amount = { expression, compiledExpression };
|
|
46
46
|
} catch (err) {
|
|
47
47
|
configUtil.throwConfigError(`Problem evaluating expression: ${err.message}`, this.op);
|
|
48
48
|
}
|
|
@@ -64,12 +64,12 @@ class RisingEdgeCounterFilter extends TransformState {
|
|
|
64
64
|
configUtil.requirePositive(mergeWindow, 'merge-window', this.op);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
defn.args = {
|
|
67
|
+
defn.args = { amount, reset, mergeWindow };
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
static getExpressions(configUtil, body, info) {
|
|
71
71
|
return [
|
|
72
|
-
...configUtil.getExpressions(body, { ...info, field: '
|
|
72
|
+
...configUtil.getExpressions(body, { ...info, field: 'amount' }, true),
|
|
73
73
|
...configUtil.getExpressions(body, { ...info, field: 'reset' }),
|
|
74
74
|
];
|
|
75
75
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
device: mtconnect-adapter
|
|
3
|
+
endpoint: localhost:8001
|
|
4
|
+
mtconnect-port: 8002
|
|
5
|
+
declare-keys:
|
|
6
|
+
- cond1:
|
|
7
|
+
type: condition
|
|
8
|
+
variables:
|
|
9
|
+
activeCodes:
|
|
10
|
+
- source: cond1
|
|
11
|
+
- object-values
|
|
12
|
+
- reject:
|
|
13
|
+
expression: this.level != 'FAULT' and this.level != 'WARNING'
|
|
14
|
+
- map:
|
|
15
|
+
- expression: this.code
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EngineV2 = require('../../lib/engine/engineV2');
|
|
4
|
+
const Builder = require('../../lib/engine/transformBuilderV2');
|
|
5
|
+
const testUtils = require('../util/testUtils');
|
|
6
|
+
|
|
7
|
+
describe('repro active condition codes via object-values pipeline', async function () {
|
|
8
|
+
let config;
|
|
9
|
+
before(async () => {
|
|
10
|
+
config = await testUtils.loadConfig('repro/active-condition-codes-repro.yml');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('emits the list of FAULT/WARNING codes as the condition table evolves', function () {
|
|
14
|
+
const engine = new EngineV2(config);
|
|
15
|
+
const builder = new Builder(config);
|
|
16
|
+
builder.build(engine);
|
|
17
|
+
|
|
18
|
+
const source = testUtils.mtconnectSource(config.device.keys);
|
|
19
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.activeCodes, source);
|
|
20
|
+
|
|
21
|
+
source.sendCondition('cond1', { level: 'NORMAL' }, 0);
|
|
22
|
+
source.sendCondition('cond1', { code: 'X01', level: 'WARNING', message: 'W X01' }, 1000);
|
|
23
|
+
source.sendCondition('cond1', { code: 'X02', level: 'FAULT', message: 'F X02' }, 2000);
|
|
24
|
+
source.sendCondition('cond1', { code: 'X01', level: 'NORMAL' }, 3000);
|
|
25
|
+
source.sendCondition('cond1', { code: 'X01', level: 'FAULT', message: 'F X01' }, 4000);
|
|
26
|
+
source.sendCondition('cond1', { level: 'UNAVAILABLE' }, 5000);
|
|
27
|
+
source.sendCondition('cond1', { code: 'X02', level: 'WARNING', message: 'W X02' }, 6000);
|
|
28
|
+
source.sendCondition('cond1', { level: 'UNAVAILABLE' }, 7000);
|
|
29
|
+
|
|
30
|
+
engine.validateFilter([
|
|
31
|
+
[[], 0],
|
|
32
|
+
[['X01'], 1],
|
|
33
|
+
[['X01', 'X02'], 2],
|
|
34
|
+
[['X02'], 3],
|
|
35
|
+
[['X01', 'X02'], 4],
|
|
36
|
+
[[], 5],
|
|
37
|
+
[['X02'], 6],
|
|
38
|
+
[[], 7],
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EngineV2 = require('../../lib/engine/engineV2');
|
|
4
|
+
const Builder = require('../../lib/engine/transformBuilderV2');
|
|
5
|
+
const ObjectKeys = require('../../lib/transform').objectKeys;
|
|
6
|
+
const testUtils = require('../util/testUtils');
|
|
7
|
+
|
|
8
|
+
describe('object-keys transform tests', function () {
|
|
9
|
+
it('returns keys for objects', async function () {
|
|
10
|
+
await testUtils.testValue(new ObjectKeys(), { a: 1, b: 2 }, ['a', 'b']);
|
|
11
|
+
await testUtils.testValue(new ObjectKeys(), { x: 'hello', y: 'world', z: '!' }, ['x', 'y', 'z']);
|
|
12
|
+
await testUtils.testValue(new ObjectKeys(), {}, []);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('returns indexes for arrays', async function () {
|
|
16
|
+
await testUtils.testValue(new ObjectKeys(), ['a', 'b', 'c'], [0, 1, 2]);
|
|
17
|
+
await testUtils.testValue(new ObjectKeys(), [10, 20], [0, 1]);
|
|
18
|
+
await testUtils.testValue(new ObjectKeys(), [], []);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('passes through non-object values', async function () {
|
|
22
|
+
await testUtils.testValue(new ObjectKeys(), 42, 42);
|
|
23
|
+
await testUtils.testValue(new ObjectKeys(), 'hello', 'hello');
|
|
24
|
+
await testUtils.testValue(new ObjectKeys(), null, null);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('object-keys full engine config file tests', function () {
|
|
29
|
+
let config;
|
|
30
|
+
before(async () => {
|
|
31
|
+
config = await testUtils.loadConfig('transform/object-keys.yml');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns keys for objects', function () {
|
|
35
|
+
const engine = new EngineV2(config);
|
|
36
|
+
const builder = new Builder(config);
|
|
37
|
+
builder.build(engine);
|
|
38
|
+
|
|
39
|
+
const source = testUtils.valueSource();
|
|
40
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.objKeys, source);
|
|
41
|
+
|
|
42
|
+
source.sendValue('obj', { a: 1, b: 2, c: 3 }, 0);
|
|
43
|
+
|
|
44
|
+
engine.validateFilter([
|
|
45
|
+
[['a', 'b', 'c'], 0],
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('returns indexes for arrays', function () {
|
|
50
|
+
const engine = new EngineV2(config);
|
|
51
|
+
const builder = new Builder(config);
|
|
52
|
+
builder.build(engine);
|
|
53
|
+
|
|
54
|
+
const source = testUtils.valueSource();
|
|
55
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.arrKeys, source);
|
|
56
|
+
|
|
57
|
+
source.sendValue('arr', ['x', 'y', 'z'], 0);
|
|
58
|
+
|
|
59
|
+
engine.validateFilter([
|
|
60
|
+
[[0, 1, 2], 0],
|
|
61
|
+
]);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EngineV2 = require('../../lib/engine/engineV2');
|
|
4
|
+
const Builder = require('../../lib/engine/transformBuilderV2');
|
|
5
|
+
const ObjectValues = require('../../lib/transform').objectValues;
|
|
6
|
+
const testUtils = require('../util/testUtils');
|
|
7
|
+
|
|
8
|
+
describe('object-values transform tests', function () {
|
|
9
|
+
it('returns values for objects', async function () {
|
|
10
|
+
await testUtils.testValue(new ObjectValues(), { a: 1, b: 2 }, [1, 2]);
|
|
11
|
+
await testUtils.testValue(new ObjectValues(), { x: 'hello', y: 'world', z: '!' }, ['hello', 'world', '!']);
|
|
12
|
+
await testUtils.testValue(new ObjectValues(), {}, []);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('returns array itself for arrays', async function () {
|
|
16
|
+
await testUtils.testValue(new ObjectValues(), ['a', 'b', 'c'], ['a', 'b', 'c']);
|
|
17
|
+
await testUtils.testValue(new ObjectValues(), [10, 20], [10, 20]);
|
|
18
|
+
await testUtils.testValue(new ObjectValues(), [], []);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('passes through non-object values', async function () {
|
|
22
|
+
await testUtils.testValue(new ObjectValues(), 42, 42);
|
|
23
|
+
await testUtils.testValue(new ObjectValues(), 'hello', 'hello');
|
|
24
|
+
await testUtils.testValue(new ObjectValues(), null, null);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('object-values full engine config file tests', function () {
|
|
29
|
+
let config;
|
|
30
|
+
before(async () => {
|
|
31
|
+
config = await testUtils.loadConfig('transform/object-values.yml');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns values for objects', function () {
|
|
35
|
+
const engine = new EngineV2(config);
|
|
36
|
+
const builder = new Builder(config);
|
|
37
|
+
builder.build(engine);
|
|
38
|
+
|
|
39
|
+
const source = testUtils.valueSource();
|
|
40
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.objValues, source);
|
|
41
|
+
|
|
42
|
+
source.sendValue('obj', { a: 1, b: 2, c: 3 }, 0);
|
|
43
|
+
|
|
44
|
+
engine.validateFilter([
|
|
45
|
+
[[1, 2, 3], 0],
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('returns the array itself for arrays', function () {
|
|
50
|
+
const engine = new EngineV2(config);
|
|
51
|
+
const builder = new Builder(config);
|
|
52
|
+
builder.build(engine);
|
|
53
|
+
|
|
54
|
+
const source = testUtils.valueSource();
|
|
55
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.arrValues, source);
|
|
56
|
+
|
|
57
|
+
source.sendValue('arr', ['x', 'y', 'z'], 0);
|
|
58
|
+
|
|
59
|
+
engine.validateFilter([
|
|
60
|
+
[['x', 'y', 'z'], 0],
|
|
61
|
+
]);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -224,4 +224,23 @@ describe('rising-edge-counter full engine config file tests', function () {
|
|
|
224
224
|
[14, 8], [17, 10], [17, 12], [20, 14],
|
|
225
225
|
]);
|
|
226
226
|
});
|
|
227
|
+
|
|
228
|
+
it('count by expression 3', function () {
|
|
229
|
+
const engine = new EngineV2(config);
|
|
230
|
+
const builder = new Builder(config);
|
|
231
|
+
builder.build(engine);
|
|
232
|
+
|
|
233
|
+
const source = testUtils.valueSource();
|
|
234
|
+
testUtils.attachEngineTransformValidator(engine, engine.variablePool.var8, source);
|
|
235
|
+
|
|
236
|
+
source.sendValue('ppc', 7, 0);
|
|
237
|
+
source.sendValues('active', [[false, 0], [true, 2], [false, 4], [true, 6]]);
|
|
238
|
+
source.sendValue('ppc', 3, 7);
|
|
239
|
+
source.sendValues('active', [[false, 8], [true, 10], [false, 12], [true, 14]]);
|
|
240
|
+
|
|
241
|
+
engine.validateFilter([
|
|
242
|
+
[0, 0], [7, 2], [7, 4], [14, 6], [14, 7],
|
|
243
|
+
[14, 8], [17, 10], [17, 12], [20, 14],
|
|
244
|
+
]);
|
|
245
|
+
});
|
|
227
246
|
});
|