fit-file-parser 5.2.1 → 6.1.1
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/CHANGELOG.md +35 -191
- package/PROFILE.md +43 -0
- package/README.md +126 -82
- package/dist/binary.d.ts +2 -0
- package/dist/binary.js +23 -6
- package/dist/cjs/binary.d.ts +2 -0
- package/dist/cjs/binary.js +23 -6
- package/dist/cjs/fit-parser.d.ts +5 -0
- package/dist/cjs/fit-parser.js +42 -4
- package/dist/cjs/fit.d.ts +0 -6
- package/dist/cjs/fit.js +4 -114
- package/dist/cjs/fit_types.d.ts +2 -1
- package/dist/cjs/profile-lookup.d.ts +19 -0
- package/dist/cjs/profile-lookup.js +150 -0
- package/dist/cjs/profile.d.ts +9 -0
- package/dist/{garmin_profile.generated.js → cjs/profile.js} +287 -8
- package/dist/cjs/raw-message-reader.d.ts +60 -0
- package/dist/cjs/raw-message-reader.js +377 -0
- package/dist/cjs/type_generator.js +1 -0
- package/dist/fit-parser.d.ts +5 -0
- package/dist/fit-parser.js +27 -3
- package/dist/fit.d.ts +0 -6
- package/dist/fit.js +3 -113
- package/dist/fit_types.d.ts +2 -1
- package/dist/profile-lookup.d.ts +19 -0
- package/dist/profile-lookup.js +140 -0
- package/dist/profile.d.ts +9 -0
- package/dist/{cjs/garmin_profile.generated.js → profile.js} +284 -11
- package/dist/raw-message-reader.d.ts +60 -0
- package/dist/raw-message-reader.js +368 -0
- package/dist/type_generator.js +1 -0
- package/package.json +38 -9
- package/dist/cjs/garmin_profile.generated.d.ts +0 -9
- package/dist/garmin_profile.generated.d.ts +0 -9
package/dist/cjs/binary.js
CHANGED
|
@@ -528,6 +528,8 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
528
528
|
&& options.includeRawDeveloperFields.includes(messageType.globalMessageNumber));
|
|
529
529
|
const rawFields = includeRawMessage ? [] : undefined;
|
|
530
530
|
const rawDeveloperFields = includeRawDeveloperFields || includeRawMessage ? [] : undefined;
|
|
531
|
+
const unmappedFields = options.includeUnmappedMessages ? [] : undefined;
|
|
532
|
+
const unmappedDeveloperFields = options.includeUnmappedMessages ? [] : undefined;
|
|
531
533
|
if (retainsRawMessages(options)) {
|
|
532
534
|
const nativeSize = messageType.fieldDefs.reduce((total, field, index) => (total + (isCompressedTimestamp && index === 0 && field.fDefNo === 253 ? 0 : field.size)), 0);
|
|
533
535
|
const developerSize = developerFieldDefs.reduce((total, field) => total + field.size, 0);
|
|
@@ -543,12 +545,17 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
543
545
|
rawData[i] = InvalidFieldData;
|
|
544
546
|
continue;
|
|
545
547
|
}
|
|
546
|
-
if (rawFields
|
|
547
|
-
|
|
548
|
+
if ((rawFields || (unmappedFields && !isOutputFieldName(fDef.name)))
|
|
549
|
+
&& readDataFromIndex + fDef.size <= dataEnd) {
|
|
550
|
+
const rawField = {
|
|
548
551
|
fieldDefinitionNumber: fDef.fDefNo,
|
|
549
552
|
baseType: fDef.baseTypeNo,
|
|
550
553
|
rawValue: Array.from(blob.subarray(readDataFromIndex, readDataFromIndex + fDef.size)),
|
|
551
|
-
}
|
|
554
|
+
};
|
|
555
|
+
rawFields === null || rawFields === void 0 ? void 0 : rawFields.push(rawField);
|
|
556
|
+
if (!isOutputFieldName(fDef.name)) {
|
|
557
|
+
unmappedFields === null || unmappedFields === void 0 ? void 0 : unmappedFields.push(rawField);
|
|
558
|
+
}
|
|
552
559
|
}
|
|
553
560
|
const data = readData(blob, dataView, fDef, readDataFromIndex);
|
|
554
561
|
if (data !== InvalidFieldData
|
|
@@ -572,15 +579,21 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
572
579
|
for (let i = 0; i < developerFieldDefs.length; i++) {
|
|
573
580
|
const developerFieldDef = developerFieldDefs[i];
|
|
574
581
|
const rawDataIndex = messageType.fieldDefs.length + i;
|
|
575
|
-
|
|
582
|
+
let rawDeveloperField;
|
|
583
|
+
if ((rawDeveloperFields
|
|
584
|
+
|| (unmappedDeveloperFields && developerFieldDef.resolvedFieldDef === undefined))
|
|
576
585
|
&& readDataFromIndex + developerFieldDef.size <= dataEnd) {
|
|
577
|
-
|
|
586
|
+
rawDeveloperField = {
|
|
578
587
|
developerDataIndex: developerFieldDef.developerDataIndex,
|
|
579
588
|
fieldDefinitionNumber: developerFieldDef.fieldDefinitionNumber,
|
|
580
589
|
rawValue: Array.from(blob.subarray(readDataFromIndex, readDataFromIndex + developerFieldDef.size)),
|
|
581
|
-
}
|
|
590
|
+
};
|
|
591
|
+
rawDeveloperFields === null || rawDeveloperFields === void 0 ? void 0 : rawDeveloperFields.push(rawDeveloperField);
|
|
582
592
|
}
|
|
583
593
|
const fDef = resolveDeveloperFieldDefinition(developerFieldDef, messageType.littleEndian, developerFields, options);
|
|
594
|
+
if (!fDef && rawDeveloperField) {
|
|
595
|
+
unmappedDeveloperFields === null || unmappedDeveloperFields === void 0 ? void 0 : unmappedDeveloperFields.push(rawDeveloperField);
|
|
596
|
+
}
|
|
584
597
|
if (fDef) {
|
|
585
598
|
const data = readData(blob, dataView, fDef, readDataFromIndex);
|
|
586
599
|
if (data !== InvalidFieldData
|
|
@@ -698,6 +711,10 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
|
|
|
698
711
|
message: fields,
|
|
699
712
|
rawFields,
|
|
700
713
|
rawDeveloperFields,
|
|
714
|
+
unmappedFields: unmappedFields && unmappedFields.length > 0 ? unmappedFields : undefined,
|
|
715
|
+
unmappedDeveloperFields: unmappedDeveloperFields && unmappedDeveloperFields.length > 0
|
|
716
|
+
? unmappedDeveloperFields
|
|
717
|
+
: undefined,
|
|
701
718
|
};
|
|
702
719
|
}
|
|
703
720
|
function getArrayBuffer(buffer) {
|
package/dist/cjs/fit-parser.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import type { ParsedFit } from './fit_types.js';
|
|
|
3
3
|
export { FitBaseType, FitEncoder } from './fit-encoder.js';
|
|
4
4
|
export type { FitEncoderField, FitEncoderOptions } from './fit-encoder.js';
|
|
5
5
|
export type { ParsedFit, ParsedRawDeveloperField, ParsedRawFitField, ParsedRawFitMessage, ParsedRawFitMessageDeveloperField, } from './fit_types.js';
|
|
6
|
+
export { getFitCoursePointId, getFitGarminProductDisplayName, getFitGarminProductName, getFitManufacturerName, getFitSportId, getFitSportName, getFitSubSportId, getFitSubSportName, } from './profile-lookup.js';
|
|
7
|
+
export { FitMessageReaderError, fitTimestampToUnixMilliseconds, getFitBaseTypeId, readFitMessages, readFitStringField, readFitUnsignedField, } from './raw-message-reader.js';
|
|
8
|
+
export type { FitMessageReaderErrorCode, FitMessageReaderIssue, FitMessageReaderIssueCode, FitMessageReaderOptions, FitMessageReaderResult, FitRawDeveloperField, FitRawField, FitRawMessage, } from './raw-message-reader.js';
|
|
6
9
|
export interface FitParserOptions {
|
|
7
10
|
force?: boolean;
|
|
8
11
|
speedUnit?: string;
|
|
@@ -15,6 +18,8 @@ export interface FitParserOptions {
|
|
|
15
18
|
includeRawDeveloperFields?: boolean | readonly number[];
|
|
16
19
|
/** Retains exact native and developer fields for all or selected global message numbers. */
|
|
17
20
|
includeRawMessages?: boolean | readonly number[];
|
|
21
|
+
/** Retains exact bytes for fields that have no semantic profile mapping. */
|
|
22
|
+
includeUnmappedMessages?: boolean;
|
|
18
23
|
/** Returns only parser metadata and retained raw messages instead of decoded activity collections. */
|
|
19
24
|
rawMessagesOnly?: boolean;
|
|
20
25
|
}
|
package/dist/cjs/fit-parser.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FitEncoder = exports.FitBaseType = void 0;
|
|
3
|
+
exports.readFitUnsignedField = exports.readFitStringField = exports.readFitMessages = exports.getFitBaseTypeId = exports.fitTimestampToUnixMilliseconds = exports.FitMessageReaderError = exports.getFitSubSportName = exports.getFitSubSportId = exports.getFitSportName = exports.getFitSportId = exports.getFitManufacturerName = exports.getFitGarminProductName = exports.getFitGarminProductDisplayName = exports.getFitCoursePointId = exports.FitEncoder = exports.FitBaseType = void 0;
|
|
4
4
|
const binary_js_1 = require("./binary.js");
|
|
5
5
|
const helper_js_1 = require("./helper.js");
|
|
6
6
|
var fit_encoder_js_1 = require("./fit-encoder.js");
|
|
7
7
|
Object.defineProperty(exports, "FitBaseType", { enumerable: true, get: function () { return fit_encoder_js_1.FitBaseType; } });
|
|
8
8
|
Object.defineProperty(exports, "FitEncoder", { enumerable: true, get: function () { return fit_encoder_js_1.FitEncoder; } });
|
|
9
|
+
var profile_lookup_js_1 = require("./profile-lookup.js");
|
|
10
|
+
Object.defineProperty(exports, "getFitCoursePointId", { enumerable: true, get: function () { return profile_lookup_js_1.getFitCoursePointId; } });
|
|
11
|
+
Object.defineProperty(exports, "getFitGarminProductDisplayName", { enumerable: true, get: function () { return profile_lookup_js_1.getFitGarminProductDisplayName; } });
|
|
12
|
+
Object.defineProperty(exports, "getFitGarminProductName", { enumerable: true, get: function () { return profile_lookup_js_1.getFitGarminProductName; } });
|
|
13
|
+
Object.defineProperty(exports, "getFitManufacturerName", { enumerable: true, get: function () { return profile_lookup_js_1.getFitManufacturerName; } });
|
|
14
|
+
Object.defineProperty(exports, "getFitSportId", { enumerable: true, get: function () { return profile_lookup_js_1.getFitSportId; } });
|
|
15
|
+
Object.defineProperty(exports, "getFitSportName", { enumerable: true, get: function () { return profile_lookup_js_1.getFitSportName; } });
|
|
16
|
+
Object.defineProperty(exports, "getFitSubSportId", { enumerable: true, get: function () { return profile_lookup_js_1.getFitSubSportId; } });
|
|
17
|
+
Object.defineProperty(exports, "getFitSubSportName", { enumerable: true, get: function () { return profile_lookup_js_1.getFitSubSportName; } });
|
|
18
|
+
var raw_message_reader_js_1 = require("./raw-message-reader.js");
|
|
19
|
+
Object.defineProperty(exports, "FitMessageReaderError", { enumerable: true, get: function () { return raw_message_reader_js_1.FitMessageReaderError; } });
|
|
20
|
+
Object.defineProperty(exports, "fitTimestampToUnixMilliseconds", { enumerable: true, get: function () { return raw_message_reader_js_1.fitTimestampToUnixMilliseconds; } });
|
|
21
|
+
Object.defineProperty(exports, "getFitBaseTypeId", { enumerable: true, get: function () { return raw_message_reader_js_1.getFitBaseTypeId; } });
|
|
22
|
+
Object.defineProperty(exports, "readFitMessages", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitMessages; } });
|
|
23
|
+
Object.defineProperty(exports, "readFitStringField", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitStringField; } });
|
|
24
|
+
Object.defineProperty(exports, "readFitUnsignedField", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitUnsignedField; } });
|
|
9
25
|
class FitParser {
|
|
10
26
|
constructor(options = {}) {
|
|
11
|
-
var _a, _b, _c;
|
|
27
|
+
var _a, _b, _c, _d;
|
|
12
28
|
this.options = {
|
|
13
29
|
force: options.force != null ? options.force : true,
|
|
14
30
|
speedUnit: options.speedUnit || 'm/s',
|
|
@@ -19,7 +35,8 @@ class FitParser {
|
|
|
19
35
|
mode: options.mode || 'list',
|
|
20
36
|
includeRawDeveloperFields: (_a = options.includeRawDeveloperFields) !== null && _a !== void 0 ? _a : false,
|
|
21
37
|
includeRawMessages: (_b = options.includeRawMessages) !== null && _b !== void 0 ? _b : false,
|
|
22
|
-
|
|
38
|
+
includeUnmappedMessages: (_c = options.includeUnmappedMessages) !== null && _c !== void 0 ? _c : false,
|
|
39
|
+
rawMessagesOnly: (_d = options.rawMessagesOnly) !== null && _d !== void 0 ? _d : false,
|
|
23
40
|
};
|
|
24
41
|
}
|
|
25
42
|
parseAsync(content) {
|
|
@@ -130,6 +147,7 @@ class FitParser {
|
|
|
130
147
|
|| Array.isArray(this.options.includeRawMessages)
|
|
131
148
|
? []
|
|
132
149
|
: undefined;
|
|
150
|
+
const unmappedMessages = this.options.includeUnmappedMessages ? [] : undefined;
|
|
133
151
|
const messageCountsByGlobalNumber = new Map();
|
|
134
152
|
let loopIndex = headerLength;
|
|
135
153
|
const messageTypes = [];
|
|
@@ -141,7 +159,7 @@ class FitParser {
|
|
|
141
159
|
let lastStopTimestamp;
|
|
142
160
|
let pausedTime = 0;
|
|
143
161
|
while (loopIndex < crcStart) {
|
|
144
|
-
const { globalMessageNumber, littleEndian, message, messageType, nextIndex, compressedTimestamp, rawFields: recordRawFields, rawDeveloperFields: recordRawDeveloperFields, } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState, crcStart);
|
|
162
|
+
const { globalMessageNumber, littleEndian, message, messageType, nextIndex, compressedTimestamp, rawFields: recordRawFields, rawDeveloperFields: recordRawDeveloperFields, unmappedFields: recordUnmappedFields, unmappedDeveloperFields: recordUnmappedDeveloperFields, } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState, crcStart);
|
|
145
163
|
loopIndex = nextIndex;
|
|
146
164
|
if (globalMessageNumber !== undefined) {
|
|
147
165
|
const messageIndex = (_a = messageCountsByGlobalNumber.get(globalMessageNumber)) !== null && _a !== void 0 ? _a : 0;
|
|
@@ -168,6 +186,20 @@ class FitParser {
|
|
|
168
186
|
raw_value: field.rawValue,
|
|
169
187
|
});
|
|
170
188
|
});
|
|
189
|
+
if (littleEndian !== undefined
|
|
190
|
+
&& ((recordUnmappedFields === null || recordUnmappedFields === void 0 ? void 0 : recordUnmappedFields.length) || (recordUnmappedDeveloperFields === null || recordUnmappedDeveloperFields === void 0 ? void 0 : recordUnmappedDeveloperFields.length))) {
|
|
191
|
+
unmappedMessages === null || unmappedMessages === void 0 ? void 0 : unmappedMessages.push(Object.assign(Object.assign({ global_message_number: globalMessageNumber, message_index: messageIndex, little_endian: littleEndian }, (compressedTimestamp === undefined
|
|
192
|
+
? {}
|
|
193
|
+
: { compressed_timestamp: compressedTimestamp })), { fields: (recordUnmappedFields !== null && recordUnmappedFields !== void 0 ? recordUnmappedFields : []).map(field => ({
|
|
194
|
+
field_definition_number: field.fieldDefinitionNumber,
|
|
195
|
+
base_type: field.baseType,
|
|
196
|
+
raw_value: field.rawValue,
|
|
197
|
+
})), developer_fields: (recordUnmappedDeveloperFields !== null && recordUnmappedDeveloperFields !== void 0 ? recordUnmappedDeveloperFields : []).map(field => ({
|
|
198
|
+
developer_data_index: field.developerDataIndex,
|
|
199
|
+
field_definition_number: field.fieldDefinitionNumber,
|
|
200
|
+
raw_value: field.rawValue,
|
|
201
|
+
})) }));
|
|
202
|
+
}
|
|
171
203
|
}
|
|
172
204
|
if (this.options.rawMessagesOnly) {
|
|
173
205
|
continue;
|
|
@@ -298,6 +330,9 @@ class FitParser {
|
|
|
298
330
|
if (rawMessages) {
|
|
299
331
|
fitObj.raw_messages = rawMessages;
|
|
300
332
|
}
|
|
333
|
+
if (unmappedMessages && unmappedMessages.length > 0) {
|
|
334
|
+
fitObj.unmapped_messages = unmappedMessages;
|
|
335
|
+
}
|
|
301
336
|
callback(undefined, fitObj);
|
|
302
337
|
return;
|
|
303
338
|
}
|
|
@@ -326,6 +361,9 @@ class FitParser {
|
|
|
326
361
|
if (rawMessages) {
|
|
327
362
|
fitObj.raw_messages = rawMessages;
|
|
328
363
|
}
|
|
364
|
+
if (unmappedMessages && unmappedMessages.length > 0) {
|
|
365
|
+
fitObj.unmapped_messages = unmappedMessages;
|
|
366
|
+
}
|
|
329
367
|
if (isCascadeNeeded) {
|
|
330
368
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'records', records);
|
|
331
369
|
laps = (0, helper_js_1.mapDataIntoLap)(laps, 'lengths', lengths);
|
package/dist/cjs/fit.d.ts
CHANGED
|
@@ -37,10 +37,4 @@ export interface FitType {
|
|
|
37
37
|
messages: Record<number, Message>;
|
|
38
38
|
types: Record<string, Record<number, string | number>>;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Garmin fields observed in the external FIT corpus but absent from the pinned
|
|
42
|
-
* public SDK profile. These additions may not replace standard SDK fields.
|
|
43
|
-
*/
|
|
44
|
-
export declare const FIT_VENDOR_MESSAGE_EXTENSIONS: Record<number, Message>;
|
|
45
|
-
export declare const FIT_VENDOR_TYPE_EXTENSIONS: Record<string, Record<number, string>>;
|
|
46
40
|
export declare const FIT: FitType;
|
package/dist/cjs/fit.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FIT =
|
|
4
|
-
const
|
|
3
|
+
exports.FIT = void 0;
|
|
4
|
+
const profile_js_1 = require("./profile.js");
|
|
5
5
|
const metersInOneKilometer = 1000;
|
|
6
6
|
const secondsInOneHour = 3600;
|
|
7
7
|
// according to https://en.wikipedia.org/wiki/Mile
|
|
@@ -31,119 +31,9 @@ const options = {
|
|
|
31
31
|
psi: { multiplier: psiInOneBar, offset: 0 },
|
|
32
32
|
},
|
|
33
33
|
};
|
|
34
|
-
/**
|
|
35
|
-
* Garmin fields observed in the external FIT corpus but absent from the pinned
|
|
36
|
-
* public SDK profile. These additions may not replace standard SDK fields.
|
|
37
|
-
*/
|
|
38
|
-
exports.FIT_VENDOR_MESSAGE_EXTENSIONS = {
|
|
39
|
-
18: {
|
|
40
|
-
name: 'session',
|
|
41
|
-
178: field('est_sweat_loss', 'uint16', 1, 'ml'),
|
|
42
|
-
188: field('primary_benefit', 'uint8'),
|
|
43
|
-
205: field('beginning_potential_stamina', 'uint8', 1, 'percent'),
|
|
44
|
-
206: field('ending_potential_stamina', 'uint8', 1, 'percent'),
|
|
45
|
-
207: field('min_stamina', 'uint8', 1, 'percent'),
|
|
46
|
-
},
|
|
47
|
-
20: {
|
|
48
|
-
name: 'record',
|
|
49
|
-
90: field('garmin_performance_condition', 'sint8'),
|
|
50
|
-
137: field('potential_stamina', 'uint8', 1, 'percent'),
|
|
51
|
-
138: field('stamina', 'uint8', 1, 'percent'),
|
|
52
|
-
},
|
|
53
|
-
23: {
|
|
54
|
-
name: 'device_info',
|
|
55
|
-
24: field('ant_id', 'uint32z'),
|
|
56
|
-
},
|
|
57
|
-
// Undocumented Garmin user metrics message observed in activity FIT files.
|
|
58
|
-
79: {
|
|
59
|
-
name: 'user_metrics',
|
|
60
|
-
0: field('vo2_max', 'uint16', 1024 / 3.5, 'ml/kg/min'),
|
|
61
|
-
1: field('age', 'uint8', 1, 'years'),
|
|
62
|
-
2: field('height', 'uint8', 100, 'm'),
|
|
63
|
-
3: field('weight', 'uint16', 10, 'kg'),
|
|
64
|
-
4: field('gender', 'gender'),
|
|
65
|
-
6: field('max_heart_rate', 'uint8', 1, 'bpm'),
|
|
66
|
-
8: field('remaining_recovery_time', 'uint16'),
|
|
67
|
-
11: field('lthr', 'uint16', 1, 'bpm'),
|
|
68
|
-
12: field('ltpower', 'uint16', 1, 'watts'),
|
|
69
|
-
13: field('ltspeed', 'uint16', 1000, 'm/s'),
|
|
70
|
-
16: field('start_of_activity', 'date_time'),
|
|
71
|
-
19: field('first_vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
72
|
-
35: field('end_of_previous_activity', 'date_time'),
|
|
73
|
-
253: field('timestamp', 'date_time'),
|
|
74
|
-
},
|
|
75
|
-
// Undocumented Garmin activity metrics message observed in activity FIT files.
|
|
76
|
-
140: {
|
|
77
|
-
name: 'activity_metrics',
|
|
78
|
-
1: field('new_max_heart_rate', 'uint8', 1, 'bpm'),
|
|
79
|
-
4: field('aerobic_training_effect', 'uint8', 10),
|
|
80
|
-
7: field('vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
81
|
-
9: field('recovery_time', 'uint16', 1, 'min'),
|
|
82
|
-
11: field('sport', 'sport'),
|
|
83
|
-
20: field('anaerobic_training_effect', 'uint8', 10),
|
|
84
|
-
29: field('first_vo2_max', 'uint32', 65536 / 3.5, 'ml/kg/min'),
|
|
85
|
-
41: field('primary_benefit', 'uint8'),
|
|
86
|
-
60: field('total_ascent', 'uint16', 1, 'm'),
|
|
87
|
-
61: field('total_descent', 'uint16', 1, 'm'),
|
|
88
|
-
62: field('avg_power', 'uint16', 1, 'watts'),
|
|
89
|
-
63: field('avg_heart_rate', 'uint8', 1, 'bpm'),
|
|
90
|
-
},
|
|
91
|
-
312: {
|
|
92
|
-
name: 'split',
|
|
93
|
-
107: field('beginning_potential_stamina', 'uint8', 1, 'percent'),
|
|
94
|
-
108: field('ending_potential_stamina', 'uint8', 1, 'percent'),
|
|
95
|
-
109: field('min_stamina', 'uint8', 1, 'percent'),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
exports.FIT_VENDOR_TYPE_EXTENSIONS = {
|
|
99
|
-
mesg_num: {
|
|
100
|
-
79: 'user_metrics',
|
|
101
|
-
140: 'activity_metrics',
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
function field(name, type, scale = 1, units = '', baseType) {
|
|
105
|
-
return Object.assign(Object.assign({ field: name, type }, (baseType ? { baseType } : {})), { scale, offset: 0, units });
|
|
106
|
-
}
|
|
107
|
-
function mergeVendorMessages() {
|
|
108
|
-
const messages = Object.assign({}, garmin_profile_generated_js_1.GARMIN_MESSAGES);
|
|
109
|
-
Object.entries(exports.FIT_VENDOR_MESSAGE_EXTENSIONS).forEach(([messageIdText, extension]) => {
|
|
110
|
-
const messageId = Number(messageIdText);
|
|
111
|
-
const standardMessage = messages[messageId];
|
|
112
|
-
if (!standardMessage) {
|
|
113
|
-
messages[messageId] = extension;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (standardMessage.name !== extension.name) {
|
|
117
|
-
throw new Error(`Vendor message ${messageId} conflicts with the Garmin SDK name`);
|
|
118
|
-
}
|
|
119
|
-
Object.keys(extension)
|
|
120
|
-
.filter(key => key !== 'name')
|
|
121
|
-
.forEach((fieldId) => {
|
|
122
|
-
if (standardMessage[Number(fieldId)]) {
|
|
123
|
-
throw new Error(`Vendor message ${messageId}, field ${fieldId} conflicts with the Garmin SDK profile`);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
messages[messageId] = Object.assign(Object.assign({}, standardMessage), extension);
|
|
127
|
-
});
|
|
128
|
-
return messages;
|
|
129
|
-
}
|
|
130
|
-
function mergeVendorTypes() {
|
|
131
|
-
const types = Object.fromEntries(Object.entries(garmin_profile_generated_js_1.GARMIN_TYPES).map(([name, values]) => [name, Object.assign({}, values)]));
|
|
132
|
-
Object.entries(exports.FIT_VENDOR_TYPE_EXTENSIONS).forEach(([name, extension]) => {
|
|
133
|
-
var _a;
|
|
134
|
-
const standardValues = (_a = types[name]) !== null && _a !== void 0 ? _a : {};
|
|
135
|
-
Object.keys(extension).forEach((valueId) => {
|
|
136
|
-
if (standardValues[Number(valueId)] !== undefined) {
|
|
137
|
-
throw new Error(`Vendor type ${name}, value ${valueId} conflicts with the Garmin SDK profile`);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
types[name] = Object.assign(Object.assign({}, standardValues), extension);
|
|
141
|
-
});
|
|
142
|
-
return types;
|
|
143
|
-
}
|
|
144
34
|
exports.FIT = {
|
|
145
35
|
scConst: 180 / Math.pow(2, 31),
|
|
146
36
|
options,
|
|
147
|
-
messages:
|
|
148
|
-
types:
|
|
37
|
+
messages: profile_js_1.PROFILE_MESSAGES,
|
|
38
|
+
types: profile_js_1.PROFILE_TYPES,
|
|
149
39
|
};
|
package/dist/cjs/fit_types.d.ts
CHANGED
|
@@ -213,7 +213,7 @@ export type SportEvent = 'uncategorized' | 'geocaching' | 'fitness' | 'recreatio
|
|
|
213
213
|
export type SquatExerciseName = 'leg_press' | 'back_squat_with_body_bar' | 'back_squats' | 'weighted_back_squats' | 'balancing_squat' | 'weighted_balancing_squat' | 'barbell_back_squat' | 'barbell_box_squat' | 'barbell_front_squat' | 'barbell_hack_squat' | 'barbell_hang_squat_snatch' | 'barbell_lateral_step_up' | 'barbell_quarter_squat' | 'barbell_siff_squat' | 'barbell_squat_snatch' | 'barbell_squat_with_heels_raised' | 'barbell_stepover' | 'barbell_step_up' | 'bench_squat_with_rotational_chop' | 'weighted_bench_squat_with_rotational_chop' | 'body_weight_wall_squat' | 'weighted_wall_squat' | 'box_step_squat' | 'weighted_box_step_squat' | 'braced_squat' | 'crossed_arm_barbell_front_squat' | 'crossover_dumbbell_step_up' | 'dumbbell_front_squat' | 'dumbbell_split_squat' | 'dumbbell_squat' | 'dumbbell_squat_clean' | 'dumbbell_stepover' | 'dumbbell_step_up' | 'elevated_single_leg_squat' | 'weighted_elevated_single_leg_squat' | 'figure_four_squats' | 'weighted_figure_four_squats' | 'goblet_squat' | 'kettlebell_squat' | 'kettlebell_swing_overhead' | 'kettlebell_swing_with_flip_to_squat' | 'lateral_dumbbell_step_up' | 'one_legged_squat' | 'overhead_dumbbell_squat' | 'overhead_squat' | 'partial_single_leg_squat' | 'weighted_partial_single_leg_squat' | 'pistol_squat' | 'weighted_pistol_squat' | 'plie_slides' | 'weighted_plie_slides' | 'plie_squat' | 'weighted_plie_squat' | 'prisoner_squat' | 'weighted_prisoner_squat' | 'single_leg_bench_get_up' | 'weighted_single_leg_bench_get_up' | 'single_leg_bench_squat' | 'weighted_single_leg_bench_squat' | 'single_leg_squat_on_swiss_ball' | 'weighted_single_leg_squat_on_swiss_ball' | 'squat' | 'weighted_squat' | 'squats_with_band' | 'staggered_squat' | 'weighted_staggered_squat' | 'step_up' | 'weighted_step_up' | 'suitcase_squats' | 'sumo_squat' | 'sumo_squat_slide_in' | 'weighted_sumo_squat_slide_in' | 'sumo_squat_to_high_pull' | 'sumo_squat_to_stand' | 'weighted_sumo_squat_to_stand' | 'sumo_squat_with_rotation' | 'weighted_sumo_squat_with_rotation' | 'swiss_ball_body_weight_wall_squat' | 'weighted_swiss_ball_wall_squat' | 'thrusters' | 'uneven_squat' | 'weighted_uneven_squat' | 'waist_slimming_squat' | 'wall_ball' | 'wide_stance_barbell_squat' | 'wide_stance_goblet_squat' | 'zercher_squat' | 'kbs_overhead' | 'squat_and_side_kick' | 'squat_jumps_in_n_out' | 'pilates_plie_squats_parallel_turned_out_flat_and_heels' | 'releve_straight_leg_and_knee_bent_with_one_leg_variation' | 'alternating_box_dumbbell_step_ups' | 'dumbbell_overhead_squat_single_arm' | 'dumbbell_squat_snatch' | 'medicine_ball_squat' | 'wall_ball_squat_and_press' | 'squat_american_swing' | 'air_squat' | 'dumbbell_thrusters' | 'overhead_barbell_squat' | number;
|
|
214
214
|
export type StairStepperExerciseName = 'stair_stepper' | number;
|
|
215
215
|
export type StrokeType = 'no_event' | 'other' | 'serve' | 'forehand' | 'backhand' | 'smash' | number;
|
|
216
|
-
export type SubSport = 'generic' | 'treadmill' | 'street' | 'trail' | 'track' | 'spin' | 'indoor_cycling' | 'road' | 'mountain' | 'downhill' | 'recumbent' | 'cyclocross' | 'hand_cycling' | 'track_cycling' | 'indoor_rowing' | 'elliptical' | 'stair_climbing' | 'lap_swimming' | 'open_water' | 'flexibility_training' | 'strength_training' | 'warm_up' | 'match' | 'exercise' | 'challenge' | 'indoor_skiing' | 'cardio_training' | 'indoor_walking' | 'e_bike_fitness' | 'bmx' | 'casual_walking' | 'speed_walking' | 'bike_to_run_transition' | 'run_to_bike_transition' | 'swim_to_bike_transition' | 'atv' | 'motocross' | 'backcountry' | 'resort' | 'rc_drone' | 'wingsuit' | 'whitewater' | 'skate_skiing' | 'yoga' | 'pilates' | 'indoor_running' | 'gravel_cycling' | 'e_bike_mountain' | 'commuting' | 'mixed_surface' | 'navigate' | 'track_me' | 'map' | 'single_gas_diving' | 'multi_gas_diving' | 'gauge_diving' | 'apnea_diving' | 'apnea_hunting' | 'virtual_activity' | 'obstacle' | 'breathing' | 'ccr_diving' | 'sail_race' | 'expedition' | 'ultra' | 'indoor_climbing' | 'bouldering' | 'hiit' | 'indoor_grinding' | 'hunting_with_dogs' | 'amrap' | 'emom' | 'tabata' | 'esport' | 'triathlon' | 'duathlon' | 'brick' | 'swim_run' | 'adventure_race' | 'trucker_workout' | 'pickleball' | 'padel' | 'indoor_wheelchair_walk' | 'indoor_wheelchair_run' | 'indoor_hand_cycling' | 'field' | 'ice' | 'ultimate' | 'platform' | 'squash' | 'badminton' | 'racquetball' | 'table_tennis' | 'overland' | 'trolling_motor' | 'fly_canopy' | 'fly_paraglide' | 'fly_paramotor' | 'fly_pressurized' | 'fly_navigate' | 'fly_timer' | 'fly_altimeter' | 'fly_wx' | 'fly_vfr' | 'fly_ifr' | 'dynamic_apnea' | 'enduro' | 'rucking' | 'rally' | 'pool_triathlon' | 'e_bike_enduro' | 'all' | number;
|
|
216
|
+
export type SubSport = 'generic' | 'treadmill' | 'street' | 'trail' | 'track' | 'spin' | 'indoor_cycling' | 'road' | 'mountain' | 'downhill' | 'recumbent' | 'cyclocross' | 'hand_cycling' | 'track_cycling' | 'indoor_rowing' | 'elliptical' | 'stair_climbing' | 'lap_swimming' | 'open_water' | 'flexibility_training' | 'strength_training' | 'warm_up' | 'match' | 'exercise' | 'challenge' | 'indoor_skiing' | 'cardio_training' | 'indoor_walking' | 'e_bike_fitness' | 'bmx' | 'casual_walking' | 'speed_walking' | 'bike_to_run_transition' | 'run_to_bike_transition' | 'swim_to_bike_transition' | 'atv' | 'motocross' | 'backcountry' | 'resort' | 'rc_drone' | 'wingsuit' | 'whitewater' | 'skate_skiing' | 'yoga' | 'pilates' | 'indoor_running' | 'gravel_cycling' | 'e_bike_mountain' | 'commuting' | 'mixed_surface' | 'navigate' | 'track_me' | 'map' | 'single_gas_diving' | 'multi_gas_diving' | 'gauge_diving' | 'apnea_diving' | 'apnea_hunting' | 'virtual_activity' | 'obstacle' | 'breathing' | 'ccr_diving' | 'sail_race' | 'expedition' | 'ultra' | 'indoor_climbing' | 'bouldering' | 'hiit' | 'indoor_grinding' | 'hunting_with_dogs' | 'amrap' | 'emom' | 'tabata' | 'esport' | 'triathlon' | 'duathlon' | 'brick' | 'swim_run' | 'adventure_race' | 'trucker_workout' | 'pickleball' | 'padel' | 'indoor_wheelchair_walk' | 'indoor_wheelchair_run' | 'indoor_hand_cycling' | 'field' | 'ice' | 'ultimate' | 'platform' | 'squash' | 'badminton' | 'racquetball' | 'table_tennis' | 'overland' | 'trolling_motor' | 'fly_canopy' | 'fly_paraglide' | 'fly_paramotor' | 'fly_pressurized' | 'fly_navigate' | 'fly_timer' | 'fly_altimeter' | 'fly_wx' | 'fly_vfr' | 'fly_ifr' | 'dynamic_apnea' | 'enduro' | 'rucking' | 'rally' | 'pool_triathlon' | 'e_bike_enduro' | 'mountain_enduro' | 'mountain_downhill' | 'all' | number;
|
|
217
217
|
export type SupportedExdScreenLayouts = 'full_screen' | 'half_vertical' | 'half_horizontal' | 'half_vertical_right_split' | 'half_horizontal_bottom_split' | 'full_quarter_split' | 'half_vertical_left_split' | 'half_horizontal_top_split' | number;
|
|
218
218
|
export type SuspensionExerciseName = 'chest_fly' | 'chest_press' | 'crunch' | 'curl' | 'dip' | 'face_pull' | 'glute_bridge' | 'hamstring_curl' | 'hip_drop' | 'inverted_row' | 'knee_drive_jump' | 'knee_to_chest' | 'lat_pullover' | 'lunge' | 'mountain_climber' | 'pendulum' | 'pike' | 'plank' | 'power_pull' | 'pull_up' | 'push_up' | 'reverse_mountain_climber' | 'reverse_plank' | 'rollout' | 'row' | 'side_lunge' | 'side_plank' | 'single_leg_deadlift' | 'single_leg_squat' | 'sit_up' | 'split' | 'squat' | 'squat_jump' | 'tricep_press' | 'y_fly' | number;
|
|
219
219
|
export type SwimStroke = 'freestyle' | 'backstroke' | 'breaststroke' | 'butterfly' | 'drill' | 'mixed' | 'im' | 'im_by_round' | 'rimo' | number;
|
|
@@ -2097,6 +2097,7 @@ export interface ParsedFit {
|
|
|
2097
2097
|
messages?: ParsedMessages;
|
|
2098
2098
|
raw_developer_fields?: ParsedRawDeveloperField[];
|
|
2099
2099
|
raw_messages?: ParsedRawFitMessage[];
|
|
2100
|
+
unmapped_messages?: ParsedRawFitMessage[];
|
|
2100
2101
|
file_creator: ParsedFileCreator;
|
|
2101
2102
|
device_settings: ParsedDeviceSettings;
|
|
2102
2103
|
dive_summary?: ParsedDiveSummary;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Resolves a FIT manufacturer identifier to its canonical profile name. */
|
|
2
|
+
export declare function getFitManufacturerName(value: number | string | null | undefined): string | null;
|
|
3
|
+
/** Resolves a Garmin product identifier to its canonical profile name. */
|
|
4
|
+
export declare function getFitGarminProductName(value: number | string | null | undefined): string | null;
|
|
5
|
+
/** Resolves a FIT sport identifier to its canonical profile name. */
|
|
6
|
+
export declare function getFitSportName(value: number | string | null | undefined): string | null;
|
|
7
|
+
/** Resolves a FIT sub-sport identifier to its canonical profile name. */
|
|
8
|
+
export declare function getFitSubSportName(value: number | string | null | undefined): string | null;
|
|
9
|
+
/** Resolves a FIT sport name to its numeric profile identifier. */
|
|
10
|
+
export declare function getFitSportId(value: string | null | undefined): number | null;
|
|
11
|
+
/** Resolves a FIT sub-sport name to its numeric profile identifier. */
|
|
12
|
+
export declare function getFitSubSportId(value: string | null | undefined): number | null;
|
|
13
|
+
/** Resolves a FIT course-point name to its numeric profile identifier. */
|
|
14
|
+
export declare function getFitCoursePointId(value: string | null | undefined): number | null;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a Garmin product identifier to a human-readable device name.
|
|
17
|
+
* This does not alter parsed `product` or `product_name` fields.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getFitGarminProductDisplayName(value: number | string | null | undefined): string | null;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFitManufacturerName = getFitManufacturerName;
|
|
4
|
+
exports.getFitGarminProductName = getFitGarminProductName;
|
|
5
|
+
exports.getFitSportName = getFitSportName;
|
|
6
|
+
exports.getFitSubSportName = getFitSubSportName;
|
|
7
|
+
exports.getFitSportId = getFitSportId;
|
|
8
|
+
exports.getFitSubSportId = getFitSubSportId;
|
|
9
|
+
exports.getFitCoursePointId = getFitCoursePointId;
|
|
10
|
+
exports.getFitGarminProductDisplayName = getFitGarminProductDisplayName;
|
|
11
|
+
const profile_js_1 = require("./profile.js");
|
|
12
|
+
function normalizeProfileName(value) {
|
|
13
|
+
return value.trim().toLowerCase().replace(/[\s_-]/g, '');
|
|
14
|
+
}
|
|
15
|
+
const FIT_PROFILE_MANUFACTURERS = profile_js_1.PROFILE_TYPES.manufacturer;
|
|
16
|
+
const FIT_PROFILE_GARMIN_PRODUCTS = profile_js_1.PROFILE_TYPES.garmin_product;
|
|
17
|
+
const FIT_PROFILE_SPORTS = profile_js_1.PROFILE_TYPES.sport;
|
|
18
|
+
const FIT_PROFILE_SUB_SPORTS = profile_js_1.PROFILE_TYPES.sub_sport;
|
|
19
|
+
const FIT_PROFILE_COURSE_POINTS = profile_js_1.PROFILE_TYPES.course_point;
|
|
20
|
+
function createProfileIdMap(mapping) {
|
|
21
|
+
return new Map(Object.entries(mapping)
|
|
22
|
+
.filter((entry) => typeof entry[1] === 'string')
|
|
23
|
+
.map(([id, name]) => [normalizeProfileName(name), Number(id)]));
|
|
24
|
+
}
|
|
25
|
+
const FIT_PROFILE_SPORT_IDS = createProfileIdMap(FIT_PROFILE_SPORTS);
|
|
26
|
+
const FIT_PROFILE_SUB_SPORT_IDS = createProfileIdMap(FIT_PROFILE_SUB_SPORTS);
|
|
27
|
+
const FIT_PROFILE_COURSE_POINT_IDS = createProfileIdMap(FIT_PROFILE_COURSE_POINTS);
|
|
28
|
+
function getProfileName(mapping, value) {
|
|
29
|
+
if (value === null || value === undefined) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const normalizedValue = typeof value === 'string' ? value.trim() : value;
|
|
36
|
+
if (normalizedValue === '' || (typeof normalizedValue === 'string' && !/^\d+$/.test(normalizedValue))) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const id = Number(normalizedValue);
|
|
40
|
+
if (!Number.isSafeInteger(id) || id < 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const name = mapping[id];
|
|
44
|
+
return typeof name === 'string' ? name : null;
|
|
45
|
+
}
|
|
46
|
+
function getProfileId(mapping, value) {
|
|
47
|
+
var _a;
|
|
48
|
+
if (typeof value !== 'string') {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const name = normalizeProfileName(value);
|
|
52
|
+
if (name === '') {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return (_a = mapping.get(name)) !== null && _a !== void 0 ? _a : null;
|
|
56
|
+
}
|
|
57
|
+
/** Resolves a FIT manufacturer identifier to its canonical profile name. */
|
|
58
|
+
function getFitManufacturerName(value) {
|
|
59
|
+
return getProfileName(FIT_PROFILE_MANUFACTURERS, value);
|
|
60
|
+
}
|
|
61
|
+
/** Resolves a Garmin product identifier to its canonical profile name. */
|
|
62
|
+
function getFitGarminProductName(value) {
|
|
63
|
+
return getProfileName(FIT_PROFILE_GARMIN_PRODUCTS, value);
|
|
64
|
+
}
|
|
65
|
+
/** Resolves a FIT sport identifier to its canonical profile name. */
|
|
66
|
+
function getFitSportName(value) {
|
|
67
|
+
return getProfileName(FIT_PROFILE_SPORTS, value);
|
|
68
|
+
}
|
|
69
|
+
/** Resolves a FIT sub-sport identifier to its canonical profile name. */
|
|
70
|
+
function getFitSubSportName(value) {
|
|
71
|
+
return getProfileName(FIT_PROFILE_SUB_SPORTS, value);
|
|
72
|
+
}
|
|
73
|
+
/** Resolves a FIT sport name to its numeric profile identifier. */
|
|
74
|
+
function getFitSportId(value) {
|
|
75
|
+
return getProfileId(FIT_PROFILE_SPORT_IDS, value);
|
|
76
|
+
}
|
|
77
|
+
/** Resolves a FIT sub-sport name to its numeric profile identifier. */
|
|
78
|
+
function getFitSubSportId(value) {
|
|
79
|
+
return getProfileId(FIT_PROFILE_SUB_SPORT_IDS, value);
|
|
80
|
+
}
|
|
81
|
+
/** Resolves a FIT course-point name to its numeric profile identifier. */
|
|
82
|
+
function getFitCoursePointId(value) {
|
|
83
|
+
return getProfileId(FIT_PROFILE_COURSE_POINT_IDS, value);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolves a Garmin product identifier to a human-readable device name.
|
|
87
|
+
* This does not alter parsed `product` or `product_name` fields.
|
|
88
|
+
*/
|
|
89
|
+
function getFitGarminProductDisplayName(value) {
|
|
90
|
+
const name = getFitGarminProductName(value);
|
|
91
|
+
if (!name) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// Preserve the established display spelling for the optical heart-rate product.
|
|
95
|
+
const displaySource = name === 'o_hr' ? 'o_h_r' : name;
|
|
96
|
+
const formatted = displaySource
|
|
97
|
+
.replace(/^fr(\d+)/i, 'Forerunner $1')
|
|
98
|
+
.replace(/^fenix(\d+)/i, 'Fenix $1')
|
|
99
|
+
.replace(/^edge(\d+)/i, 'Edge $1')
|
|
100
|
+
.replace(/^vivoactive/i, 'VivoActive')
|
|
101
|
+
.replace(/^vivosmart/i, 'VivoSmart')
|
|
102
|
+
.replace(/^vivofit/i, 'VivoFit')
|
|
103
|
+
.replace(/^vivomove/i, 'VivoMove')
|
|
104
|
+
.replace(/^vivosport/i, 'VivoSport')
|
|
105
|
+
.replace(/^approach([A-Z\d])/i, 'Approach $1')
|
|
106
|
+
.replace(/^marq([A-Z])/i, 'Marq $1')
|
|
107
|
+
.replace(/^hrm/i, 'HRM ')
|
|
108
|
+
.replace(/_/g, ' ')
|
|
109
|
+
.replace(/([a-z])([A-Z0-9])/g, '$1 $2')
|
|
110
|
+
.replace(/(\d)([a-z])/gi, '$1 $2');
|
|
111
|
+
return formatted
|
|
112
|
+
.split(' ')
|
|
113
|
+
.map((word) => {
|
|
114
|
+
const lower = word.toLowerCase();
|
|
115
|
+
if (lower === 'apac')
|
|
116
|
+
return 'APAC';
|
|
117
|
+
if (lower === 'xt')
|
|
118
|
+
return 'XT';
|
|
119
|
+
if (lower === 'lte')
|
|
120
|
+
return 'LTE';
|
|
121
|
+
if (lower === 'hr')
|
|
122
|
+
return 'HR';
|
|
123
|
+
if (lower === 'gps')
|
|
124
|
+
return 'GPS';
|
|
125
|
+
if (lower === 'mtb')
|
|
126
|
+
return 'MTB';
|
|
127
|
+
if (lower === 'ii')
|
|
128
|
+
return 'II';
|
|
129
|
+
if (lower === 'iii')
|
|
130
|
+
return 'III';
|
|
131
|
+
if (lower === 'm' && name.toLowerCase().includes('645m'))
|
|
132
|
+
return 'Music';
|
|
133
|
+
if (lower === 'jpn')
|
|
134
|
+
return 'Japan';
|
|
135
|
+
if (lower === 'chn')
|
|
136
|
+
return 'China';
|
|
137
|
+
if (lower === 'twn')
|
|
138
|
+
return 'Taiwan';
|
|
139
|
+
if (lower === 'kor')
|
|
140
|
+
return 'Korea';
|
|
141
|
+
if (lower === 'rus')
|
|
142
|
+
return 'Russia';
|
|
143
|
+
if (lower === 'sea')
|
|
144
|
+
return 'SEA';
|
|
145
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
146
|
+
})
|
|
147
|
+
.join(' ')
|
|
148
|
+
.replace(/Vivo Active/g, 'VivoActive')
|
|
149
|
+
.trim();
|
|
150
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Message } from './fit.js';
|
|
2
|
+
/**
|
|
3
|
+
* Static, community-maintained FIT interoperability profile.
|
|
4
|
+
*
|
|
5
|
+
* This table is ordinary project source maintained under the repository's MIT
|
|
6
|
+
* license. See PROFILE.md for the maintenance and verification policy.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROFILE_MESSAGES: Record<number, Message>;
|
|
9
|
+
export declare const PROFILE_TYPES: Record<string, Record<number, string | number>>;
|