@sports-alliance/sports-lib 6.1.0 → 6.1.3
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 +3 -2
- package/lib/cjs/activities/activity.d.ts +1 -0
- package/lib/cjs/activities/activity.interface.d.ts +5 -0
- package/lib/cjs/activities/activity.js +7 -0
- package/lib/cjs/activities/activity.types.d.ts +1 -0
- package/lib/cjs/activities/activity.types.js +1 -0
- package/lib/cjs/data/data.store.export.spec.js +2 -2
- package/lib/cjs/events/adapters/importers/fit/importer.fit.garmin.profile.data.d.ts +12 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.garmin.profile.data.js +868 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.d.ts +22 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.js +110 -0
- package/lib/cjs/events/adapters/importers/fit/importer.fit.js +26 -10
- package/lib/cjs/events/adapters/importers/fit/importer.fit.spec.js +1 -1
- package/lib/cjs/index.d.ts +114 -0
- package/lib/cjs/index.js +124 -0
- package/lib/cjs/specs/activity-duration-stream.integration.spec.d.ts +1 -0
- package/lib/cjs/specs/activity-duration-stream.integration.spec.js +59 -0
- package/lib/esm/activities/activity.d.ts +1 -0
- package/lib/esm/activities/activity.interface.d.ts +5 -0
- package/lib/esm/activities/activity.js +7 -0
- package/lib/esm/activities/activity.types.d.ts +1 -0
- package/lib/esm/activities/activity.types.js +1 -0
- package/lib/esm/data/data.store.export.spec.js +2 -2
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.data.d.ts +12 -0
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.data.js +865 -0
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.d.ts +22 -0
- package/lib/esm/events/adapters/importers/fit/importer.fit.garmin.profile.mapper.js +106 -0
- package/lib/esm/events/adapters/importers/fit/importer.fit.js +26 -10
- package/lib/esm/events/adapters/importers/fit/importer.fit.spec.js +1 -1
- package/lib/esm/index.d.ts +114 -0
- package/lib/esm/index.js +114 -0
- package/lib/esm/specs/activity-duration-stream.integration.spec.d.ts +1 -0
- package/lib/esm/specs/activity-duration-stream.integration.spec.js +57 -0
- package/package.json +2 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare class GarminProfileMapper {
|
|
2
|
+
/**
|
|
3
|
+
* Translates a Garmin Product ID to a readable device name
|
|
4
|
+
*/
|
|
5
|
+
static getDeviceName(productId: number | string): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Translates a Manufacturer ID to a readable name
|
|
8
|
+
*/
|
|
9
|
+
static getManufacturerName(manufacturerId: number | string): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Translates a Sport ID to a readable name
|
|
12
|
+
*/
|
|
13
|
+
static getSportName(sportId: number | string): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Translates a Sub-Sport ID to a readable name
|
|
16
|
+
*/
|
|
17
|
+
static getSubSportName(subSportId: number | string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Formats internal Garmin names into pretty names (e.g. fr945 -> Forerunner 945)
|
|
20
|
+
*/
|
|
21
|
+
private static formatDeviceName;
|
|
22
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { GarminManufacturers, GarminProducts, GarminSports, GarminSubSports } from './importer.fit.garmin.profile.data';
|
|
2
|
+
export class GarminProfileMapper {
|
|
3
|
+
/**
|
|
4
|
+
* Translates a Garmin Product ID to a readable device name
|
|
5
|
+
*/
|
|
6
|
+
static getDeviceName(productId) {
|
|
7
|
+
if (productId === null || productId === undefined) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const id = typeof productId === 'string' ? parseInt(productId, 10) : productId;
|
|
11
|
+
const name = GarminProducts[id];
|
|
12
|
+
return name ? this.formatDeviceName(name) : null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Translates a Manufacturer ID to a readable name
|
|
16
|
+
*/
|
|
17
|
+
static getManufacturerName(manufacturerId) {
|
|
18
|
+
if (manufacturerId === null || manufacturerId === undefined) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const id = typeof manufacturerId === 'string' ? parseInt(manufacturerId, 10) : manufacturerId;
|
|
22
|
+
return GarminManufacturers[id] || null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Translates a Sport ID to a readable name
|
|
26
|
+
*/
|
|
27
|
+
static getSportName(sportId) {
|
|
28
|
+
if (sportId === null || sportId === undefined) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const id = typeof sportId === 'string' ? parseInt(sportId, 10) : sportId;
|
|
32
|
+
return GarminSports[id] || null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Translates a Sub-Sport ID to a readable name
|
|
36
|
+
*/
|
|
37
|
+
static getSubSportName(subSportId) {
|
|
38
|
+
if (subSportId === null || subSportId === undefined) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const id = typeof subSportId === 'string' ? parseInt(subSportId, 10) : subSportId;
|
|
42
|
+
return GarminSubSports[id] || null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Formats internal Garmin names into pretty names (e.g. fr945 -> Forerunner 945)
|
|
46
|
+
*/
|
|
47
|
+
static formatDeviceName(name) {
|
|
48
|
+
if (!name)
|
|
49
|
+
return 'Unknown';
|
|
50
|
+
// First expand known abbreviations and add spaces
|
|
51
|
+
let formatted = name
|
|
52
|
+
.replace(/^fr(\d+)/i, 'Forerunner $1')
|
|
53
|
+
.replace(/^fenix(\d+)/i, 'Fenix $1')
|
|
54
|
+
.replace(/^edge(\d+)/i, 'Edge $1')
|
|
55
|
+
.replace(/^vivoactive/i, 'VivoActive')
|
|
56
|
+
.replace(/^vivosmart/i, 'VivoSmart')
|
|
57
|
+
.replace(/^vivofit/i, 'VivoFit')
|
|
58
|
+
.replace(/^vivomove/i, 'VivoMove')
|
|
59
|
+
.replace(/^vivosport/i, 'VivoSport')
|
|
60
|
+
.replace(/^approach([A-Z\d])/i, 'Approach $1')
|
|
61
|
+
.replace(/^marq([A-Z])/i, 'Marq $1')
|
|
62
|
+
.replace(/^hrm/i, 'HRM ')
|
|
63
|
+
.replace(/_/g, ' ') // Replace underscores with spaces
|
|
64
|
+
.replace(/([a-z])([A-Z0-9])/g, '$1 $2') // Add spaces between camelCase
|
|
65
|
+
.replace(/([0-9])([a-zA-Z])/g, '$1 $2'); // Add spaces between numbers and letters
|
|
66
|
+
// Capitalize and clean up special terms
|
|
67
|
+
formatted = formatted
|
|
68
|
+
.split(' ')
|
|
69
|
+
.map(word => {
|
|
70
|
+
const lower = word.toLowerCase();
|
|
71
|
+
if (lower === 'apac')
|
|
72
|
+
return 'APAC';
|
|
73
|
+
if (lower === 'xt')
|
|
74
|
+
return 'XT';
|
|
75
|
+
if (lower === 'lte')
|
|
76
|
+
return 'LTE';
|
|
77
|
+
if (lower === 'hr')
|
|
78
|
+
return 'HR';
|
|
79
|
+
if (lower === 'gps')
|
|
80
|
+
return 'GPS';
|
|
81
|
+
if (lower === 'ii')
|
|
82
|
+
return 'II';
|
|
83
|
+
if (lower === 'iii')
|
|
84
|
+
return 'III';
|
|
85
|
+
if (lower === 'm' && name.toLowerCase().includes('645m'))
|
|
86
|
+
return 'Music'; // Special case for Fr645m
|
|
87
|
+
if (lower === 'jpn')
|
|
88
|
+
return 'Japan';
|
|
89
|
+
if (lower === 'chn')
|
|
90
|
+
return 'China';
|
|
91
|
+
if (lower === 'twn')
|
|
92
|
+
return 'Taiwan';
|
|
93
|
+
if (lower === 'kor')
|
|
94
|
+
return 'Korea';
|
|
95
|
+
if (lower === 'rus')
|
|
96
|
+
return 'Russia';
|
|
97
|
+
if (lower === 'sea')
|
|
98
|
+
return 'SEA';
|
|
99
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
100
|
+
})
|
|
101
|
+
.join(' ')
|
|
102
|
+
.replace(/Vivo Active/g, 'VivoActive')
|
|
103
|
+
.trim();
|
|
104
|
+
return formatted;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -15,8 +15,8 @@ import { ActivityTypes, ActivityTypesMoving } from '../../../../activities/activ
|
|
|
15
15
|
import { DataDuration } from '../../../../data/data.duration';
|
|
16
16
|
import { DataEnergy } from '../../../../data/data.energy';
|
|
17
17
|
import { DataDistance } from '../../../../data/data.distance';
|
|
18
|
-
import { ImporterFitGarminDeviceNames } from './importer.fit.garmin.device.names';
|
|
19
18
|
import { ImporterFitSuuntoDeviceNames } from './importer.fit.suunto.device.names';
|
|
19
|
+
import { GarminProfileMapper } from './importer.fit.garmin.profile.mapper';
|
|
20
20
|
import { DataPause } from '../../../../data/data.pause';
|
|
21
21
|
import { DataCadenceAvg } from '../../../../data/data.cadence-avg';
|
|
22
22
|
import { DataPowerAvg } from '../../../../data/data.power-avg';
|
|
@@ -538,13 +538,24 @@ export class EventImporterFIT {
|
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
540
|
static getActivityTypeFromSessionObject(session) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
541
|
+
const activityTypeKey = session.sub_sport && session.sub_sport !== 'generic' ? `${session.sport}_${session.sub_sport}` : session.sport;
|
|
542
|
+
let activityType = ActivityTypes[activityTypeKey];
|
|
543
|
+
if (!activityType || activityType === ActivityTypes.unknown) {
|
|
544
|
+
// Fallback to Garmin SDK mappings
|
|
545
|
+
const sportName = GarminProfileMapper.getSportName(session.sport);
|
|
546
|
+
const subSportName = session.sub_sport && session.sub_sport !== 'generic'
|
|
547
|
+
? GarminProfileMapper.getSubSportName(session.sub_sport)
|
|
548
|
+
: null;
|
|
549
|
+
if (sportName || subSportName) {
|
|
550
|
+
// Try to find in ActivityTypes using the name from Garmin SDK
|
|
551
|
+
const nameKey = subSportName ? `${sportName}_${subSportName}` : sportName;
|
|
552
|
+
activityType =
|
|
553
|
+
ActivityTypes[nameKey] ||
|
|
554
|
+
ActivityTypes[sportName] ||
|
|
555
|
+
nameKey;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return activityType || session.sport || ActivityTypes.unknown;
|
|
548
559
|
}
|
|
549
560
|
// @todo move this to a mapper
|
|
550
561
|
static getStatsFromObject(object, activity, isLap) {
|
|
@@ -841,7 +852,7 @@ export class EventImporterFIT {
|
|
|
841
852
|
break;
|
|
842
853
|
}
|
|
843
854
|
case 'garmin': {
|
|
844
|
-
recognizedName =
|
|
855
|
+
recognizedName = GarminProfileMapper.getDeviceName(productId);
|
|
845
856
|
creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, 'Garmin'), productId);
|
|
846
857
|
break;
|
|
847
858
|
}
|
|
@@ -902,7 +913,12 @@ export class EventImporterFIT {
|
|
|
902
913
|
break;
|
|
903
914
|
}
|
|
904
915
|
default: {
|
|
905
|
-
|
|
916
|
+
// Try to find if it's a numeric Garmin mapping that was missed
|
|
917
|
+
const manufacturerName = typeof manufacturer === 'number' ? GarminProfileMapper.getManufacturerName(manufacturer) : manufacturer;
|
|
918
|
+
if (manufacturerName === 'garmin') {
|
|
919
|
+
recognizedName = GarminProfileMapper.getDeviceName(productId);
|
|
920
|
+
}
|
|
921
|
+
creator = new Creator(formatDeviceName(manufacturer, productName, recognizedName, manufacturerName === 'garmin' ? 'Garmin' : null), productId);
|
|
906
922
|
}
|
|
907
923
|
}
|
|
908
924
|
creator.manufacturer = manufacturer;
|
|
@@ -46,7 +46,7 @@ describe('EventImporterFIT', () => {
|
|
|
46
46
|
it('should recognize a known Garmin device', done => {
|
|
47
47
|
const manufacturer = 'garmin';
|
|
48
48
|
const expectedName = 'Garmin Edge 1000';
|
|
49
|
-
const productId =
|
|
49
|
+
const productId = 1836;
|
|
50
50
|
const fitDataObject = generateFitDeviceDataObject(manufacturer, productId);
|
|
51
51
|
// When
|
|
52
52
|
const creator = EventImporterFIT.getCreatorFromFitDataObject(fitDataObject);
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -33,3 +33,117 @@ export declare class SportsLib {
|
|
|
33
33
|
*/
|
|
34
34
|
static importFromJSON(json: EventJSONInterface): EventInterface;
|
|
35
35
|
}
|
|
36
|
+
export * from './activities/activity.interface';
|
|
37
|
+
export * from './activities/activity.json.interface';
|
|
38
|
+
export * from './activities/activity.types';
|
|
39
|
+
export * from './constants/constants';
|
|
40
|
+
export * from './data/data-aerobic-training-effect';
|
|
41
|
+
export * from './data/data.absolute-pressure';
|
|
42
|
+
export * from './data/data.accumulated-power';
|
|
43
|
+
export * from './data/data.activity-types';
|
|
44
|
+
export * from './data/data.air-power';
|
|
45
|
+
export * from './data/data.altitude';
|
|
46
|
+
export * from './data/data.altitude-avg';
|
|
47
|
+
export * from './data/data.altitude-gps';
|
|
48
|
+
export * from './data/data.altitude-max';
|
|
49
|
+
export * from './data/data.altitude-min';
|
|
50
|
+
export * from './data/data.ascent';
|
|
51
|
+
export * from './data/data.cadence-avg';
|
|
52
|
+
export * from './data/data.cadence-max';
|
|
53
|
+
export * from './data/data.cadence-min';
|
|
54
|
+
export * from './data/data.descent';
|
|
55
|
+
export * from './data/data.description';
|
|
56
|
+
export * from './data/data.device-names';
|
|
57
|
+
export * from './data/data.distance';
|
|
58
|
+
export * from './data/data.duration';
|
|
59
|
+
export * from './data/data.ehpe';
|
|
60
|
+
export * from './data/data.energy';
|
|
61
|
+
export * from './data/data.epoc';
|
|
62
|
+
export * from './data/data.evpe';
|
|
63
|
+
export * from './data/data.feeling';
|
|
64
|
+
export * from './data/data.grade-adjusted-pace';
|
|
65
|
+
export * from './data/data.grade-adjusted-pace-avg';
|
|
66
|
+
export * from './data/data.grade-adjusted-speed';
|
|
67
|
+
export * from './data/data.grade-adjusted-speed-avg';
|
|
68
|
+
export * from './data/data.heart-rate';
|
|
69
|
+
export * from './data/data.heart-rate-avg';
|
|
70
|
+
export * from './data/data.heart-rate-max';
|
|
71
|
+
export * from './data/data.heart-rate-min';
|
|
72
|
+
export * from './data/data.ibi';
|
|
73
|
+
export * from './data/data.interface';
|
|
74
|
+
export * from './data/data.latitude-degrees';
|
|
75
|
+
export * from './data/data.left-balance';
|
|
76
|
+
export * from './data/data.longitude-degrees';
|
|
77
|
+
export * from './data/data.moving-time';
|
|
78
|
+
export * from './data/data.pace';
|
|
79
|
+
export * from './data/data.pace-avg';
|
|
80
|
+
export * from './data/data.peak-epoc';
|
|
81
|
+
export * from './data/data.peak-training-effect';
|
|
82
|
+
export * from './data/data.position.interface';
|
|
83
|
+
export * from './data/data.power';
|
|
84
|
+
export * from './data/data.power-avg';
|
|
85
|
+
export * from './data/data.power-left';
|
|
86
|
+
export * from './data/data.power-max';
|
|
87
|
+
export * from './data/data.power-min';
|
|
88
|
+
export * from './data/data.power-right';
|
|
89
|
+
export * from './data/data.recovery-time';
|
|
90
|
+
export * from './data/data.right-balance';
|
|
91
|
+
export * from './data/data.rpe';
|
|
92
|
+
export * from './data/data.sea-level-pressure';
|
|
93
|
+
export * from './data/data.speed';
|
|
94
|
+
export * from './data/data.speed-avg';
|
|
95
|
+
export * from './data/data.speed-max';
|
|
96
|
+
export * from './data/data.speed-min';
|
|
97
|
+
export * from './data/data.start-position';
|
|
98
|
+
export * from './data/data.store';
|
|
99
|
+
export * from './data/data.stryd-altitude';
|
|
100
|
+
export * from './data/data.stryd-distance';
|
|
101
|
+
export * from './data/data.stryd-speed';
|
|
102
|
+
export * from './data/data.swim-pace';
|
|
103
|
+
export * from './data/data.swim-pace-avg';
|
|
104
|
+
export * from './data/data.swim-pace-max';
|
|
105
|
+
export * from './data/data.temperature';
|
|
106
|
+
export * from './data/data.temperature-avg';
|
|
107
|
+
export * from './data/data.temperature-max';
|
|
108
|
+
export * from './data/data.temperature-min';
|
|
109
|
+
export * from './data/data.vertical-speed';
|
|
110
|
+
export * from './data/data.vertical-speed-avg';
|
|
111
|
+
export * from './data/data.vo2-max';
|
|
112
|
+
export * from './data/ibi/data.ibi';
|
|
113
|
+
export * from './events/adapters/exporters/exporter.gpx';
|
|
114
|
+
export * from './events/adapters/exporters/exporter.json';
|
|
115
|
+
export * from './events/adapters/importers/fit/importer.fit';
|
|
116
|
+
export * from './events/adapters/importers/gpx/importer.gpx';
|
|
117
|
+
export * from './events/adapters/importers/json/importer.json';
|
|
118
|
+
export * from './events/adapters/importers/suunto/importer.suunto.json';
|
|
119
|
+
export * from './events/adapters/importers/suunto/importer.suunto.sml';
|
|
120
|
+
export * from './events/adapters/importers/tcx/importer.tcx';
|
|
121
|
+
export * from './events/event.interface';
|
|
122
|
+
export * from './events/event.json.interface';
|
|
123
|
+
export * from './events/utilities/activity.utilities';
|
|
124
|
+
export * from './events/utilities/event.utilities';
|
|
125
|
+
export * from './events/utilities/helpers';
|
|
126
|
+
export * from './geodesy/adapters/geolib.adapter';
|
|
127
|
+
export * from './laps/lap.interface';
|
|
128
|
+
export * from './laps/lap.types';
|
|
129
|
+
export * from './meta-data/event-meta-data.interface';
|
|
130
|
+
export * from './meta-data/meta-data';
|
|
131
|
+
export * from './privacy/privacy.class.interface';
|
|
132
|
+
export * from './service-tokens/oauth1-service-token.interface';
|
|
133
|
+
export * from './service-tokens/oauth2-service-token.interface';
|
|
134
|
+
export * from './stats/stats.class.interface';
|
|
135
|
+
export * from './streams/compressed.stream.interface';
|
|
136
|
+
export * from './streams/stream';
|
|
137
|
+
export * from './streams/stream.interface';
|
|
138
|
+
export * from './tiles/tile.settings.interface';
|
|
139
|
+
export * from './users/settings/dashboard/user.dashboard.settings.interface';
|
|
140
|
+
export * from './users/settings/user.app.settings.interface';
|
|
141
|
+
export * from './users/settings/user.chart.settings.interface';
|
|
142
|
+
export * from './users/settings/user.map.settings.interface';
|
|
143
|
+
export * from './users/settings/user.my-tracks.settings.interface';
|
|
144
|
+
export * from './users/settings/user.settings.interface';
|
|
145
|
+
export * from './users/settings/user.summaries.settings.interface';
|
|
146
|
+
export * from './users/settings/user.unit.settings.interface';
|
|
147
|
+
export * from './users/user';
|
|
148
|
+
export * from './users/user.export-to-csv.settings.interface';
|
|
149
|
+
export * from './users/user.service.meta.interface';
|
package/lib/esm/index.js
CHANGED
|
@@ -45,3 +45,117 @@ export class SportsLib {
|
|
|
45
45
|
return EventImporterJSON.getEventFromJSON(json);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
export * from './activities/activity.interface';
|
|
49
|
+
export * from './activities/activity.json.interface';
|
|
50
|
+
export * from './activities/activity.types';
|
|
51
|
+
export * from './constants/constants';
|
|
52
|
+
export * from './data/data-aerobic-training-effect';
|
|
53
|
+
export * from './data/data.absolute-pressure';
|
|
54
|
+
export * from './data/data.accumulated-power';
|
|
55
|
+
export * from './data/data.activity-types';
|
|
56
|
+
export * from './data/data.air-power';
|
|
57
|
+
export * from './data/data.altitude';
|
|
58
|
+
export * from './data/data.altitude-avg';
|
|
59
|
+
export * from './data/data.altitude-gps';
|
|
60
|
+
export * from './data/data.altitude-max';
|
|
61
|
+
export * from './data/data.altitude-min';
|
|
62
|
+
export * from './data/data.ascent';
|
|
63
|
+
export * from './data/data.cadence-avg';
|
|
64
|
+
export * from './data/data.cadence-max';
|
|
65
|
+
export * from './data/data.cadence-min';
|
|
66
|
+
export * from './data/data.descent';
|
|
67
|
+
export * from './data/data.description';
|
|
68
|
+
export * from './data/data.device-names';
|
|
69
|
+
export * from './data/data.distance';
|
|
70
|
+
export * from './data/data.duration';
|
|
71
|
+
export * from './data/data.ehpe';
|
|
72
|
+
export * from './data/data.energy';
|
|
73
|
+
export * from './data/data.epoc';
|
|
74
|
+
export * from './data/data.evpe';
|
|
75
|
+
export * from './data/data.feeling';
|
|
76
|
+
export * from './data/data.grade-adjusted-pace';
|
|
77
|
+
export * from './data/data.grade-adjusted-pace-avg';
|
|
78
|
+
export * from './data/data.grade-adjusted-speed';
|
|
79
|
+
export * from './data/data.grade-adjusted-speed-avg';
|
|
80
|
+
export * from './data/data.heart-rate';
|
|
81
|
+
export * from './data/data.heart-rate-avg';
|
|
82
|
+
export * from './data/data.heart-rate-max';
|
|
83
|
+
export * from './data/data.heart-rate-min';
|
|
84
|
+
export * from './data/data.ibi';
|
|
85
|
+
export * from './data/data.interface';
|
|
86
|
+
export * from './data/data.latitude-degrees';
|
|
87
|
+
export * from './data/data.left-balance';
|
|
88
|
+
export * from './data/data.longitude-degrees';
|
|
89
|
+
export * from './data/data.moving-time';
|
|
90
|
+
export * from './data/data.pace';
|
|
91
|
+
export * from './data/data.pace-avg';
|
|
92
|
+
export * from './data/data.peak-epoc';
|
|
93
|
+
export * from './data/data.peak-training-effect';
|
|
94
|
+
export * from './data/data.position.interface';
|
|
95
|
+
export * from './data/data.power';
|
|
96
|
+
export * from './data/data.power-avg';
|
|
97
|
+
export * from './data/data.power-left';
|
|
98
|
+
export * from './data/data.power-max';
|
|
99
|
+
export * from './data/data.power-min';
|
|
100
|
+
export * from './data/data.power-right';
|
|
101
|
+
export * from './data/data.recovery-time';
|
|
102
|
+
export * from './data/data.right-balance';
|
|
103
|
+
export * from './data/data.rpe';
|
|
104
|
+
export * from './data/data.sea-level-pressure';
|
|
105
|
+
export * from './data/data.speed';
|
|
106
|
+
export * from './data/data.speed-avg';
|
|
107
|
+
export * from './data/data.speed-max';
|
|
108
|
+
export * from './data/data.speed-min';
|
|
109
|
+
export * from './data/data.start-position';
|
|
110
|
+
export * from './data/data.store';
|
|
111
|
+
export * from './data/data.stryd-altitude';
|
|
112
|
+
export * from './data/data.stryd-distance';
|
|
113
|
+
export * from './data/data.stryd-speed';
|
|
114
|
+
export * from './data/data.swim-pace';
|
|
115
|
+
export * from './data/data.swim-pace-avg';
|
|
116
|
+
export * from './data/data.swim-pace-max';
|
|
117
|
+
export * from './data/data.temperature';
|
|
118
|
+
export * from './data/data.temperature-avg';
|
|
119
|
+
export * from './data/data.temperature-max';
|
|
120
|
+
export * from './data/data.temperature-min';
|
|
121
|
+
export * from './data/data.vertical-speed';
|
|
122
|
+
export * from './data/data.vertical-speed-avg';
|
|
123
|
+
export * from './data/data.vo2-max';
|
|
124
|
+
export * from './data/ibi/data.ibi';
|
|
125
|
+
export * from './events/adapters/exporters/exporter.gpx';
|
|
126
|
+
export * from './events/adapters/exporters/exporter.json';
|
|
127
|
+
export * from './events/adapters/importers/fit/importer.fit';
|
|
128
|
+
export * from './events/adapters/importers/gpx/importer.gpx';
|
|
129
|
+
export * from './events/adapters/importers/json/importer.json';
|
|
130
|
+
export * from './events/adapters/importers/suunto/importer.suunto.json';
|
|
131
|
+
export * from './events/adapters/importers/suunto/importer.suunto.sml';
|
|
132
|
+
export * from './events/adapters/importers/tcx/importer.tcx';
|
|
133
|
+
export * from './events/event.interface';
|
|
134
|
+
export * from './events/event.json.interface';
|
|
135
|
+
export * from './events/utilities/activity.utilities';
|
|
136
|
+
export * from './events/utilities/event.utilities';
|
|
137
|
+
export * from './events/utilities/helpers';
|
|
138
|
+
export * from './geodesy/adapters/geolib.adapter';
|
|
139
|
+
export * from './laps/lap.interface';
|
|
140
|
+
export * from './laps/lap.types';
|
|
141
|
+
export * from './meta-data/event-meta-data.interface';
|
|
142
|
+
export * from './meta-data/meta-data';
|
|
143
|
+
export * from './privacy/privacy.class.interface';
|
|
144
|
+
export * from './service-tokens/oauth1-service-token.interface';
|
|
145
|
+
export * from './service-tokens/oauth2-service-token.interface';
|
|
146
|
+
export * from './stats/stats.class.interface';
|
|
147
|
+
export * from './streams/compressed.stream.interface';
|
|
148
|
+
export * from './streams/stream';
|
|
149
|
+
export * from './streams/stream.interface';
|
|
150
|
+
export * from './tiles/tile.settings.interface';
|
|
151
|
+
export * from './users/settings/dashboard/user.dashboard.settings.interface';
|
|
152
|
+
export * from './users/settings/user.app.settings.interface';
|
|
153
|
+
export * from './users/settings/user.chart.settings.interface';
|
|
154
|
+
export * from './users/settings/user.map.settings.interface';
|
|
155
|
+
export * from './users/settings/user.my-tracks.settings.interface';
|
|
156
|
+
export * from './users/settings/user.settings.interface';
|
|
157
|
+
export * from './users/settings/user.summaries.settings.interface';
|
|
158
|
+
export * from './users/settings/user.unit.settings.interface';
|
|
159
|
+
export * from './users/user';
|
|
160
|
+
export * from './users/user.export-to-csv.settings.interface';
|
|
161
|
+
export * from './users/user.service.meta.interface';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Activity } from '../activities/activity';
|
|
2
|
+
import { Creator } from '../creators/creator';
|
|
3
|
+
import { DataDistance } from '../data/data.distance';
|
|
4
|
+
import { ActivityTypes } from '../activities/activity.types';
|
|
5
|
+
import { DataDuration } from '../data/data.duration';
|
|
6
|
+
describe('Activity Duration Stream', () => {
|
|
7
|
+
let activity;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Create a 10-second activity
|
|
10
|
+
const startDate = new Date('2023-01-01T10:00:00Z');
|
|
11
|
+
const endDate = new Date('2023-01-01T10:00:10Z');
|
|
12
|
+
const creator = new Creator('Test Creator');
|
|
13
|
+
activity = new Activity(startDate, endDate, ActivityTypes.Running, creator);
|
|
14
|
+
});
|
|
15
|
+
it('should generate a duration stream based on time stream logic', () => {
|
|
16
|
+
// Add a distance stream with some data
|
|
17
|
+
const distanceStream = activity.createStream(DataDistance.type);
|
|
18
|
+
// Data at 0s, 5s, 10s
|
|
19
|
+
distanceStream.getData()[0] = 0;
|
|
20
|
+
distanceStream.getData()[5] = 50;
|
|
21
|
+
distanceStream.getData()[10] = 100;
|
|
22
|
+
activity.addStream(distanceStream);
|
|
23
|
+
const durationStream = activity.generateDurationStream();
|
|
24
|
+
expect(durationStream.type).toBe(DataDuration.type);
|
|
25
|
+
const data = durationStream.getData();
|
|
26
|
+
// Assuming generateTimeStream fills data where source stream has data
|
|
27
|
+
expect(data[0]).toBe(0);
|
|
28
|
+
expect(data[5]).toBe(5);
|
|
29
|
+
expect(data[10]).toBe(10);
|
|
30
|
+
// Other indices should be null/undefined as per generateTimeStream logic?
|
|
31
|
+
// Let's verify what generateTimeStream does.
|
|
32
|
+
// It uses `getStreamDataByDuration` with filterNull=true.
|
|
33
|
+
// So it only populates indices where source stream has data.
|
|
34
|
+
expect(data[1]).toBeFalsy();
|
|
35
|
+
expect(data[2]).toBeFalsy();
|
|
36
|
+
});
|
|
37
|
+
it('should allow specifying stream types to base duration on', () => {
|
|
38
|
+
// Scenario where we want duration based on HeartRate, not Distance
|
|
39
|
+
// Although logic reuses generateTimeStream which filters by streamTypes if provided.
|
|
40
|
+
// But generateTimeStream implementation:
|
|
41
|
+
/*
|
|
42
|
+
if (streamTypes.length) {
|
|
43
|
+
streams = streams.filter(stream => streamTypes.indexOf(stream.type) !== -1);
|
|
44
|
+
}
|
|
45
|
+
*/
|
|
46
|
+
// It unions all provided streams?
|
|
47
|
+
// "streams.forEach(stream => { ... })"
|
|
48
|
+
// Yes, it iterates all matching streams and fills the time stream.
|
|
49
|
+
// Let's create a custom stream
|
|
50
|
+
const customStream = activity.createStream('Custom');
|
|
51
|
+
customStream.getData()[2] = 123;
|
|
52
|
+
activity.addStream(customStream);
|
|
53
|
+
const durationStream = activity.generateDurationStream(['Custom']);
|
|
54
|
+
expect(durationStream.getData()[2]).toBe(2);
|
|
55
|
+
expect(durationStream.getData()[0]).toBeFalsy(); // Distance stream at 0 should be ignored if we only asked for Custom
|
|
56
|
+
});
|
|
57
|
+
});
|
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.3",
|
|
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",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@babel/core": "^7.28.5",
|
|
66
66
|
"@babel/preset-env": "^7.28.5",
|
|
67
|
+
"@garmin/fitsdk": "^21.178.0",
|
|
67
68
|
"@types/jest": "^27.0.1",
|
|
68
69
|
"@types/node": "^14.6.1",
|
|
69
70
|
"@types/xmldom": "^0.1.31",
|