@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.
@@ -14,5 +14,6 @@ export declare class ActivityParsingOptions {
14
14
  };
15
15
  };
16
16
  maxActivityDurationDays: number;
17
+ generateUnitStreams: boolean;
17
18
  constructor(options: ActivityParsingOptions);
18
19
  }
@@ -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): string[];
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
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.swimPaceUnits);
509
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.paceUnits);
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
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedPaceUnits);
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[]): StreamInterface[];
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
- activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
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
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
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
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
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
  });
@@ -14,5 +14,6 @@ export declare class ActivityParsingOptions {
14
14
  };
15
15
  };
16
16
  maxActivityDurationDays: number;
17
+ generateUnitStreams: boolean;
17
18
  constructor(options: ActivityParsingOptions);
18
19
  }
@@ -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): string[];
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
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.swimPaceUnits);
504
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.paceUnits);
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
- unitBasedDataTypes = unitBasedDataTypes.concat(userUnitSettings.gradeAdjustedPaceUnits);
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[]): StreamInterface[];
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
- activity.addStreams(this.createUnitStreamsFromStreams(activity.getAllStreams(), activity.type));
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
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeSpeedBasedStreams(speedStream, activityType));
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
- baseUnitStreams = baseUnitStreams.concat(this.createByActivityTypeAltiDistanceSpeedBasedStreams(gradeAdjustedSpeedStream, activityType));
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.6",
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",