@sports-alliance/sports-lib 6.1.10 → 6.1.11
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/babel.config.js +1 -1
- package/lib/cjs/data/data-store.spec.js +3 -1
- package/lib/cjs/events/adapters/importers/fit/importer.fit.js +27 -23
- package/lib/cjs/events/adapters/importers/fit/importer.fit.mapper.js +21 -9
- package/lib/cjs/events/utilities/activity.utilities.js +13 -7
- package/lib/cjs/events/utilities/activity.utilities.spec.js +18 -11
- package/lib/esm/data/data-store.spec.js +3 -1
- package/lib/esm/events/adapters/importers/fit/importer.fit.js +27 -23
- package/lib/esm/events/adapters/importers/fit/importer.fit.mapper.js +21 -9
- package/lib/esm/events/utilities/activity.utilities.js +13 -7
- package/lib/esm/events/utilities/activity.utilities.spec.js +18 -11
- package/package.json +1 -1
package/babel.config.js
CHANGED
|
@@ -70,7 +70,9 @@ describe('DataStore', () => {
|
|
|
70
70
|
temperatureUnits: [],
|
|
71
71
|
weightUnits: []
|
|
72
72
|
};
|
|
73
|
-
const result = data_store_1.DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([data_speed_1.DataSpeed.type], settings, {
|
|
73
|
+
const result = data_store_1.DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([data_speed_1.DataSpeed.type], settings, {
|
|
74
|
+
includeDerivedTypes: false
|
|
75
|
+
});
|
|
74
76
|
expect(result).toContain(data_speed_1.DataSpeedKilometersPerHour.type);
|
|
75
77
|
expect(result).not.toContain(data_pace_1.DataPaceMinutesPerMile.type);
|
|
76
78
|
});
|
|
@@ -627,10 +627,20 @@ class EventImporterFIT {
|
|
|
627
627
|
// Pause TIME on Object (activity, lap...)
|
|
628
628
|
const pause = elapsedTime > movingTime && movingTime > 0 ? Math.round((elapsedTime - movingTime) * 100) / 100 : 0;
|
|
629
629
|
stats.push(new data_pause_1.DataPause(pause));
|
|
630
|
+
const getStatValue = (obj, keys) => {
|
|
631
|
+
for (const key of keys) {
|
|
632
|
+
if ((0, helpers_1.isNumberOrString)(obj[key])) {
|
|
633
|
+
return obj[key];
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return null;
|
|
637
|
+
};
|
|
638
|
+
const avgSpeed = getStatValue(object, ['enhanced_avg_speed', 'EnhancedAvgSpeed', 'avg_speed', 'AvgSpeed']);
|
|
639
|
+
const totalDistance = getStatValue(object, ['total_distance', 'TotalDistance']);
|
|
630
640
|
// Assign is active lap status
|
|
631
|
-
stats.push(new data_active_lap_1.DataActiveLap(!!(
|
|
632
|
-
if (
|
|
633
|
-
stats.push(new data_distance_1.DataDistance(
|
|
641
|
+
stats.push(new data_active_lap_1.DataActiveLap(!!(totalDistance || avgSpeed)));
|
|
642
|
+
if (totalDistance !== null) {
|
|
643
|
+
stats.push(new data_distance_1.DataDistance(totalDistance));
|
|
634
644
|
}
|
|
635
645
|
else {
|
|
636
646
|
stats.push(new data_distance_1.DataDistance(0));
|
|
@@ -690,24 +700,16 @@ class EventImporterFIT {
|
|
|
690
700
|
stats.push(new data_power_pedal_smoothness_right_1.DataPowerPedalSmoothnessRight(object.avg_right_pedal_smoothness));
|
|
691
701
|
}
|
|
692
702
|
// Speed
|
|
693
|
-
if (
|
|
694
|
-
stats.push(new data_speed_avg_1.DataSpeedAvg(
|
|
695
|
-
}
|
|
696
|
-
if ((0, helpers_1.isNumberOrString)(object.min_speed)) {
|
|
697
|
-
stats.push(new data_speed_min_1.DataSpeedMin(object.min_speed));
|
|
698
|
-
}
|
|
699
|
-
if ((0, helpers_1.isNumberOrString)(object.max_speed)) {
|
|
700
|
-
stats.push(new data_speed_max_1.DataSpeedMax(object.max_speed));
|
|
701
|
-
}
|
|
702
|
-
// Keep latest , enhanced @todo this can create a bug
|
|
703
|
-
if ((0, helpers_1.isNumberOrString)(object.enhanced_avg_speed)) {
|
|
704
|
-
stats.push(new data_speed_avg_1.DataSpeedAvg(object.enhanced_avg_speed));
|
|
703
|
+
if (avgSpeed !== null) {
|
|
704
|
+
stats.push(new data_speed_avg_1.DataSpeedAvg(avgSpeed));
|
|
705
705
|
}
|
|
706
|
-
|
|
707
|
-
|
|
706
|
+
const minSpeed = getStatValue(object, ['enhanced_min_speed', 'EnhancedMinSpeed', 'min_speed', 'MinSpeed']);
|
|
707
|
+
if (minSpeed !== null) {
|
|
708
|
+
stats.push(new data_speed_min_1.DataSpeedMin(minSpeed));
|
|
708
709
|
}
|
|
709
|
-
|
|
710
|
-
|
|
710
|
+
const maxSpeed = getStatValue(object, ['enhanced_max_speed', 'EnhancedMaxSpeed', 'max_speed', 'MaxSpeed']);
|
|
711
|
+
if (maxSpeed !== null) {
|
|
712
|
+
stats.push(new data_speed_max_1.DataSpeedMax(maxSpeed));
|
|
711
713
|
}
|
|
712
714
|
// Temperature
|
|
713
715
|
if ((0, helpers_1.isNumberOrString)(object.avg_temperature)) {
|
|
@@ -720,12 +722,14 @@ class EventImporterFIT {
|
|
|
720
722
|
stats.push(new data_temperature_max_1.DataTemperatureMax(object.max_temperature));
|
|
721
723
|
}
|
|
722
724
|
// Ascent
|
|
723
|
-
|
|
724
|
-
|
|
725
|
+
const ascent = getStatValue(object, ['total_ascent', 'TotalAscent']);
|
|
726
|
+
if (ascent !== null) {
|
|
727
|
+
stats.push(new data_ascent_1.DataAscent(ascent));
|
|
725
728
|
}
|
|
726
729
|
// Descent
|
|
727
|
-
|
|
728
|
-
|
|
730
|
+
const descent = getStatValue(object, ['total_descent', 'TotalDescent']);
|
|
731
|
+
if (descent !== null) {
|
|
732
|
+
stats.push(new data_descent_1.DataDescent(descent));
|
|
729
733
|
}
|
|
730
734
|
// Calories
|
|
731
735
|
if ((0, helpers_1.isNumberOrString)(object.total_calories)) {
|
|
@@ -50,7 +50,7 @@ exports.FITSampleMapper = [
|
|
|
50
50
|
{
|
|
51
51
|
dataType: data_distance_1.DataDistance.type,
|
|
52
52
|
getSampleValue: (sample) => {
|
|
53
|
-
return sample.distance;
|
|
53
|
+
return (0, helpers_1.isNumber)(sample.distance) ? sample.distance : sample.Distance;
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
{
|
|
@@ -62,13 +62,19 @@ exports.FITSampleMapper = [
|
|
|
62
62
|
{
|
|
63
63
|
dataType: data_altitude_1.DataAltitude.type,
|
|
64
64
|
getSampleValue: (sample) => {
|
|
65
|
-
|
|
66
|
-
?
|
|
65
|
+
const altitude = (0, helpers_1.isNumber)(sample.enhanced_altitude)
|
|
66
|
+
? sample.enhanced_altitude
|
|
67
|
+
: (0, helpers_1.isNumber)(sample.EnhancedAltitude)
|
|
68
|
+
? sample.EnhancedAltitude
|
|
69
|
+
: (0, helpers_1.isNumber)(sample.altitude)
|
|
70
|
+
? sample.altitude
|
|
71
|
+
: (0, helpers_1.isNumber)(sample.Altitude)
|
|
72
|
+
? sample.Altitude
|
|
73
|
+
: null;
|
|
74
|
+
return (0, helpers_1.isNumber)(altitude)
|
|
75
|
+
? Math.round(altitude * Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
|
|
67
76
|
Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
|
|
68
|
-
:
|
|
69
|
-
? Math.round(sample.altitude * Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
|
|
70
|
-
Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
|
|
71
|
-
: sample.altitude;
|
|
77
|
+
: altitude;
|
|
72
78
|
}
|
|
73
79
|
},
|
|
74
80
|
{
|
|
@@ -105,12 +111,18 @@ exports.FITSampleMapper = [
|
|
|
105
111
|
{
|
|
106
112
|
dataType: data_speed_1.DataSpeed.type,
|
|
107
113
|
getSampleValue: (sample) => {
|
|
108
|
-
if (
|
|
114
|
+
if ((0, helpers_1.isNumber)(sample.enhanced_speed)) {
|
|
109
115
|
return sample.enhanced_speed;
|
|
110
116
|
}
|
|
111
|
-
if (
|
|
117
|
+
if ((0, helpers_1.isNumber)(sample.EnhancedSpeed)) {
|
|
118
|
+
return sample.EnhancedSpeed;
|
|
119
|
+
}
|
|
120
|
+
if ((0, helpers_1.isNumber)(sample.speed)) {
|
|
112
121
|
return sample.speed;
|
|
113
122
|
}
|
|
123
|
+
if ((0, helpers_1.isNumber)(sample.Speed)) {
|
|
124
|
+
return sample.Speed;
|
|
125
|
+
}
|
|
114
126
|
return null;
|
|
115
127
|
}
|
|
116
128
|
},
|
|
@@ -291,9 +291,12 @@ class ActivityUtilities {
|
|
|
291
291
|
static generateMissingStreams(activity) {
|
|
292
292
|
// Compute missing streams
|
|
293
293
|
this.generateMissingStreamsForActivity(activity);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
// Always include derived base streams (like Pace), but conditionally include unit variants
|
|
295
|
+
const includeUnitVariants = !activity.parseOptions || activity.parseOptions.generateUnitStreams;
|
|
296
|
+
activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type, undefined, {
|
|
297
|
+
includeDerivedTypes: true,
|
|
298
|
+
includeUnitVariants
|
|
299
|
+
}));
|
|
297
300
|
}
|
|
298
301
|
static getSummaryStatsForActivities(activities) {
|
|
299
302
|
const stats = [];
|
|
@@ -680,7 +683,10 @@ class ActivityUtilities {
|
|
|
680
683
|
includeUnitVariants: true
|
|
681
684
|
}) {
|
|
682
685
|
// @todo perhaps check input to be unitStreamTypesStrictly
|
|
683
|
-
const unitStreamTypesToCreate = unitStreamTypes ||
|
|
686
|
+
const unitStreamTypesToCreate = unitStreamTypes || [
|
|
687
|
+
...data_store_1.DynamicDataLoader.allUnitDerivedDataTypes,
|
|
688
|
+
...data_store_1.DynamicDataLoader.speedDerivedDataTypes
|
|
689
|
+
];
|
|
684
690
|
let baseUnitStreams = [];
|
|
685
691
|
const speedStream = streams.find(stream => stream.type === data_speed_1.DataSpeed.type);
|
|
686
692
|
if (speedStream) {
|
|
@@ -707,8 +713,7 @@ class ActivityUtilities {
|
|
|
707
713
|
? baseUnitStreams.concat(verticalSpeedStream)
|
|
708
714
|
: baseUnitStreams;
|
|
709
715
|
}
|
|
710
|
-
|
|
711
|
-
const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
716
|
+
const startWith = baseUnitStreams.filter((baseUnitStream) => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
712
717
|
if (options.includeUnitVariants === false) {
|
|
713
718
|
return startWith;
|
|
714
719
|
}
|
|
@@ -867,7 +872,8 @@ class ActivityUtilities {
|
|
|
867
872
|
activity.addStream(leftPowerStream);
|
|
868
873
|
}
|
|
869
874
|
// If left stance time stream available, then add the right balance stream too
|
|
870
|
-
if (activity.hasStreamData(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type) &&
|
|
875
|
+
if (activity.hasStreamData(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type) &&
|
|
876
|
+
!activity.hasStreamData(data_stance_time_balance_right_1.DataStanceTimeBalanceRight.type)) {
|
|
871
877
|
const rightStanceBalanceTimeStream = activity.createStream(data_stance_time_balance_right_1.DataStanceTimeBalanceRight.type);
|
|
872
878
|
const leftStanceBalanceTimeStream = activity.getStreamData(data_stance_time_balance_left_1.DataStanceTimeBalanceLeft.type);
|
|
873
879
|
const rightStanceBalanceTimeData = leftStanceBalanceTimeStream.map(leftBalance => {
|
|
@@ -238,7 +238,10 @@ describe('Activity Utilities', () => {
|
|
|
238
238
|
});
|
|
239
239
|
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
240
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, {
|
|
241
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, undefined, {
|
|
242
|
+
includeDerivedTypes: false,
|
|
243
|
+
includeUnitVariants: true
|
|
244
|
+
});
|
|
242
245
|
const paceStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
243
246
|
const kmhStream = result.find(s => s.type === data_speed_2.DataSpeedKilometersPerHour.type);
|
|
244
247
|
expect(paceStream).toBeUndefined();
|
|
@@ -247,7 +250,10 @@ describe('Activity Utilities', () => {
|
|
|
247
250
|
it('should exclude unit variants when includeUnitVariants is false', () => {
|
|
248
251
|
const streams = [new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20])];
|
|
249
252
|
// 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], {
|
|
253
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, [data_pace_1.DataPace.type], {
|
|
254
|
+
includeDerivedTypes: true,
|
|
255
|
+
includeUnitVariants: false
|
|
256
|
+
});
|
|
251
257
|
const paceStream = result.find(s => s.type === data_pace_1.DataPace.type);
|
|
252
258
|
const paceUnitStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
253
259
|
expect(paceStream).toBeDefined(); // Derived type should be there
|
|
@@ -255,7 +261,10 @@ describe('Activity Utilities', () => {
|
|
|
255
261
|
});
|
|
256
262
|
it('should exclude both derived types and unit variants', () => {
|
|
257
263
|
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], {
|
|
264
|
+
const result = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams(streams, activity_types_1.ActivityTypes.Running, [data_pace_1.DataPace.type], {
|
|
265
|
+
includeDerivedTypes: false,
|
|
266
|
+
includeUnitVariants: false
|
|
267
|
+
});
|
|
259
268
|
const paceStream = result.find(s => s.type === data_pace_1.DataPace.type);
|
|
260
269
|
const paceUnitStream = result.find(s => s.type === data_pace_1.DataPaceMinutesPerMile.type);
|
|
261
270
|
expect(paceStream).toBeUndefined();
|
|
@@ -278,7 +287,7 @@ describe('Activity Utilities', () => {
|
|
|
278
287
|
activity.parseOptions = {
|
|
279
288
|
streams: { smooth: {}, fixAbnormal: {} },
|
|
280
289
|
maxActivityDurationDays: 14,
|
|
281
|
-
generateUnitStreams: false
|
|
290
|
+
generateUnitStreams: false
|
|
282
291
|
};
|
|
283
292
|
// Add a speed stream
|
|
284
293
|
activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
|
|
@@ -296,20 +305,18 @@ describe('Activity Utilities', () => {
|
|
|
296
305
|
activity.parseOptions = {
|
|
297
306
|
streams: { smooth: {}, fixAbnormal: {} },
|
|
298
307
|
maxActivityDurationDays: 14,
|
|
299
|
-
generateUnitStreams: false
|
|
308
|
+
generateUnitStreams: false // DISABLE streams
|
|
300
309
|
};
|
|
301
310
|
// Add a speed stream [10 m/s, 20 m/s]
|
|
302
311
|
// Max speed = 20 m/s
|
|
303
312
|
activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
|
|
304
313
|
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)
|
|
314
|
+
// 1. Verify Unit Streams are missing (as requested)
|
|
308
315
|
expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(false);
|
|
309
|
-
// 2. Verify
|
|
316
|
+
// 2. Verify Derived Base Streams are PRESENT (The fix)
|
|
317
|
+
expect(activity.hasStreamData(data_pace_1.DataPace.type)).toBe(true);
|
|
318
|
+
// 3. Verify Stats are PRESENT (Safety Check)
|
|
310
319
|
// 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
320
|
const allStats = Array.from(activity.getStats().values());
|
|
314
321
|
const speedMaxKmh = allStats.find(s => s.getType() === data_speed_max_1.DataSpeedMaxKilometersPerHour.type);
|
|
315
322
|
expect(speedMaxKmh).toBeDefined();
|
|
@@ -68,7 +68,9 @@ describe('DataStore', () => {
|
|
|
68
68
|
temperatureUnits: [],
|
|
69
69
|
weightUnits: []
|
|
70
70
|
};
|
|
71
|
-
const result = DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([DataSpeed.type], settings, {
|
|
71
|
+
const result = DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([DataSpeed.type], settings, {
|
|
72
|
+
includeDerivedTypes: false
|
|
73
|
+
});
|
|
72
74
|
expect(result).toContain(DataSpeedKilometersPerHour.type);
|
|
73
75
|
expect(result).not.toContain(DataPaceMinutesPerMile.type);
|
|
74
76
|
});
|
|
@@ -621,10 +621,20 @@ export class EventImporterFIT {
|
|
|
621
621
|
// Pause TIME on Object (activity, lap...)
|
|
622
622
|
const pause = elapsedTime > movingTime && movingTime > 0 ? Math.round((elapsedTime - movingTime) * 100) / 100 : 0;
|
|
623
623
|
stats.push(new DataPause(pause));
|
|
624
|
+
const getStatValue = (obj, keys) => {
|
|
625
|
+
for (const key of keys) {
|
|
626
|
+
if (isNumberOrString(obj[key])) {
|
|
627
|
+
return obj[key];
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return null;
|
|
631
|
+
};
|
|
632
|
+
const avgSpeed = getStatValue(object, ['enhanced_avg_speed', 'EnhancedAvgSpeed', 'avg_speed', 'AvgSpeed']);
|
|
633
|
+
const totalDistance = getStatValue(object, ['total_distance', 'TotalDistance']);
|
|
624
634
|
// Assign is active lap status
|
|
625
|
-
stats.push(new DataActiveLap(!!(
|
|
626
|
-
if (
|
|
627
|
-
stats.push(new DataDistance(
|
|
635
|
+
stats.push(new DataActiveLap(!!(totalDistance || avgSpeed)));
|
|
636
|
+
if (totalDistance !== null) {
|
|
637
|
+
stats.push(new DataDistance(totalDistance));
|
|
628
638
|
}
|
|
629
639
|
else {
|
|
630
640
|
stats.push(new DataDistance(0));
|
|
@@ -684,24 +694,16 @@ export class EventImporterFIT {
|
|
|
684
694
|
stats.push(new DataPowerPedalSmoothnessRight(object.avg_right_pedal_smoothness));
|
|
685
695
|
}
|
|
686
696
|
// Speed
|
|
687
|
-
if (
|
|
688
|
-
stats.push(new DataSpeedAvg(
|
|
689
|
-
}
|
|
690
|
-
if (isNumberOrString(object.min_speed)) {
|
|
691
|
-
stats.push(new DataSpeedMin(object.min_speed));
|
|
692
|
-
}
|
|
693
|
-
if (isNumberOrString(object.max_speed)) {
|
|
694
|
-
stats.push(new DataSpeedMax(object.max_speed));
|
|
695
|
-
}
|
|
696
|
-
// Keep latest , enhanced @todo this can create a bug
|
|
697
|
-
if (isNumberOrString(object.enhanced_avg_speed)) {
|
|
698
|
-
stats.push(new DataSpeedAvg(object.enhanced_avg_speed));
|
|
697
|
+
if (avgSpeed !== null) {
|
|
698
|
+
stats.push(new DataSpeedAvg(avgSpeed));
|
|
699
699
|
}
|
|
700
|
-
|
|
701
|
-
|
|
700
|
+
const minSpeed = getStatValue(object, ['enhanced_min_speed', 'EnhancedMinSpeed', 'min_speed', 'MinSpeed']);
|
|
701
|
+
if (minSpeed !== null) {
|
|
702
|
+
stats.push(new DataSpeedMin(minSpeed));
|
|
702
703
|
}
|
|
703
|
-
|
|
704
|
-
|
|
704
|
+
const maxSpeed = getStatValue(object, ['enhanced_max_speed', 'EnhancedMaxSpeed', 'max_speed', 'MaxSpeed']);
|
|
705
|
+
if (maxSpeed !== null) {
|
|
706
|
+
stats.push(new DataSpeedMax(maxSpeed));
|
|
705
707
|
}
|
|
706
708
|
// Temperature
|
|
707
709
|
if (isNumberOrString(object.avg_temperature)) {
|
|
@@ -714,12 +716,14 @@ export class EventImporterFIT {
|
|
|
714
716
|
stats.push(new DataTemperatureMax(object.max_temperature));
|
|
715
717
|
}
|
|
716
718
|
// Ascent
|
|
717
|
-
|
|
718
|
-
|
|
719
|
+
const ascent = getStatValue(object, ['total_ascent', 'TotalAscent']);
|
|
720
|
+
if (ascent !== null) {
|
|
721
|
+
stats.push(new DataAscent(ascent));
|
|
719
722
|
}
|
|
720
723
|
// Descent
|
|
721
|
-
|
|
722
|
-
|
|
724
|
+
const descent = getStatValue(object, ['total_descent', 'TotalDescent']);
|
|
725
|
+
if (descent !== null) {
|
|
726
|
+
stats.push(new DataDescent(descent));
|
|
723
727
|
}
|
|
724
728
|
// Calories
|
|
725
729
|
if (isNumberOrString(object.total_calories)) {
|
|
@@ -47,7 +47,7 @@ export const FITSampleMapper = [
|
|
|
47
47
|
{
|
|
48
48
|
dataType: DataDistance.type,
|
|
49
49
|
getSampleValue: (sample) => {
|
|
50
|
-
return sample.distance;
|
|
50
|
+
return isNumber(sample.distance) ? sample.distance : sample.Distance;
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
{
|
|
@@ -59,13 +59,19 @@ export const FITSampleMapper = [
|
|
|
59
59
|
{
|
|
60
60
|
dataType: DataAltitude.type,
|
|
61
61
|
getSampleValue: (sample) => {
|
|
62
|
-
|
|
63
|
-
?
|
|
62
|
+
const altitude = isNumber(sample.enhanced_altitude)
|
|
63
|
+
? sample.enhanced_altitude
|
|
64
|
+
: isNumber(sample.EnhancedAltitude)
|
|
65
|
+
? sample.EnhancedAltitude
|
|
66
|
+
: isNumber(sample.altitude)
|
|
67
|
+
? sample.altitude
|
|
68
|
+
: isNumber(sample.Altitude)
|
|
69
|
+
? sample.Altitude
|
|
70
|
+
: null;
|
|
71
|
+
return isNumber(altitude)
|
|
72
|
+
? Math.round(altitude * Math.pow(10, ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
|
|
64
73
|
Math.pow(10, ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
|
|
65
|
-
:
|
|
66
|
-
? Math.round(sample.altitude * Math.pow(10, ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
|
|
67
|
-
Math.pow(10, ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)
|
|
68
|
-
: sample.altitude;
|
|
74
|
+
: altitude;
|
|
69
75
|
}
|
|
70
76
|
},
|
|
71
77
|
{
|
|
@@ -102,12 +108,18 @@ export const FITSampleMapper = [
|
|
|
102
108
|
{
|
|
103
109
|
dataType: DataSpeed.type,
|
|
104
110
|
getSampleValue: (sample) => {
|
|
105
|
-
if (
|
|
111
|
+
if (isNumber(sample.enhanced_speed)) {
|
|
106
112
|
return sample.enhanced_speed;
|
|
107
113
|
}
|
|
108
|
-
if (
|
|
114
|
+
if (isNumber(sample.EnhancedSpeed)) {
|
|
115
|
+
return sample.EnhancedSpeed;
|
|
116
|
+
}
|
|
117
|
+
if (isNumber(sample.speed)) {
|
|
109
118
|
return sample.speed;
|
|
110
119
|
}
|
|
120
|
+
if (isNumber(sample.Speed)) {
|
|
121
|
+
return sample.Speed;
|
|
122
|
+
}
|
|
111
123
|
return null;
|
|
112
124
|
}
|
|
113
125
|
},
|
|
@@ -288,9 +288,12 @@ export class ActivityUtilities {
|
|
|
288
288
|
static generateMissingStreams(activity) {
|
|
289
289
|
// Compute missing streams
|
|
290
290
|
this.generateMissingStreamsForActivity(activity);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
// Always include derived base streams (like Pace), but conditionally include unit variants
|
|
292
|
+
const includeUnitVariants = !activity.parseOptions || activity.parseOptions.generateUnitStreams;
|
|
293
|
+
activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type, undefined, {
|
|
294
|
+
includeDerivedTypes: true,
|
|
295
|
+
includeUnitVariants
|
|
296
|
+
}));
|
|
294
297
|
}
|
|
295
298
|
static getSummaryStatsForActivities(activities) {
|
|
296
299
|
const stats = [];
|
|
@@ -677,7 +680,10 @@ export class ActivityUtilities {
|
|
|
677
680
|
includeUnitVariants: true
|
|
678
681
|
}) {
|
|
679
682
|
// @todo perhaps check input to be unitStreamTypesStrictly
|
|
680
|
-
const unitStreamTypesToCreate = unitStreamTypes ||
|
|
683
|
+
const unitStreamTypesToCreate = unitStreamTypes || [
|
|
684
|
+
...DynamicDataLoader.allUnitDerivedDataTypes,
|
|
685
|
+
...DynamicDataLoader.speedDerivedDataTypes
|
|
686
|
+
];
|
|
681
687
|
let baseUnitStreams = [];
|
|
682
688
|
const speedStream = streams.find(stream => stream.type === DataSpeed.type);
|
|
683
689
|
if (speedStream) {
|
|
@@ -704,8 +710,7 @@ export class ActivityUtilities {
|
|
|
704
710
|
? baseUnitStreams.concat(verticalSpeedStream)
|
|
705
711
|
: baseUnitStreams;
|
|
706
712
|
}
|
|
707
|
-
|
|
708
|
-
const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
713
|
+
const startWith = baseUnitStreams.filter((baseUnitStream) => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
|
|
709
714
|
if (options.includeUnitVariants === false) {
|
|
710
715
|
return startWith;
|
|
711
716
|
}
|
|
@@ -864,7 +869,8 @@ export class ActivityUtilities {
|
|
|
864
869
|
activity.addStream(leftPowerStream);
|
|
865
870
|
}
|
|
866
871
|
// If left stance time stream available, then add the right balance stream too
|
|
867
|
-
if (activity.hasStreamData(DataStanceTimeBalanceLeft.type) &&
|
|
872
|
+
if (activity.hasStreamData(DataStanceTimeBalanceLeft.type) &&
|
|
873
|
+
!activity.hasStreamData(DataStanceTimeBalanceRight.type)) {
|
|
868
874
|
const rightStanceBalanceTimeStream = activity.createStream(DataStanceTimeBalanceRight.type);
|
|
869
875
|
const leftStanceBalanceTimeStream = activity.getStreamData(DataStanceTimeBalanceLeft.type);
|
|
870
876
|
const rightStanceBalanceTimeData = leftStanceBalanceTimeStream.map(leftBalance => {
|
|
@@ -236,7 +236,10 @@ describe('Activity Utilities', () => {
|
|
|
236
236
|
});
|
|
237
237
|
it('should exclude derived types when includeDerivedTypes is false', () => {
|
|
238
238
|
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
239
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, undefined, {
|
|
239
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, undefined, {
|
|
240
|
+
includeDerivedTypes: false,
|
|
241
|
+
includeUnitVariants: true
|
|
242
|
+
});
|
|
240
243
|
const paceStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
241
244
|
const kmhStream = result.find(s => s.type === DataSpeedKilometersPerHour.type);
|
|
242
245
|
expect(paceStream).toBeUndefined();
|
|
@@ -245,7 +248,10 @@ describe('Activity Utilities', () => {
|
|
|
245
248
|
it('should exclude unit variants when includeUnitVariants is false', () => {
|
|
246
249
|
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
247
250
|
// 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], {
|
|
251
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], {
|
|
252
|
+
includeDerivedTypes: true,
|
|
253
|
+
includeUnitVariants: false
|
|
254
|
+
});
|
|
249
255
|
const paceStream = result.find(s => s.type === DataPace.type);
|
|
250
256
|
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
251
257
|
expect(paceStream).toBeDefined(); // Derived type should be there
|
|
@@ -253,7 +259,10 @@ describe('Activity Utilities', () => {
|
|
|
253
259
|
});
|
|
254
260
|
it('should exclude both derived types and unit variants', () => {
|
|
255
261
|
const streams = [new Stream(DataSpeed.type, [10, 20])];
|
|
256
|
-
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], {
|
|
262
|
+
const result = ActivityUtilities.createUnitStreamsFromStreams(streams, ActivityTypes.Running, [DataPace.type], {
|
|
263
|
+
includeDerivedTypes: false,
|
|
264
|
+
includeUnitVariants: false
|
|
265
|
+
});
|
|
257
266
|
const paceStream = result.find(s => s.type === DataPace.type);
|
|
258
267
|
const paceUnitStream = result.find(s => s.type === DataPaceMinutesPerMile.type);
|
|
259
268
|
expect(paceStream).toBeUndefined();
|
|
@@ -276,7 +285,7 @@ describe('Activity Utilities', () => {
|
|
|
276
285
|
activity.parseOptions = {
|
|
277
286
|
streams: { smooth: {}, fixAbnormal: {} },
|
|
278
287
|
maxActivityDurationDays: 14,
|
|
279
|
-
generateUnitStreams: false
|
|
288
|
+
generateUnitStreams: false
|
|
280
289
|
};
|
|
281
290
|
// Add a speed stream
|
|
282
291
|
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
@@ -294,20 +303,18 @@ describe('Activity Utilities', () => {
|
|
|
294
303
|
activity.parseOptions = {
|
|
295
304
|
streams: { smooth: {}, fixAbnormal: {} },
|
|
296
305
|
maxActivityDurationDays: 14,
|
|
297
|
-
generateUnitStreams: false
|
|
306
|
+
generateUnitStreams: false // DISABLE streams
|
|
298
307
|
};
|
|
299
308
|
// Add a speed stream [10 m/s, 20 m/s]
|
|
300
309
|
// Max speed = 20 m/s
|
|
301
310
|
activity.addStream(new Stream(DataSpeed.type, [10, 20]));
|
|
302
311
|
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)
|
|
312
|
+
// 1. Verify Unit Streams are missing (as requested)
|
|
306
313
|
expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
|
|
307
|
-
// 2. Verify
|
|
314
|
+
// 2. Verify Derived Base Streams are PRESENT (The fix)
|
|
315
|
+
expect(activity.hasStreamData(DataPace.type)).toBe(true);
|
|
316
|
+
// 3. Verify Stats are PRESENT (Safety Check)
|
|
308
317
|
// 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
318
|
const allStats = Array.from(activity.getStats().values());
|
|
312
319
|
const speedMaxKmh = allStats.find(s => s.getType() === DataSpeedMaxKilometersPerHour.type);
|
|
313
320
|
expect(speedMaxKmh).toBeDefined();
|
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.11",
|
|
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",
|