@sports-alliance/sports-lib 6.1.9 → 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 CHANGED
@@ -1,3 +1,3 @@
1
1
  module.exports = {
2
- presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
2
+ presets: [['@babel/preset-env', { targets: { node: 'current' } }]]
3
3
  };
@@ -15,5 +15,5 @@ export declare class ActivityParsingOptions {
15
15
  };
16
16
  maxActivityDurationDays: number;
17
17
  generateUnitStreams: boolean;
18
- constructor(options: ActivityParsingOptions);
18
+ constructor(options: Partial<ActivityParsingOptions>);
19
19
  }
@@ -3,10 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActivityParsingOptions = void 0;
4
4
  class ActivityParsingOptions {
5
5
  constructor(options) {
6
- var _a;
7
- this.streams = options.streams;
8
- this.maxActivityDurationDays = options.maxActivityDurationDays;
9
- this.generateUnitStreams = (_a = options.generateUnitStreams) !== null && _a !== void 0 ? _a : true;
6
+ var _a, _b, _c;
7
+ this.streams = (_a = options.streams) !== null && _a !== void 0 ? _a : {
8
+ smooth: { altitudeSmooth: true, grade: true, gradeSmooth: true },
9
+ fixAbnormal: { speed: false }
10
+ };
11
+ this.maxActivityDurationDays = (_b = options.maxActivityDurationDays) !== null && _b !== void 0 ? _b : 14;
12
+ this.generateUnitStreams = (_c = options.generateUnitStreams) !== null && _c !== void 0 ? _c : true;
10
13
  }
11
14
  }
12
15
  exports.ActivityParsingOptions = ActivityParsingOptions;
@@ -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, { includeDerivedTypes: false });
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(!!(object.total_distance || object.avg_speed)));
632
- if ((0, helpers_1.isNumberOrString)(object.total_distance)) {
633
- stats.push(new data_distance_1.DataDistance(object.total_distance));
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 ((0, helpers_1.isNumberOrString)(object.avg_speed)) {
694
- stats.push(new data_speed_avg_1.DataSpeedAvg(object.avg_speed));
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
- if ((0, helpers_1.isNumberOrString)(object.enhanced_min_speed)) {
707
- stats.push(new data_speed_min_1.DataSpeedMin(object.enhanced_min_speed));
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
- if ((0, helpers_1.isNumberOrString)(object.enhanced_max_speed)) {
710
- stats.push(new data_speed_max_1.DataSpeedMax(object.enhanced_max_speed));
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
- if ((0, helpers_1.isNumberOrString)(object.total_ascent)) {
724
- stats.push(new data_ascent_1.DataAscent(object.total_ascent));
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
- if ((0, helpers_1.isNumberOrString)(object.total_descent)) {
728
- stats.push(new data_descent_1.DataDescent(object.total_descent));
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
- return (0, helpers_1.isNumber)(sample.enhanced_altitude)
66
- ? Math.round(sample.enhanced_altitude * Math.pow(10, constants_1.ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
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
- : (0, helpers_1.isNumber)(sample.altitude)
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 (Number.isFinite(sample.enhanced_speed)) {
114
+ if ((0, helpers_1.isNumber)(sample.enhanced_speed)) {
109
115
  return sample.enhanced_speed;
110
116
  }
111
- if (Number.isFinite(sample.speed)) {
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
- if (!activity.parseOptions || activity.parseOptions.generateUnitStreams) {
295
- activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
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 || data_store_1.DynamicDataLoader.allUnitDerivedDataTypes;
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
- // @todo add distance ?
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) && !activity.hasStreamData(data_stance_time_balance_right_1.DataStanceTimeBalanceRight.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, { includeDerivedTypes: false, includeUnitVariants: true });
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], { includeDerivedTypes: true, includeUnitVariants: false });
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], { includeDerivedTypes: false, includeUnitVariants: false });
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, // DISABLE streams
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 Stats are PRESENT (Safety Check)
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();
@@ -15,5 +15,5 @@ export declare class ActivityParsingOptions {
15
15
  };
16
16
  maxActivityDurationDays: number;
17
17
  generateUnitStreams: boolean;
18
- constructor(options: ActivityParsingOptions);
18
+ constructor(options: Partial<ActivityParsingOptions>);
19
19
  }
@@ -1,9 +1,12 @@
1
1
  export class ActivityParsingOptions {
2
2
  constructor(options) {
3
- var _a;
4
- this.streams = options.streams;
5
- this.maxActivityDurationDays = options.maxActivityDurationDays;
6
- this.generateUnitStreams = (_a = options.generateUnitStreams) !== null && _a !== void 0 ? _a : true;
3
+ var _a, _b, _c;
4
+ this.streams = (_a = options.streams) !== null && _a !== void 0 ? _a : {
5
+ smooth: { altitudeSmooth: true, grade: true, gradeSmooth: true },
6
+ fixAbnormal: { speed: false }
7
+ };
8
+ this.maxActivityDurationDays = (_b = options.maxActivityDurationDays) !== null && _b !== void 0 ? _b : 14;
9
+ this.generateUnitStreams = (_c = options.generateUnitStreams) !== null && _c !== void 0 ? _c : true;
7
10
  }
8
11
  }
9
12
  ActivityParsingOptions.DEFAULT = new ActivityParsingOptions({
@@ -68,7 +68,9 @@ describe('DataStore', () => {
68
68
  temperatureUnits: [],
69
69
  weightUnits: []
70
70
  };
71
- const result = DynamicDataLoader.getUnitBasedDataTypesFromDataTypes([DataSpeed.type], settings, { includeDerivedTypes: false });
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(!!(object.total_distance || object.avg_speed)));
626
- if (isNumberOrString(object.total_distance)) {
627
- stats.push(new DataDistance(object.total_distance));
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 (isNumberOrString(object.avg_speed)) {
688
- stats.push(new DataSpeedAvg(object.avg_speed));
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
- if (isNumberOrString(object.enhanced_min_speed)) {
701
- stats.push(new DataSpeedMin(object.enhanced_min_speed));
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
- if (isNumberOrString(object.enhanced_max_speed)) {
704
- stats.push(new DataSpeedMax(object.enhanced_max_speed));
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
- if (isNumberOrString(object.total_ascent)) {
718
- stats.push(new DataAscent(object.total_ascent));
719
+ const ascent = getStatValue(object, ['total_ascent', 'TotalAscent']);
720
+ if (ascent !== null) {
721
+ stats.push(new DataAscent(ascent));
719
722
  }
720
723
  // Descent
721
- if (isNumberOrString(object.total_descent)) {
722
- stats.push(new DataDescent(object.total_descent));
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
- return isNumber(sample.enhanced_altitude)
63
- ? Math.round(sample.enhanced_altitude * Math.pow(10, ALTITUDE_PRECISION_NUMBER_OF_DECIMAL_PLACES)) /
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
- : isNumber(sample.altitude)
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 (Number.isFinite(sample.enhanced_speed)) {
111
+ if (isNumber(sample.enhanced_speed)) {
106
112
  return sample.enhanced_speed;
107
113
  }
108
- if (Number.isFinite(sample.speed)) {
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
- if (!activity.parseOptions || activity.parseOptions.generateUnitStreams) {
292
- activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
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 || DynamicDataLoader.allUnitDerivedDataTypes;
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
- // @todo add distance ?
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) && !activity.hasStreamData(DataStanceTimeBalanceRight.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, { includeDerivedTypes: false, includeUnitVariants: true });
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], { includeDerivedTypes: true, includeUnitVariants: false });
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], { includeDerivedTypes: false, includeUnitVariants: false });
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, // DISABLE streams
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 Stats are PRESENT (Safety Check)
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.9",
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",