@sports-alliance/sports-lib 6.1.6 → 6.1.8
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/lib/cjs/activities/activity-parsing-options.d.ts +1 -0
- package/lib/cjs/activities/activity-parsing-options.js +4 -1
- package/lib/cjs/data/data-store.spec.js +36 -0
- package/lib/cjs/data/data.store.d.ts +3 -1
- package/lib/cjs/data/data.store.js +8 -4
- package/lib/cjs/events/utilities/activity.utilities.d.ts +6 -1
- package/lib/cjs/events/utilities/activity.utilities.js +24 -4
- package/lib/cjs/events/utilities/activity.utilities.spec.js +92 -0
- package/lib/esm/activities/activity-parsing-options.d.ts +1 -0
- package/lib/esm/activities/activity-parsing-options.js +4 -1
- package/lib/esm/data/data-store.spec.js +37 -1
- package/lib/esm/data/data.store.d.ts +3 -1
- package/lib/esm/data/data.store.js +8 -4
- package/lib/esm/events/utilities/activity.utilities.d.ts +6 -1
- package/lib/esm/events/utilities/activity.utilities.js +24 -4
- package/lib/esm/events/utilities/activity.utilities.spec.js +92 -0
- package/package.json +1 -1
|
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ActivityParsingOptions = void 0;
|
|
4
4
|
class ActivityParsingOptions {
|
|
5
5
|
constructor(options) {
|
|
6
|
+
var _a;
|
|
6
7
|
this.streams = options.streams;
|
|
7
8
|
this.maxActivityDurationDays = options.maxActivityDurationDays;
|
|
9
|
+
this.generateUnitStreams = (_a = options.generateUnitStreams) !== null && _a !== void 0 ? _a : true;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
exports.ActivityParsingOptions = ActivityParsingOptions;
|
|
@@ -13,5 +15,6 @@ ActivityParsingOptions.DEFAULT = new ActivityParsingOptions({
|
|
|
13
15
|
smooth: { altitudeSmooth: true, grade: true, gradeSmooth: true },
|
|
14
16
|
fixAbnormal: { speed: false }
|
|
15
17
|
},
|
|
16
|
-
maxActivityDurationDays: 14
|
|
18
|
+
maxActivityDurationDays: 14,
|
|
19
|
+
generateUnitStreams: true
|
|
17
20
|
});
|
|
@@ -39,4 +39,40 @@ describe('DataStore', () => {
|
|
|
39
39
|
// @todo here we should think
|
|
40
40
|
expect(data_store_1.DynamicDataLoader.allUnitDerivedDataTypes.sort()).toEqual(unitDerivedDataTypes.sort());
|
|
41
41
|
});
|
|
42
|
+
describe('getUnitBasedDataTypesFromDataTypes', () => {
|
|
43
|
+
it('should include derived types by default', () => {
|
|
44
|
+
const types = [data_speed_1.DataSpeedKilometersPerHour.type, data_pace_1.DataPace.type];
|
|
45
|
+
const settings = {
|
|
46
|
+
speedUnits: [data_speed_1.DataSpeedKilometersPerHour.type],
|
|
47
|
+
swimPaceUnits: [],
|
|
48
|
+
paceUnits: [data_pace_1.DataPaceMinutesPerMile.type],
|
|
49
|
+
gradeAdjustedSpeedUnits: [],
|
|
50
|
+
gradeAdjustedPaceUnits: [],
|
|
51
|
+
verticalSpeedUnits: [],
|
|
52
|
+
distanceUnits: [],
|
|
53
|
+
elevationUnits: [],
|
|
54
|
+
temperatureUnits: [],
|
|
55
|
+
weightUnits: []
|
|
56
|
+
};
|
|
57
|
+
const result = data_store_1.DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([data_speed_1.DataSpeed.type], settings);
|
|
58
|
+
expect(result).toContain(data_pace_1.DataPaceMinutesPerMile.type);
|
|
59
|
+
});
|
|
60
|
+
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
61
|
+
const settings = {
|
|
62
|
+
speedUnits: [data_speed_1.DataSpeedKilometersPerHour.type],
|
|
63
|
+
swimPaceUnits: [],
|
|
64
|
+
paceUnits: [data_pace_1.DataPaceMinutesPerMile.type],
|
|
65
|
+
gradeAdjustedSpeedUnits: [],
|
|
66
|
+
gradeAdjustedPaceUnits: [],
|
|
67
|
+
verticalSpeedUnits: [],
|
|
68
|
+
distanceUnits: [],
|
|
69
|
+
elevationUnits: [],
|
|
70
|
+
temperatureUnits: [],
|
|
71
|
+
weightUnits: []
|
|
72
|
+
};
|
|
73
|
+
const result = data_store_1.DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([data_speed_1.DataSpeed.type], settings, { includeDerivedTypes: false });
|
|
74
|
+
expect(result).toContain(data_speed_1.DataSpeedKilometersPerHour.type);
|
|
75
|
+
expect(result).not.toContain(data_pace_1.DataPaceMinutesPerMile.type);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
42
78
|
});
|
|
@@ -45,7 +45,9 @@ export declare class DynamicDataLoader {
|
|
|
45
45
|
* @param dataTypes
|
|
46
46
|
* @param userUnitSettings
|
|
47
47
|
*/
|
|
48
|
-
static getUnitBasedDataTypesFromDataTypes(dataTypes: string[], userUnitSettings?: UserUnitSettingsInterface
|
|
48
|
+
static getUnitBasedDataTypesFromDataTypes(dataTypes: string[], userUnitSettings?: UserUnitSettingsInterface, options?: {
|
|
49
|
+
includeDerivedTypes?: boolean;
|
|
50
|
+
}): string[];
|
|
49
51
|
/**
|
|
50
52
|
* Gets the unitbased types
|
|
51
53
|
* @param dataType
|
|
@@ -498,19 +498,23 @@ class DynamicDataLoader {
|
|
|
498
498
|
* @param dataTypes
|
|
499
499
|
* @param userUnitSettings
|
|
500
500
|
*/
|
|
501
|
-
static getUnitBasedDataTypesFromDataTypes(dataTypes, userUnitSettings) {
|
|
501
|
+
static getUnitBasedDataTypesFromDataTypes(dataTypes, userUnitSettings, options = { includeDerivedTypes: true }) {
|
|
502
502
|
let unitBasedDataTypes = [];
|
|
503
503
|
if (!userUnitSettings) {
|
|
504
504
|
return unitBasedDataTypes;
|
|
505
505
|
}
|
|
506
506
|
if (dataTypes.indexOf(data_speed_1.DataSpeed.type) !== -1) {
|
|
507
507
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.speedUnits);
|
|
508
|
-
|
|
509
|
-
|
|
508
|
+
if (options.includeDerivedTypes) {
|
|
509
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.swimPaceUnits);
|
|
510
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.paceUnits);
|
|
511
|
+
}
|
|
510
512
|
}
|
|
511
513
|
if (dataTypes.indexOf(data_grade_adjusted_speed_1.DataGradeAdjustedSpeed.type) !== -1) {
|
|
512
514
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedSpeedUnits);
|
|
513
|
-
|
|
515
|
+
if (options.includeDerivedTypes) {
|
|
516
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedPaceUnits);
|
|
517
|
+
}
|
|
514
518
|
}
|
|
515
519
|
if (dataTypes.indexOf(data_vertical_speed_1.DataVerticalSpeed.type) !== -1) {
|
|
516
520
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.verticalSpeedUnits);
|
|
@@ -63,14 +63,19 @@ export declare class ActivityUtilities {
|
|
|
63
63
|
*/
|
|
64
64
|
private static createByActivityTypeAltiDistanceSpeedBasedStreams;
|
|
65
65
|
/**
|
|
66
|
+
|
|
66
67
|
* @todo unit test (get the pun?)
|
|
67
68
|
* This creates streams that are deriving as unit based streams
|
|
68
69
|
* For example it will create pace from speed, swim pace from speed but also speed in km/h as a unitstream
|
|
69
70
|
* @param streams
|
|
70
71
|
* @param activityType
|
|
71
72
|
* @param unitStreamTypes DynamicDataLoader.allUnitDerivedDataTypes this acts like a whitelist for the unit derived units ONLY!
|
|
73
|
+
* @param options
|
|
72
74
|
*/
|
|
73
|
-
static createUnitStreamsFromStreams(streams: StreamInterface[], activityType: ActivityTypes, unitStreamTypes?: string[]
|
|
75
|
+
static createUnitStreamsFromStreams(streams: StreamInterface[], activityType: ActivityTypes, unitStreamTypes?: string[], options?: {
|
|
76
|
+
includeDerivedTypes?: boolean;
|
|
77
|
+
includeUnitVariants?: boolean;
|
|
78
|
+
}): StreamInterface[];
|
|
74
79
|
/**
|
|
75
80
|
* Generates missing streams for an activity such as distance etc if they are missing
|
|
76
81
|
* This will always create a steam even if the distance is 0
|
|
@@ -291,7 +291,9 @@ class ActivityUtilities {
|
|
|
291
291
|
static generateMissingStreams(activity) {
|
|
292
292
|
// Compute missing streams
|
|
293
293
|
this.generateMissingStreamsForActivity(activity);
|
|
294
|
-
|
|
294
|
+
if (!activity.parseOptions || activity.parseOptions.generateUnitStreams) {
|
|
295
|
+
activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
|
|
296
|
+
}
|
|
295
297
|
}
|
|
296
298
|
static getSummaryStatsForActivities(activities) {
|
|
297
299
|
const stats = [];
|
|
@@ -664,24 +666,39 @@ class ActivityUtilities {
|
|
|
664
666
|
}, []);
|
|
665
667
|
}
|
|
666
668
|
/**
|
|
669
|
+
|
|
667
670
|
* @todo unit test (get the pun?)
|
|
668
671
|
* This creates streams that are deriving as unit based streams
|
|
669
672
|
* For example it will create pace from speed, swim pace from speed but also speed in km/h as a unitstream
|
|
670
673
|
* @param streams
|
|
671
674
|
* @param activityType
|
|
672
675
|
* @param unitStreamTypes DynamicDataLoader.allUnitDerivedDataTypes this acts like a whitelist for the unit derived units ONLY!
|
|
676
|
+
* @param options
|
|
673
677
|
*/
|
|
674
|
-
static createUnitStreamsFromStreams(streams, activityType, unitStreamTypes
|
|
678
|
+
static createUnitStreamsFromStreams(streams, activityType, unitStreamTypes, options = {
|
|
679
|
+
includeDerivedTypes: true,
|
|
680
|
+
includeUnitVariants: true
|
|
681
|
+
}) {
|
|
675
682
|
// @todo perhaps check input to be unitStreamTypesStrictly
|
|
676
683
|
const unitStreamTypesToCreate = unitStreamTypes || data_store_1.DynamicDataLoader.allUnitDerivedDataTypes;
|
|
677
684
|
let baseUnitStreams = [];
|
|
678
685
|
const speedStream = streams.find(stream => stream.type === data_speed_1.DataSpeed.type);
|
|
679
686
|
if (speedStream) {
|
|
680
|
-
|
|
687
|
+
if (options.includeDerivedTypes) {
|
|
688
|
+
baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
baseUnitStreams.push(speedStream);
|
|
692
|
+
}
|
|
681
693
|
}
|
|
682
694
|
const gradeAdjustedSpeedStream = streams.find(stream => stream.type === data_grade_adjusted_speed_1.DataGradeAdjustedSpeed.type);
|
|
683
695
|
if (gradeAdjustedSpeedStream) {
|
|
684
|
-
|
|
696
|
+
if (options.includeDerivedTypes) {
|
|
697
|
+
baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
baseUnitStreams.push(gradeAdjustedSpeedStream);
|
|
701
|
+
}
|
|
685
702
|
}
|
|
686
703
|
const verticalSpeedStream = streams.find(stream => stream.type === data_vertical_speed_1.DataVerticalSpeed.type);
|
|
687
704
|
if (verticalSpeedStream) {
|
|
@@ -692,6 +709,9 @@ class ActivityUtilities {
|
|
|
692
709
|
}
|
|
693
710
|
// @todo add distance ?
|
|
694
711
|
const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
712
|
+
if (options.includeUnitVariants === false) {
|
|
713
|
+
return startWith;
|
|
714
|
+
}
|
|
695
715
|
return Object.keys(data_store_1.DynamicDataLoader.dataTypeUnitGroups).reduce((array, baseDataType) => {
|
|
696
716
|
const baseStream = baseUnitStreams.find(stream => stream.type === baseDataType);
|
|
697
717
|
if (!baseStream) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const event_1 = require("../event");
|
|
4
|
+
const data_speed_max_1 = require("../../data/data.speed-max");
|
|
4
5
|
const activity_1 = require("../../activities/activity");
|
|
5
6
|
const data_heart_rate_1 = require("../../data/data.heart-rate");
|
|
6
7
|
const data_altitude_1 = require("../../data/data.altitude");
|
|
@@ -17,6 +18,8 @@ const lap_types_1 = require("../../laps/lap.types");
|
|
|
17
18
|
const data_time_1 = require("../../data/data.time");
|
|
18
19
|
const file_type_enum_1 = require("../adapters/file-type.enum");
|
|
19
20
|
const importer_json_1 = require("../adapters/importers/json/importer.json");
|
|
21
|
+
const data_pace_1 = require("../../data/data.pace");
|
|
22
|
+
const data_speed_2 = require("../../data/data.speed");
|
|
20
23
|
describe('Activity Utilities', () => {
|
|
21
24
|
let event;
|
|
22
25
|
beforeEach(() => {
|
|
@@ -224,4 +227,93 @@ describe('Activity Utilities', () => {
|
|
|
224
227
|
done();
|
|
225
228
|
});
|
|
226
229
|
});
|
|
230
|
+
describe('createUnitStreamsFromStreams', () => {
|
|
231
|
+
it('should include derived types and unit variants by default', () => {
|
|
232
|
+
const streams = [new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20])];
|
|
233
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running);
|
|
234
|
+
const paceStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
235
|
+
const kmhStream = result.find(s => s.type === data_speed_2.DataSpeedKilometersPerHour.type);
|
|
236
|
+
expect(paceStream).toBeDefined();
|
|
237
|
+
expect(kmhStream).toBeDefined();
|
|
238
|
+
});
|
|
239
|
+
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
240
|
+
const streams = [new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20])];
|
|
241
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, undefined, { includeDerivedTypes: false, includeUnitVariants: true });
|
|
242
|
+
const paceStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
243
|
+
const kmhStream = result.find(s => s.type === data_speed_2.DataSpeedKilometersPerHour.type);
|
|
244
|
+
expect(paceStream).toBeUndefined();
|
|
245
|
+
expect(kmhStream).toBeDefined();
|
|
246
|
+
});
|
|
247
|
+
it('should exclude unit variants when includeUnitVariants is false', () => {
|
|
248
|
+
const streams = [new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20])];
|
|
249
|
+
// We pass DataPace.type in unitStreamTypes so we can check if the derived base stream is present
|
|
250
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, [data_pace_1.DataPace.type], { includeDerivedTypes: true, includeUnitVariants: false });
|
|
251
|
+
const paceStream = result.find(s => s.type === data_pace_1.DataPace.type);
|
|
252
|
+
const paceUnitStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
253
|
+
expect(paceStream).toBeDefined(); // Derived type should be there
|
|
254
|
+
expect(paceUnitStream).toBeUndefined(); // Unit variant should be gone
|
|
255
|
+
});
|
|
256
|
+
it('should exclude both derived types and unit variants', () => {
|
|
257
|
+
const streams = [new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20])];
|
|
258
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, [data_pace_1.DataPace.type], { includeDerivedTypes: false, includeUnitVariants: false });
|
|
259
|
+
const paceStream = result.find(s => s.type === data_pace_1.DataPace.type);
|
|
260
|
+
const paceUnitStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
261
|
+
expect(paceStream).toBeUndefined();
|
|
262
|
+
expect(paceUnitStream).toBeUndefined();
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
describe('generateMissingStreams', () => {
|
|
266
|
+
it('should generate unit streams by default (generateUnitStreams = true)', () => {
|
|
267
|
+
const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'));
|
|
268
|
+
// Add a speed stream
|
|
269
|
+
activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
|
|
270
|
+
activity_utilities_1.ActivityUtilities.generateMissingStreams(activity);
|
|
271
|
+
// Should have generated "sister" types (e.g. Pace) and unit variants (e.g. Speed km/h)
|
|
272
|
+
expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(true);
|
|
273
|
+
expect(activity.hasStreamData(data_pace_1.DataPaceMinutesPerMile.type)).toBe(true);
|
|
274
|
+
});
|
|
275
|
+
it('should NOT generate unit streams when generateUnitStreams = false', () => {
|
|
276
|
+
const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'));
|
|
277
|
+
// Mock parsing options
|
|
278
|
+
activity.parseOptions = {
|
|
279
|
+
streams: { smooth: {}, fixAbnormal: {} },
|
|
280
|
+
maxActivityDurationDays: 14,
|
|
281
|
+
generateUnitStreams: false,
|
|
282
|
+
};
|
|
283
|
+
// Add a speed stream
|
|
284
|
+
activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
|
|
285
|
+
activity_utilities_1.ActivityUtilities.generateMissingStreams(activity);
|
|
286
|
+
// Should NOT have generated unit variants
|
|
287
|
+
expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(false);
|
|
288
|
+
// It might still generate some "derived" streams depending on other flags, but our specific unit loop should be skipped
|
|
289
|
+
// The Pace stream comes from createUnitStreamsFromStreams too, so it should also be missing
|
|
290
|
+
expect(activity.hasStreamData(data_pace_1.DataPaceMinutesPerMile.type)).toBe(false);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
describe('generateMissingStreamsAndStatsForActivity', () => {
|
|
294
|
+
it('should generate unit STATS even if unit STREAMS are disabled', () => {
|
|
295
|
+
const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'));
|
|
296
|
+
activity.parseOptions = {
|
|
297
|
+
streams: { smooth: {}, fixAbnormal: {} },
|
|
298
|
+
maxActivityDurationDays: 14,
|
|
299
|
+
generateUnitStreams: false, // DISABLE streams
|
|
300
|
+
};
|
|
301
|
+
// Add a speed stream [10 m/s, 20 m/s]
|
|
302
|
+
// Max speed = 20 m/s
|
|
303
|
+
activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
|
|
304
|
+
activity_utilities_1.ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
305
|
+
// 1. Verify Streams are missing (as requested)
|
|
306
|
+
expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(false);
|
|
307
|
+
// 1. Verify Streams are missing (as requested)
|
|
308
|
+
expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(false);
|
|
309
|
+
// 2. Verify Stats are PRESENT (Safety Check)
|
|
310
|
+
// 20 m/s = 72 km/h
|
|
311
|
+
// We check for the stat by its string type if we can't import the constant easily, or iterate.
|
|
312
|
+
// Based on activity.utilities.ts it uses: DataSpeedMaxKilometersPerHour
|
|
313
|
+
const allStats = Array.from(activity.getStats().values());
|
|
314
|
+
const speedMaxKmh = allStats.find(s => s.getType() === data_speed_max_1.DataSpeedMaxKilometersPerHour.type);
|
|
315
|
+
expect(speedMaxKmh).toBeDefined();
|
|
316
|
+
expect(speedMaxKmh === null || speedMaxKmh === void 0 ? void 0 : speedMaxKmh.getValue()).toBe(72);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
227
319
|
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export class ActivityParsingOptions {
|
|
2
2
|
constructor(options) {
|
|
3
|
+
var _a;
|
|
3
4
|
this.streams = options.streams;
|
|
4
5
|
this.maxActivityDurationDays = options.maxActivityDurationDays;
|
|
6
|
+
this.generateUnitStreams = (_a = options.generateUnitStreams) !== null && _a !== void 0 ? _a : true;
|
|
5
7
|
}
|
|
6
8
|
}
|
|
7
9
|
ActivityParsingOptions.DEFAULT = new ActivityParsingOptions({
|
|
@@ -9,5 +11,6 @@ ActivityParsingOptions.DEFAULT = new ActivityParsingOptions({
|
|
|
9
11
|
smooth: { altitudeSmooth: true, grade: true, gradeSmooth: true },
|
|
10
12
|
fixAbnormal: { speed: false }
|
|
11
13
|
},
|
|
12
|
-
maxActivityDurationDays: 14
|
|
14
|
+
maxActivityDurationDays: 14,
|
|
15
|
+
generateUnitStreams: true
|
|
13
16
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataSpeedFeetPerMinute, DataSpeedFeetPerSecond, DataSpeedKilometersPerHour, DataSpeedKnots, DataSpeedMetersPerMinute, DataSpeedMilesPerHour } from './data.speed';
|
|
1
|
+
import { DataSpeedFeetPerMinute, DataSpeedFeetPerSecond, DataSpeedKilometersPerHour, DataSpeedKnots, DataSpeedMetersPerMinute, DataSpeedMilesPerHour, DataSpeed } from './data.speed';
|
|
2
2
|
import { DataPace, DataPaceMinutesPerMile } from './data.pace';
|
|
3
3
|
import { DataSwimPace, DataSwimPaceMinutesPer100Yard } from './data.swim-pace';
|
|
4
4
|
import { DataGradeAdjustedSpeedFeetPerMinute, DataGradeAdjustedSpeedFeetPerSecond, DataGradeAdjustedSpeedKilometersPerHour, DataGradeAdjustedSpeedKnots, DataGradeAdjustedSpeedMetersPerMinute, DataGradeAdjustedSpeedMilesPerHour } from './data.grade-adjusted-speed';
|
|
@@ -37,4 +37,40 @@ describe('DataStore', () => {
|
|
|
37
37
|
// @todo here we should think
|
|
38
38
|
expect(DynamicDataLoader.allUnitDerivedDataTypes.sort()).toEqual(unitDerivedDataTypes.sort());
|
|
39
39
|
});
|
|
40
|
+
describe('getUnitBasedDataTypesFromDataTypes', () => {
|
|
41
|
+
it('should include derived types by default', () => {
|
|
42
|
+
const types = [DataSpeedKilometersPerHour.type, DataPace.type];
|
|
43
|
+
const settings = {
|
|
44
|
+
speedUnits: [DataSpeedKilometersPerHour.type],
|
|
45
|
+
swimPaceUnits: [],
|
|
46
|
+
paceUnits: [DataPaceMinutesPerMile.type],
|
|
47
|
+
gradeAdjustedSpeedUnits: [],
|
|
48
|
+
gradeAdjustedPaceUnits: [],
|
|
49
|
+
verticalSpeedUnits: [],
|
|
50
|
+
distanceUnits: [],
|
|
51
|
+
elevationUnits: [],
|
|
52
|
+
temperatureUnits: [],
|
|
53
|
+
weightUnits: []
|
|
54
|
+
};
|
|
55
|
+
const result = DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([DataSpeed.type], settings);
|
|
56
|
+
expect(result).toContain(DataPaceMinutesPerMile.type);
|
|
57
|
+
});
|
|
58
|
+
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
59
|
+
const settings = {
|
|
60
|
+
speedUnits: [DataSpeedKilometersPerHour.type],
|
|
61
|
+
swimPaceUnits: [],
|
|
62
|
+
paceUnits: [DataPaceMinutesPerMile.type],
|
|
63
|
+
gradeAdjustedSpeedUnits: [],
|
|
64
|
+
gradeAdjustedPaceUnits: [],
|
|
65
|
+
verticalSpeedUnits: [],
|
|
66
|
+
distanceUnits: [],
|
|
67
|
+
elevationUnits: [],
|
|
68
|
+
temperatureUnits: [],
|
|
69
|
+
weightUnits: []
|
|
70
|
+
};
|
|
71
|
+
const result = DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([DataSpeed.type], settings, { includeDerivedTypes: false });
|
|
72
|
+
expect(result).toContain(DataSpeedKilometersPerHour.type);
|
|
73
|
+
expect(result).not.toContain(DataPaceMinutesPerMile.type);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
40
76
|
});
|
|
@@ -45,7 +45,9 @@ export declare class DynamicDataLoader {
|
|
|
45
45
|
* @param dataTypes
|
|
46
46
|
* @param userUnitSettings
|
|
47
47
|
*/
|
|
48
|
-
static getUnitBasedDataTypesFromDataTypes(dataTypes: string[], userUnitSettings?: UserUnitSettingsInterface
|
|
48
|
+
static getUnitBasedDataTypesFromDataTypes(dataTypes: string[], userUnitSettings?: UserUnitSettingsInterface, options?: {
|
|
49
|
+
includeDerivedTypes?: boolean;
|
|
50
|
+
}): string[];
|
|
49
51
|
/**
|
|
50
52
|
* Gets the unitbased types
|
|
51
53
|
* @param dataType
|
|
@@ -493,19 +493,23 @@ export class DynamicDataLoader {
|
|
|
493
493
|
* @param dataTypes
|
|
494
494
|
* @param userUnitSettings
|
|
495
495
|
*/
|
|
496
|
-
static getUnitBasedDataTypesFromDataTypes(dataTypes, userUnitSettings) {
|
|
496
|
+
static getUnitBasedDataTypesFromDataTypes(dataTypes, userUnitSettings, options = { includeDerivedTypes: true }) {
|
|
497
497
|
let unitBasedDataTypes = [];
|
|
498
498
|
if (!userUnitSettings) {
|
|
499
499
|
return unitBasedDataTypes;
|
|
500
500
|
}
|
|
501
501
|
if (dataTypes.indexOf(DataSpeed.type) !== -1) {
|
|
502
502
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.speedUnits);
|
|
503
|
-
|
|
504
|
-
|
|
503
|
+
if (options.includeDerivedTypes) {
|
|
504
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.swimPaceUnits);
|
|
505
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.paceUnits);
|
|
506
|
+
}
|
|
505
507
|
}
|
|
506
508
|
if (dataTypes.indexOf(DataGradeAdjustedSpeed.type) !== -1) {
|
|
507
509
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedSpeedUnits);
|
|
508
|
-
|
|
510
|
+
if (options.includeDerivedTypes) {
|
|
511
|
+
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedPaceUnits);
|
|
512
|
+
}
|
|
509
513
|
}
|
|
510
514
|
if (dataTypes.indexOf(DataVerticalSpeed.type) !== -1) {
|
|
511
515
|
unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.verticalSpeedUnits);
|
|
@@ -63,14 +63,19 @@ export declare class ActivityUtilities {
|
|
|
63
63
|
*/
|
|
64
64
|
private static createByActivityTypeAltiDistanceSpeedBasedStreams;
|
|
65
65
|
/**
|
|
66
|
+
|
|
66
67
|
* @todo unit test (get the pun?)
|
|
67
68
|
* This creates streams that are deriving as unit based streams
|
|
68
69
|
* For example it will create pace from speed, swim pace from speed but also speed in km/h as a unitstream
|
|
69
70
|
* @param streams
|
|
70
71
|
* @param activityType
|
|
71
72
|
* @param unitStreamTypes DynamicDataLoader.allUnitDerivedDataTypes this acts like a whitelist for the unit derived units ONLY!
|
|
73
|
+
* @param options
|
|
72
74
|
*/
|
|
73
|
-
static createUnitStreamsFromStreams(streams: StreamInterface[], activityType: ActivityTypes, unitStreamTypes?: string[]
|
|
75
|
+
static createUnitStreamsFromStreams(streams: StreamInterface[], activityType: ActivityTypes, unitStreamTypes?: string[], options?: {
|
|
76
|
+
includeDerivedTypes?: boolean;
|
|
77
|
+
includeUnitVariants?: boolean;
|
|
78
|
+
}): StreamInterface[];
|
|
74
79
|
/**
|
|
75
80
|
* Generates missing streams for an activity such as distance etc if they are missing
|
|
76
81
|
* This will always create a steam even if the distance is 0
|
|
@@ -288,7 +288,9 @@ export class ActivityUtilities {
|
|
|
288
288
|
static generateMissingStreams(activity) {
|
|
289
289
|
// Compute missing streams
|
|
290
290
|
this.generateMissingStreamsForActivity(activity);
|
|
291
|
-
|
|
291
|
+
if (!activity.parseOptions || activity.parseOptions.generateUnitStreams) {
|
|
292
|
+
activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
|
|
293
|
+
}
|
|
292
294
|
}
|
|
293
295
|
static getSummaryStatsForActivities(activities) {
|
|
294
296
|
const stats = [];
|
|
@@ -661,24 +663,39 @@ export class ActivityUtilities {
|
|
|
661
663
|
}, []);
|
|
662
664
|
}
|
|
663
665
|
/**
|
|
666
|
+
|
|
664
667
|
* @todo unit test (get the pun?)
|
|
665
668
|
* This creates streams that are deriving as unit based streams
|
|
666
669
|
* For example it will create pace from speed, swim pace from speed but also speed in km/h as a unitstream
|
|
667
670
|
* @param streams
|
|
668
671
|
* @param activityType
|
|
669
672
|
* @param unitStreamTypes DynamicDataLoader.allUnitDerivedDataTypes this acts like a whitelist for the unit derived units ONLY!
|
|
673
|
+
* @param options
|
|
670
674
|
*/
|
|
671
|
-
static createUnitStreamsFromStreams(streams, activityType, unitStreamTypes
|
|
675
|
+
static createUnitStreamsFromStreams(streams, activityType, unitStreamTypes, options = {
|
|
676
|
+
includeDerivedTypes: true,
|
|
677
|
+
includeUnitVariants: true
|
|
678
|
+
}) {
|
|
672
679
|
// @todo perhaps check input to be unitStreamTypesStrictly
|
|
673
680
|
const unitStreamTypesToCreate = unitStreamTypes || DynamicDataLoader.allUnitDerivedDataTypes;
|
|
674
681
|
let baseUnitStreams = [];
|
|
675
682
|
const speedStream = streams.find(stream => stream.type === DataSpeed.type);
|
|
676
683
|
if (speedStream) {
|
|
677
|
-
|
|
684
|
+
if (options.includeDerivedTypes) {
|
|
685
|
+
baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
baseUnitStreams.push(speedStream);
|
|
689
|
+
}
|
|
678
690
|
}
|
|
679
691
|
const gradeAdjustedSpeedStream = streams.find(stream => stream.type === DataGradeAdjustedSpeed.type);
|
|
680
692
|
if (gradeAdjustedSpeedStream) {
|
|
681
|
-
|
|
693
|
+
if (options.includeDerivedTypes) {
|
|
694
|
+
baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
baseUnitStreams.push(gradeAdjustedSpeedStream);
|
|
698
|
+
}
|
|
682
699
|
}
|
|
683
700
|
const verticalSpeedStream = streams.find(stream => stream.type === DataVerticalSpeed.type);
|
|
684
701
|
if (verticalSpeedStream) {
|
|
@@ -689,6 +706,9 @@ export class ActivityUtilities {
|
|
|
689
706
|
}
|
|
690
707
|
// @todo add distance ?
|
|
691
708
|
const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
709
|
+
if (options.includeUnitVariants === false) {
|
|
710
|
+
return startWith;
|
|
711
|
+
}
|
|
692
712
|
return Object.keys(DynamicDataLoader.dataTypeUnitGroups).reduce((array, baseDataType) => {
|
|
693
713
|
const baseStream = baseUnitStreams.find(stream => stream.type === baseDataType);
|
|
694
714
|
if (!baseStream) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Event } from '../event';
|
|
2
|
+
import { DataSpeedMaxKilometersPerHour } from '../../data/data.speed-max';
|
|
2
3
|
import { Activity } from '../../activities/activity';
|
|
3
4
|
import { DataHeartRate } from '../../data/data.heart-rate';
|
|
4
5
|
import { DataAltitude } from '../../data/data.altitude';
|
|
@@ -15,6 +16,8 @@ import { LapTypes } from '../../laps/lap.types';
|
|
|
15
16
|
import { DataTime } from '../../data/data.time';
|
|
16
17
|
import { FileType } from '../adapters/file-type.enum';
|
|
17
18
|
import { EventImporterJSON } from '../adapters/importers/json/importer.json';
|
|
19
|
+
import { DataPace, DataPaceMinutesPerMile } from '../../data/data.pace';
|
|
20
|
+
import { DataSpeedKilometersPerHour } from '../../data/data.speed';
|
|
18
21
|
describe('Activity Utilities', () => {
|
|
19
22
|
let event;
|
|
20
23
|
beforeEach(() => {
|
|
@@ -222,4 +225,93 @@ describe('Activity Utilities', () => {
|
|
|
222
225
|
done();
|
|
223
226
|
});
|
|
224
227
|
});
|
|
228
|
+
describe('createUnitStreamsFromStreams', () => {
|
|
229
|
+
it('should include derived types and unit variants by default', () => {
|
|
230
|
+
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
231
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running);
|
|
232
|
+
const paceStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
233
|
+
const kmhStream = result.find(s => s.type === DataSpeedKilometersPerHour.type);
|
|
234
|
+
expect(paceStream).toBeDefined();
|
|
235
|
+
expect(kmhStream).toBeDefined();
|
|
236
|
+
});
|
|
237
|
+
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
238
|
+
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
239
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, undefined, { includeDerivedTypes: false, includeUnitVariants: true });
|
|
240
|
+
const paceStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
241
|
+
const kmhStream = result.find(s => s.type === DataSpeedKilometersPerHour.type);
|
|
242
|
+
expect(paceStream).toBeUndefined();
|
|
243
|
+
expect(kmhStream).toBeDefined();
|
|
244
|
+
});
|
|
245
|
+
it('should exclude unit variants when includeUnitVariants is false', () => {
|
|
246
|
+
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
247
|
+
// We pass DataPace.type in unitStreamTypes so we can check if the derived base stream is present
|
|
248
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], { includeDerivedTypes: true, includeUnitVariants: false });
|
|
249
|
+
const paceStream = result.find(s => s.type === DataPace.type);
|
|
250
|
+
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
251
|
+
expect(paceStream).toBeDefined(); // Derived type should be there
|
|
252
|
+
expect(paceUnitStream).toBeUndefined(); // Unit variant should be gone
|
|
253
|
+
});
|
|
254
|
+
it('should exclude both derived types and unit variants', () => {
|
|
255
|
+
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
256
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], { includeDerivedTypes: false, includeUnitVariants: false });
|
|
257
|
+
const paceStream = result.find(s => s.type === DataPace.type);
|
|
258
|
+
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
259
|
+
expect(paceStream).toBeUndefined();
|
|
260
|
+
expect(paceUnitStream).toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
describe('generateMissingStreams', () => {
|
|
264
|
+
it('should generate unit streams by default (generateUnitStreams = true)', () => {
|
|
265
|
+
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
266
|
+
// Add a speed stream
|
|
267
|
+
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
268
|
+
ActivityUtilities.generateMissingStreams(activity);
|
|
269
|
+
// Should have generated "sister" types (e.g. Pace) and unit variants (e.g. Speed km/h)
|
|
270
|
+
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(true);
|
|
271
|
+
expect(activity.hasStreamData(DataPaceMinutesPerMile.type)).toBe(true);
|
|
272
|
+
});
|
|
273
|
+
it('should NOT generate unit streams when generateUnitStreams = false', () => {
|
|
274
|
+
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
275
|
+
// Mock parsing options
|
|
276
|
+
activity.parseOptions = {
|
|
277
|
+
streams: { smooth: {}, fixAbnormal: {} },
|
|
278
|
+
maxActivityDurationDays: 14,
|
|
279
|
+
generateUnitStreams: false,
|
|
280
|
+
};
|
|
281
|
+
// Add a speed stream
|
|
282
|
+
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
283
|
+
ActivityUtilities.generateMissingStreams(activity);
|
|
284
|
+
// Should NOT have generated unit variants
|
|
285
|
+
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
286
|
+
// It might still generate some "derived" streams depending on other flags, but our specific unit loop should be skipped
|
|
287
|
+
// The Pace stream comes from createUnitStreamsFromStreams too, so it should also be missing
|
|
288
|
+
expect(activity.hasStreamData(DataPaceMinutesPerMile.type)).toBe(false);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
describe('generateMissingStreamsAndStatsForActivity', () => {
|
|
292
|
+
it('should generate unit STATS even if unit STREAMS are disabled', () => {
|
|
293
|
+
const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
|
|
294
|
+
activity.parseOptions = {
|
|
295
|
+
streams: { smooth: {}, fixAbnormal: {} },
|
|
296
|
+
maxActivityDurationDays: 14,
|
|
297
|
+
generateUnitStreams: false, // DISABLE streams
|
|
298
|
+
};
|
|
299
|
+
// Add a speed stream [10 m/s, 20 m/s]
|
|
300
|
+
// Max speed = 20 m/s
|
|
301
|
+
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
302
|
+
ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
|
|
303
|
+
// 1. Verify Streams are missing (as requested)
|
|
304
|
+
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
305
|
+
// 1. Verify Streams are missing (as requested)
|
|
306
|
+
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
307
|
+
// 2. Verify Stats are PRESENT (Safety Check)
|
|
308
|
+
// 20 m/s = 72 km/h
|
|
309
|
+
// We check for the stat by its string type if we can't import the constant easily, or iterate.
|
|
310
|
+
// Based on activity.utilities.ts it uses: DataSpeedMaxKilometersPerHour
|
|
311
|
+
const allStats = Array.from(activity.getStats().values());
|
|
312
|
+
const speedMaxKmh = allStats.find(s => s.getType() === DataSpeedMaxKilometersPerHour.type);
|
|
313
|
+
expect(speedMaxKmh).toBeDefined();
|
|
314
|
+
expect(speedMaxKmh === null || speedMaxKmh === void 0 ? void 0 : speedMaxKmh.getValue()).toBe(72);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
225
317
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sports-alliance/sports-lib",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.8",
|
|
4
4
|
"description": "A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gpx",
|