@sports-alliance/sports-lib 6.1.11 → 6.1.12

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/jest.config.js CHANGED
@@ -18,5 +18,6 @@ module.exports = {
18
18
  'ts-jest': {
19
19
  babelConfig: true
20
20
  }
21
- }
21
+ },
22
+ setupFilesAfterEnv: ['<rootDir>/jest.setup.ts']
22
23
  };
package/jest.setup.ts ADDED
@@ -0,0 +1,9 @@
1
+
2
+ import { ActivityParsingOptions } from './src/activities/activity-parsing-options';
3
+
4
+ // Disable unit stream generation by default for tests to improve performance
5
+ // This creates separate arrays for km/h, mph, etc. which are expensive and rarely needed in tests
6
+ // unless specifically testing the charting logic or unit conversion.
7
+ ActivityParsingOptions.DEFAULT.generateUnitStreams = false;
8
+
9
+ console.log('Jest Setup: Disabled ActivityParsingOptions.generateUnitStreams for faster tests.');
@@ -48,6 +48,7 @@ class ActivityTypesHelper {
48
48
  case ActivityTypeGroups.TrailRunning:
49
49
  return [data_pace_avg_1.DataPaceAvg.type, data_grade_adjusted_pace_avg_1.DataGradeAdjustedPaceAvg.type, data_speed_avg_1.DataSpeedAvg.type, data_grade_adjusted_speed_avg_1.DataGradeAdjustedSpeedAvg.type];
50
50
  case ActivityTypeGroups.WaterSports:
51
+ case ActivityTypeGroups.Swimming:
51
52
  return [data_speed_avg_1.DataSpeedAvg.type, data_swim_pace_avg_1.DataSwimPaceAvg.type];
52
53
  default:
53
54
  return [data_speed_avg_1.DataSpeedAvg.type];
@@ -60,6 +61,7 @@ class ActivityTypesHelper {
60
61
  case ActivityTypeGroups.TrailRunning:
61
62
  return [data_pace_1.DataPace.type, data_speed_1.DataSpeed.type];
62
63
  case ActivityTypeGroups.WaterSports:
64
+ case ActivityTypeGroups.Swimming:
63
65
  return [data_speed_1.DataSpeed.type, data_swim_pace_1.DataSwimPace.type];
64
66
  default:
65
67
  return [data_speed_1.DataSpeed.type];
@@ -688,32 +688,33 @@ class ActivityUtilities {
688
688
  ...data_store_1.DynamicDataLoader.speedDerivedDataTypes
689
689
  ];
690
690
  let baseUnitStreams = [];
691
- const speedStream = streams.find(stream => stream.type === data_speed_1.DataSpeed.type);
692
- if (speedStream) {
693
- if (options.includeDerivedTypes) {
694
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
691
+ // Iterate over all possible base types that can have unit variants
692
+ // This allows us to dynamically include ALL base streams (like Distance, Power, etc.) that need unit conversion
693
+ Object.keys(data_store_1.DynamicDataLoader.dataTypeUnitGroups).forEach(baseDataType => {
694
+ const stream = streams.find(s => s.type === baseDataType);
695
+ if (!stream) {
696
+ return;
695
697
  }
696
- else {
697
- baseUnitStreams.push(speedStream);
698
+ // Special handling for derived types (Pace from Speed, etc.)
699
+ if (baseDataType === data_speed_1.DataSpeed.type && options.includeDerivedTypes) {
700
+ baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(stream, activityType));
701
+ return;
698
702
  }
699
- }
700
- const gradeAdjustedSpeedStream = streams.find(stream => stream.type === data_grade_adjusted_speed_1.DataGradeAdjustedSpeed.type);
701
- if (gradeAdjustedSpeedStream) {
702
- if (options.includeDerivedTypes) {
703
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
703
+ if (baseDataType === data_grade_adjusted_speed_1.DataGradeAdjustedSpeed.type && options.includeDerivedTypes) {
704
+ baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(stream, activityType));
705
+ return;
704
706
  }
705
- else {
706
- baseUnitStreams.push(gradeAdjustedSpeedStream);
707
+ if (baseDataType === data_vertical_speed_1.DataVerticalSpeed.type) {
708
+ // Vertical speed handling
709
+ if (activity_types_1.ActivityTypesHelper.verticalSpeedDerivedDataTypesToUseForActivityType(activityType).length) {
710
+ baseUnitStreams.push(stream);
711
+ }
712
+ return;
707
713
  }
708
- }
709
- const verticalSpeedStream = streams.find(stream => stream.type === data_vertical_speed_1.DataVerticalSpeed.type);
710
- if (verticalSpeedStream) {
711
- // For vertical speed (yet) we dont need a seperate function so just add the base that is the "derived" one
712
- baseUnitStreams = activity_types_1.ActivityTypesHelper.verticalSpeedDerivedDataTypesToUseForActivityType(activityType).length
713
- ? baseUnitStreams.concat(verticalSpeedStream)
714
- : baseUnitStreams;
715
- }
716
- const startWith = baseUnitStreams.filter((baseUnitStream) => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
714
+ // For everything else (like Distance), just add the base stream so it can be used for unit generation
715
+ baseUnitStreams.push(stream);
716
+ });
717
+ const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
717
718
  if (options.includeUnitVariants === false) {
718
719
  return startWith;
719
720
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const event_1 = require("../event");
4
4
  const data_speed_max_1 = require("../../data/data.speed-max");
5
5
  const activity_1 = require("../../activities/activity");
6
+ const activity_parsing_options_1 = require("../../activities/activity-parsing-options");
6
7
  const data_heart_rate_1 = require("../../data/data.heart-rate");
7
8
  const data_altitude_1 = require("../../data/data.altitude");
8
9
  const data_distance_1 = require("../../data/data.distance");
@@ -20,6 +21,7 @@ const file_type_enum_1 = require("../adapters/file-type.enum");
20
21
  const importer_json_1 = require("../adapters/importers/json/importer.json");
21
22
  const data_pace_1 = require("../../data/data.pace");
22
23
  const data_speed_2 = require("../../data/data.speed");
24
+ const data_swim_pace_1 = require("../../data/data.swim-pace");
23
25
  describe('Activity Utilities', () => {
24
26
  let event;
25
27
  beforeEach(() => {
@@ -272,8 +274,8 @@ describe('Activity Utilities', () => {
272
274
  });
273
275
  });
274
276
  describe('generateMissingStreams', () => {
275
- it('should generate unit streams by default (generateUnitStreams = true)', () => {
276
- const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'));
277
+ it('should generate unit streams when generateUnitStreams = true', () => {
278
+ const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'), new activity_parsing_options_1.ActivityParsingOptions({ generateUnitStreams: true }));
277
279
  // Add a speed stream
278
280
  activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [10, 20]));
279
281
  activity_utilities_1.ActivityUtilities.generateMissingStreams(activity);
@@ -322,5 +324,52 @@ describe('Activity Utilities', () => {
322
324
  expect(speedMaxKmh).toBeDefined();
323
325
  expect(speedMaxKmh === null || speedMaxKmh === void 0 ? void 0 : speedMaxKmh.getValue()).toBe(72);
324
326
  });
327
+ it('should generate DataSwimPace when generateUnitStreams = false for swimming', () => {
328
+ const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Swimming, new creator_1.Creator('test'));
329
+ activity.parseOptions = {
330
+ streams: { smooth: {}, fixAbnormal: {} },
331
+ maxActivityDurationDays: 14,
332
+ generateUnitStreams: false
333
+ };
334
+ activity.addStream(new stream_1.Stream(data_speed_1.DataSpeed.type, [1, 2])); // m/s
335
+ activity_utilities_1.ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
336
+ // Verify Unit Streams missing
337
+ expect(activity.hasStreamData(data_speed_2.DataSpeedKilometersPerHour.type)).toBe(false);
338
+ // Verify Derived Base Stream (Swim Pace) IS present
339
+ expect(activity.hasStreamData(data_swim_pace_1.DataSwimPace.type)).toBe(true);
340
+ });
341
+ it('should generate DataDistanceMiles when generateUnitStreams = true', () => {
342
+ const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'), new activity_parsing_options_1.ActivityParsingOptions({ generateUnitStreams: true }));
343
+ activity.addStream(new stream_1.Stream(data_distance_1.DataDistance.type, [1000, 2000]));
344
+ activity_utilities_1.ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
345
+ // Should generate miles
346
+ expect(activity.hasStreamData(data_distance_1.DataDistanceMiles.type)).toBe(true);
347
+ });
348
+ it('should NOT generate DataDistanceMiles when generateUnitStreams = false', () => {
349
+ const activity = new activity_1.Activity(new Date(), new Date(), activity_types_1.ActivityTypes.Running, new creator_1.Creator('test'));
350
+ activity.parseOptions = {
351
+ streams: { smooth: {}, fixAbnormal: {} },
352
+ maxActivityDurationDays: 14,
353
+ generateUnitStreams: false
354
+ };
355
+ activity.addStream(new stream_1.Stream(data_distance_1.DataDistance.type, [1000, 2000]));
356
+ activity_utilities_1.ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
357
+ // Should NOT generate miles
358
+ expect(activity.hasStreamData(data_distance_1.DataDistanceMiles.type)).toBe(false);
359
+ // But base Distance should still be there (it was added manually)
360
+ expect(activity.hasStreamData(data_distance_1.DataDistance.type)).toBe(true);
361
+ });
362
+ it('should generate unit streams for Mountain Biking using DataSpeed', () => {
363
+ const speedData = [10, 20, 30]; // m/s
364
+ const speedStream = new stream_1.Stream(data_speed_1.DataSpeed.type, speedData);
365
+ // Mountain Biking (defaults to Cycling group)
366
+ const unitStreams = activity_utilities_1.ActivityUtilities.createUnitStreamsFromStreams([speedStream], activity_types_1.ActivityTypes.MountainBiking, undefined, // Auto-detect all known unit types
367
+ { includeDerivedTypes: true, includeUnitVariants: true });
368
+ const kmhStream = unitStreams.find(s => s.type === 'Speed in kilometers per hour');
369
+ expect(kmhStream).toBeDefined();
370
+ if (kmhStream) {
371
+ expect(kmhStream.getData()[0]).toBeCloseTo(36, 1); // 10 m/s = 36 km/h
372
+ }
373
+ });
325
374
  });
326
375
  });
@@ -45,6 +45,7 @@ export class ActivityTypesHelper {
45
45
  case ActivityTypeGroups.TrailRunning:
46
46
  return [DataPaceAvg.type, DataGradeAdjustedPaceAvg.type, DataSpeedAvg.type, DataGradeAdjustedSpeedAvg.type];
47
47
  case ActivityTypeGroups.WaterSports:
48
+ case ActivityTypeGroups.Swimming:
48
49
  return [DataSpeedAvg.type, DataSwimPaceAvg.type];
49
50
  default:
50
51
  return [DataSpeedAvg.type];
@@ -57,6 +58,7 @@ export class ActivityTypesHelper {
57
58
  case ActivityTypeGroups.TrailRunning:
58
59
  return [DataPace.type, DataSpeed.type];
59
60
  case ActivityTypeGroups.WaterSports:
61
+ case ActivityTypeGroups.Swimming:
60
62
  return [DataSpeed.type, DataSwimPace.type];
61
63
  default:
62
64
  return [DataSpeed.type];
@@ -685,32 +685,33 @@ export class ActivityUtilities {
685
685
  ...DynamicDataLoader.speedDerivedDataTypes
686
686
  ];
687
687
  let baseUnitStreams = [];
688
- const speedStream = streams.find(stream => stream.type === DataSpeed.type);
689
- if (speedStream) {
690
- if (options.includeDerivedTypes) {
691
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
688
+ // Iterate over all possible base types that can have unit variants
689
+ // This allows us to dynamically include ALL base streams (like Distance, Power, etc.) that need unit conversion
690
+ Object.keys(DynamicDataLoader.dataTypeUnitGroups).forEach(baseDataType => {
691
+ const stream = streams.find(s => s.type === baseDataType);
692
+ if (!stream) {
693
+ return;
692
694
  }
693
- else {
694
- baseUnitStreams.push(speedStream);
695
+ // Special handling for derived types (Pace from Speed, etc.)
696
+ if (baseDataType === DataSpeed.type && options.includeDerivedTypes) {
697
+ baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(stream, activityType));
698
+ return;
695
699
  }
696
- }
697
- const gradeAdjustedSpeedStream = streams.find(stream => stream.type === DataGradeAdjustedSpeed.type);
698
- if (gradeAdjustedSpeedStream) {
699
- if (options.includeDerivedTypes) {
700
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
700
+ if (baseDataType === DataGradeAdjustedSpeed.type && options.includeDerivedTypes) {
701
+ baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(stream, activityType));
702
+ return;
701
703
  }
702
- else {
703
- baseUnitStreams.push(gradeAdjustedSpeedStream);
704
+ if (baseDataType === DataVerticalSpeed.type) {
705
+ // Vertical speed handling
706
+ if (ActivityTypesHelper.verticalSpeedDerivedDataTypesToUseForActivityType(activityType).length) {
707
+ baseUnitStreams.push(stream);
708
+ }
709
+ return;
704
710
  }
705
- }
706
- const verticalSpeedStream = streams.find(stream => stream.type === DataVerticalSpeed.type);
707
- if (verticalSpeedStream) {
708
- // For vertical speed (yet) we dont need a seperate function so just add the base that is the "derived" one
709
- baseUnitStreams = ActivityTypesHelper.verticalSpeedDerivedDataTypesToUseForActivityType(activityType).length
710
- ? baseUnitStreams.concat(verticalSpeedStream)
711
- : baseUnitStreams;
712
- }
713
- const startWith = baseUnitStreams.filter((baseUnitStream) => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
711
+ // For everything else (like Distance), just add the base stream so it can be used for unit generation
712
+ baseUnitStreams.push(stream);
713
+ });
714
+ const startWith = baseUnitStreams.filter(baseUnitStream => unitStreamTypesToCreate.indexOf(baseUnitStream.type) !== -1 && streams.indexOf(baseUnitStream) === -1);
714
715
  if (options.includeUnitVariants === false) {
715
716
  return startWith;
716
717
  }
@@ -1,9 +1,10 @@
1
1
  import { Event } from '../event';
2
2
  import { DataSpeedMaxKilometersPerHour } from '../../data/data.speed-max';
3
3
  import { Activity } from '../../activities/activity';
4
+ import { ActivityParsingOptions } from '../../activities/activity-parsing-options';
4
5
  import { DataHeartRate } from '../../data/data.heart-rate';
5
6
  import { DataAltitude } from '../../data/data.altitude';
6
- import { DataDistance } from '../../data/data.distance';
7
+ import { DataDistance, DataDistanceMiles } from '../../data/data.distance';
7
8
  import { DataDuration } from '../../data/data.duration';
8
9
  import { Creator } from '../../creators/creator';
9
10
  import { ActivityTypes } from '../../activities/activity.types';
@@ -18,6 +19,7 @@ import { FileType } from '../adapters/file-type.enum';
18
19
  import { EventImporterJSON } from '../adapters/importers/json/importer.json';
19
20
  import { DataPace, DataPaceMinutesPerMile } from '../../data/data.pace';
20
21
  import { DataSpeedKilometersPerHour } from '../../data/data.speed';
22
+ import { DataSwimPace } from '../../data/data.swim-pace';
21
23
  describe('Activity Utilities', () => {
22
24
  let event;
23
25
  beforeEach(() => {
@@ -270,8 +272,8 @@ describe('Activity Utilities', () => {
270
272
  });
271
273
  });
272
274
  describe('generateMissingStreams', () => {
273
- it('should generate unit streams by default (generateUnitStreams = true)', () => {
274
- const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
275
+ it('should generate unit streams when generateUnitStreams = true', () => {
276
+ const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'), new ActivityParsingOptions({ generateUnitStreams: true }));
275
277
  // Add a speed stream
276
278
  activity.addStream(new Stream(DataSpeed.type, [10, 20]));
277
279
  ActivityUtilities.generateMissingStreams(activity);
@@ -320,5 +322,52 @@ describe('Activity Utilities', () => {
320
322
  expect(speedMaxKmh).toBeDefined();
321
323
  expect(speedMaxKmh === null || speedMaxKmh === void 0 ? void 0 : speedMaxKmh.getValue()).toBe(72);
322
324
  });
325
+ it('should generate DataSwimPace when generateUnitStreams = false for swimming', () => {
326
+ const activity = new Activity(new Date(), new Date(), ActivityTypes.Swimming, new Creator('test'));
327
+ activity.parseOptions = {
328
+ streams: { smooth: {}, fixAbnormal: {} },
329
+ maxActivityDurationDays: 14,
330
+ generateUnitStreams: false
331
+ };
332
+ activity.addStream(new Stream(DataSpeed.type, [1, 2])); // m/s
333
+ ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
334
+ // Verify Unit Streams missing
335
+ expect(activity.hasStreamData(DataSpeedKilometersPerHour.type)).toBe(false);
336
+ // Verify Derived Base Stream (Swim Pace) IS present
337
+ expect(activity.hasStreamData(DataSwimPace.type)).toBe(true);
338
+ });
339
+ it('should generate DataDistanceMiles when generateUnitStreams = true', () => {
340
+ const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'), new ActivityParsingOptions({ generateUnitStreams: true }));
341
+ activity.addStream(new Stream(DataDistance.type, [1000, 2000]));
342
+ ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
343
+ // Should generate miles
344
+ expect(activity.hasStreamData(DataDistanceMiles.type)).toBe(true);
345
+ });
346
+ it('should NOT generate DataDistanceMiles when generateUnitStreams = false', () => {
347
+ const activity = new Activity(new Date(), new Date(), ActivityTypes.Running, new Creator('test'));
348
+ activity.parseOptions = {
349
+ streams: { smooth: {}, fixAbnormal: {} },
350
+ maxActivityDurationDays: 14,
351
+ generateUnitStreams: false
352
+ };
353
+ activity.addStream(new Stream(DataDistance.type, [1000, 2000]));
354
+ ActivityUtilities.generateMissingStreamsAndStatsForActivity(activity);
355
+ // Should NOT generate miles
356
+ expect(activity.hasStreamData(DataDistanceMiles.type)).toBe(false);
357
+ // But base Distance should still be there (it was added manually)
358
+ expect(activity.hasStreamData(DataDistance.type)).toBe(true);
359
+ });
360
+ it('should generate unit streams for Mountain Biking using DataSpeed', () => {
361
+ const speedData = [10, 20, 30]; // m/s
362
+ const speedStream = new Stream(DataSpeed.type, speedData);
363
+ // Mountain Biking (defaults to Cycling group)
364
+ const unitStreams = ActivityUtilities.createUnitStreamsFromStreams([speedStream], ActivityTypes.MountainBiking, undefined, // Auto-detect all known unit types
365
+ { includeDerivedTypes: true, includeUnitVariants: true });
366
+ const kmhStream = unitStreams.find(s => s.type === 'Speed in kilometers per hour');
367
+ expect(kmhStream).toBeDefined();
368
+ if (kmhStream) {
369
+ expect(kmhStream.getData()[0]).toBeCloseTo(36, 1); // 10 m/s = 36 km/h
370
+ }
371
+ });
323
372
  });
324
373
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sports-alliance/sports-lib",
3
- "version": "6.1.11",
3
+ "version": "6.1.12",
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",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "fast-xml-parser": "^5.3.3",
57
57
  "fit-file-parser": "^2.1.0",
58
- "geolib": "^3.3.1",
58
+ "geolib": "^3.3.4",
59
59
  "gpx-builder": "^3.7.8",
60
60
  "kalmanjs": "^1.1.0",
61
61
  "lowpassf": "^0.5.0",