fit-file-parser 4.1.0 → 5.0.2
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 +59 -0
- package/README.md +90 -1
- package/dist/binary.d.ts +2 -3
- package/dist/binary.js +23 -40
- package/dist/cjs/binary.d.ts +2 -3
- package/dist/cjs/binary.js +23 -40
- package/dist/cjs/fit-parser.js +4 -2
- package/dist/cjs/fit.d.ts +11 -9
- package/dist/cjs/fit.js +123 -9187
- package/dist/cjs/fit_types.d.ts +551 -555
- package/dist/cjs/garmin_profile.generated.js +479 -479
- package/dist/cjs/helper.js +22 -12
- package/dist/cjs/messages.d.ts +2 -3
- package/dist/cjs/type_generator.js +36 -35
- package/dist/fit-parser.js +4 -2
- package/dist/fit.d.ts +11 -9
- package/dist/fit.js +122 -9186
- package/dist/fit_types.d.ts +551 -555
- package/dist/garmin_profile.generated.js +479 -479
- package/dist/helper.js +22 -12
- package/dist/messages.d.ts +2 -3
- package/dist/type_generator.js +36 -35
- package/package.json +1 -1
package/dist/cjs/helper.js
CHANGED
|
@@ -2,21 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mapDataIntoLap = mapDataIntoLap;
|
|
4
4
|
exports.mapDataIntoSession = mapDataIntoSession;
|
|
5
|
+
function timestampValue(value) {
|
|
6
|
+
if (value === undefined || value === null) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const timestamp = value instanceof Date
|
|
10
|
+
? value.getTime()
|
|
11
|
+
: new Date(value).getTime();
|
|
12
|
+
return Number.isFinite(timestamp) ? timestamp : undefined;
|
|
13
|
+
}
|
|
5
14
|
function mapDataIntoLap(inputLaps, lapKey, data) {
|
|
15
|
+
var _a;
|
|
6
16
|
const laps = [...inputLaps];
|
|
7
17
|
let index = 0;
|
|
8
18
|
for (let i = 0; i < laps.length; i++) {
|
|
9
19
|
const nextLap = laps[i + 1];
|
|
10
20
|
const tempData = [];
|
|
11
|
-
const nextLapStartTime = nextLap
|
|
12
|
-
? new Date(nextLap.start_time).getTime()
|
|
13
|
-
: null;
|
|
21
|
+
const nextLapStartTime = timestampValue(nextLap === null || nextLap === void 0 ? void 0 : nextLap.start_time);
|
|
14
22
|
for (let j = index; j < data.length; j++) {
|
|
15
23
|
const row = data[j];
|
|
16
|
-
if (nextLap && nextLapStartTime) {
|
|
17
|
-
const timestamp =
|
|
18
|
-
if (nextLapStartTime > timestamp) {
|
|
24
|
+
if (nextLap && nextLapStartTime !== undefined) {
|
|
25
|
+
const timestamp = timestampValue((_a = row.timestamp) !== null && _a !== void 0 ? _a : row.start_time);
|
|
26
|
+
if (timestamp === undefined || nextLapStartTime > timestamp) {
|
|
19
27
|
tempData.push(row);
|
|
28
|
+
index = j + 1;
|
|
20
29
|
}
|
|
21
30
|
else if (nextLapStartTime <= timestamp) {
|
|
22
31
|
index = j;
|
|
@@ -25,6 +34,7 @@ function mapDataIntoLap(inputLaps, lapKey, data) {
|
|
|
25
34
|
}
|
|
26
35
|
else {
|
|
27
36
|
tempData.push(row);
|
|
37
|
+
index = j + 1;
|
|
28
38
|
}
|
|
29
39
|
}
|
|
30
40
|
if (!laps[i][lapKey]) {
|
|
@@ -39,15 +49,14 @@ function mapDataIntoSession(inputSessions, laps) {
|
|
|
39
49
|
for (let i = 0; i < sessions.length; i++) {
|
|
40
50
|
const nextSession = sessions[i + 1];
|
|
41
51
|
const tempLaps = [];
|
|
42
|
-
const nextSessionStartTime = nextSession
|
|
43
|
-
? new Date(nextSession.start_time).getTime()
|
|
44
|
-
: null;
|
|
52
|
+
const nextSessionStartTime = timestampValue(nextSession === null || nextSession === void 0 ? void 0 : nextSession.start_time);
|
|
45
53
|
for (let j = lapIndex; j < laps.length; j++) {
|
|
46
54
|
const lap = laps[j];
|
|
47
|
-
if (nextSession && nextSessionStartTime) {
|
|
48
|
-
const lapStartTime =
|
|
49
|
-
if (nextSessionStartTime > lapStartTime) {
|
|
55
|
+
if (nextSession && nextSessionStartTime !== undefined) {
|
|
56
|
+
const lapStartTime = timestampValue(lap.start_time);
|
|
57
|
+
if (lapStartTime === undefined || nextSessionStartTime > lapStartTime) {
|
|
50
58
|
tempLaps.push(lap);
|
|
59
|
+
lapIndex = j + 1;
|
|
51
60
|
}
|
|
52
61
|
else if (nextSessionStartTime <= lapStartTime) {
|
|
53
62
|
lapIndex = j;
|
|
@@ -56,6 +65,7 @@ function mapDataIntoSession(inputSessions, laps) {
|
|
|
56
65
|
}
|
|
57
66
|
else {
|
|
58
67
|
tempLaps.push(lap);
|
|
68
|
+
lapIndex = j + 1;
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
if (!sessions[i].laps) {
|
package/dist/cjs/messages.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { MessageObject } from './fit.js';
|
|
2
|
-
import type { MesgNum } from './fit_types.js';
|
|
1
|
+
import type { MessageName, MessageObject } from './fit.js';
|
|
3
2
|
export declare function getFitMessage(messageNum: number): {
|
|
4
|
-
name:
|
|
3
|
+
name: MessageName | '';
|
|
5
4
|
getAttributes: (fieldNum: number) => MessageObject;
|
|
6
5
|
};
|
|
7
6
|
export declare function getFitMessageBaseType(inp: any): any;
|
|
@@ -59,9 +59,15 @@ function generateProperty(name, type, optional = true) {
|
|
|
59
59
|
function generateArrayProperty(name, type, optional = true) {
|
|
60
60
|
return generateProperty(name, typescript_1.default.factory.createArrayTypeNode(type), optional);
|
|
61
61
|
}
|
|
62
|
+
function generateNullableArrayType(type) {
|
|
63
|
+
return typescript_1.default.factory.createArrayTypeNode(typescript_1.default.factory.createParenthesizedType(typescript_1.default.factory.createUnionTypeNode([
|
|
64
|
+
type,
|
|
65
|
+
typescript_1.default.factory.createLiteralTypeNode(typescript_1.default.factory.createNull()),
|
|
66
|
+
])));
|
|
67
|
+
}
|
|
62
68
|
function generateTypeFromField(def) {
|
|
63
69
|
if (def.array === true) {
|
|
64
|
-
return
|
|
70
|
+
return generateNullableArrayType(generateTypeFromField(Object.assign(Object.assign({}, def), { array: false })));
|
|
65
71
|
}
|
|
66
72
|
switch (def.type) {
|
|
67
73
|
case 'uint32_array':
|
|
@@ -71,14 +77,15 @@ function generateTypeFromField(def) {
|
|
|
71
77
|
case 'sint16_array':
|
|
72
78
|
case 'sint8_array':
|
|
73
79
|
case 'byte_array':
|
|
74
|
-
return
|
|
80
|
+
return generateNullableArrayType(typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword));
|
|
75
81
|
case 'exercise_category_array':
|
|
76
|
-
return
|
|
77
|
-
case 'bool':
|
|
78
|
-
return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword);
|
|
82
|
+
return generateNullableArrayType(typescript_1.default.factory.createTypeReferenceNode('ExerciseCategory'));
|
|
79
83
|
case 'date_time':
|
|
84
|
+
case 'local_date_time':
|
|
85
|
+
return typescript_1.default.factory.createTypeReferenceNode('Date');
|
|
80
86
|
case 'string':
|
|
81
87
|
return typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.StringKeyword);
|
|
88
|
+
case 'bool':
|
|
82
89
|
case 'uint32':
|
|
83
90
|
case 'uint64':
|
|
84
91
|
case 'uint16':
|
|
@@ -108,20 +115,30 @@ function generateTypes(types) {
|
|
|
108
115
|
const nodes = [];
|
|
109
116
|
const typeNames = Object.keys(types);
|
|
110
117
|
typeNames.forEach((name) => {
|
|
111
|
-
if (name === 'message_index') {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
118
|
const type = types[name];
|
|
115
|
-
const names = Object.values(type);
|
|
119
|
+
const names = [...new Set(Object.values(type))];
|
|
120
|
+
const isMask = names.includes('mask');
|
|
121
|
+
const typeNode = isMask
|
|
122
|
+
? typescript_1.default.factory.createTypeLiteralNode([
|
|
123
|
+
generateProperty('value', typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword), false),
|
|
124
|
+
...names
|
|
125
|
+
.filter(value => value !== 'mask')
|
|
126
|
+
.map(value => generateProperty(String(value), typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword), false)),
|
|
127
|
+
])
|
|
128
|
+
: names.length === 0
|
|
129
|
+
? typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword)
|
|
130
|
+
: typescript_1.default.factory.createUnionTypeNode([
|
|
131
|
+
...names.map(n => typescript_1.default.factory.createLiteralTypeNode(typescript_1.default.factory.createStringLiteral(String(n)))),
|
|
132
|
+
...(name === 'mesg_num'
|
|
133
|
+
? [
|
|
134
|
+
typescript_1.default.factory.createLiteralTypeNode(typescript_1.default.factory.createStringLiteral('definition')),
|
|
135
|
+
]
|
|
136
|
+
: []),
|
|
137
|
+
typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword),
|
|
138
|
+
]);
|
|
116
139
|
const typeAlias = typescript_1.default.factory.createTypeAliasDeclaration([
|
|
117
140
|
typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ExportKeyword),
|
|
118
|
-
], snakeToCamel(name), undefined,
|
|
119
|
-
? typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword)
|
|
120
|
-
: typescript_1.default.factory.createUnionTypeNode([...names.map(n => typescript_1.default.factory.createLiteralTypeNode(typescript_1.default.factory.createStringLiteral(String(n)))), ...(name === 'mesg_num'
|
|
121
|
-
? [
|
|
122
|
-
typescript_1.default.factory.createLiteralTypeNode(typescript_1.default.factory.createStringLiteral('definition')),
|
|
123
|
-
]
|
|
124
|
-
: [])]));
|
|
141
|
+
], snakeToCamel(name), undefined, typeNode);
|
|
125
142
|
nodes.push(typeAlias);
|
|
126
143
|
});
|
|
127
144
|
return nodes;
|
|
@@ -158,13 +175,6 @@ function generateUtilities() {
|
|
|
158
175
|
]),
|
|
159
176
|
]));
|
|
160
177
|
nodes.push(unitType);
|
|
161
|
-
const messageIndex = typescript_1.default.factory.createInterfaceDeclaration([typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ExportKeyword)], 'MessageIndex', undefined, undefined, [
|
|
162
|
-
generateProperty('0', typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword), false),
|
|
163
|
-
generateProperty('value', typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword), false),
|
|
164
|
-
generateProperty('reserved', typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword), false),
|
|
165
|
-
generateProperty('selected', typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword), false),
|
|
166
|
-
]);
|
|
167
|
-
nodes.push(messageIndex);
|
|
168
178
|
return nodes;
|
|
169
179
|
}
|
|
170
180
|
function generateAdditionalFields(msg) {
|
|
@@ -262,22 +272,13 @@ function generateMessages(messages) {
|
|
|
262
272
|
const nodes = [];
|
|
263
273
|
Object.keys(messages).forEach((name) => {
|
|
264
274
|
const msg = fit_js_1.FIT.messages[Number(name)];
|
|
265
|
-
const usedFields = new Set();
|
|
266
275
|
const messageType = typescript_1.default.factory.createInterfaceDeclaration([
|
|
267
276
|
typescript_1.default.factory.createModifier(typescript_1.default.SyntaxKind.ExportKeyword),
|
|
268
277
|
], snakeToCamel(`parsed_${msg.name}`), undefined, undefined, [
|
|
269
|
-
...Object.keys(msg).filter(n => n !== 'name').
|
|
270
|
-
var _a;
|
|
278
|
+
...Object.keys(msg).filter(n => n !== 'name').map((id) => {
|
|
271
279
|
const def = msg[Number(id)];
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (!usedFields.has(definition.field)) {
|
|
275
|
-
usedFields.add(definition.field);
|
|
276
|
-
acc.push(generateProperty(definition.field, generateTypeFromField(definition), !['start_time', 'timestamp'].includes(definition.field)));
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
return acc;
|
|
280
|
-
}, []),
|
|
280
|
+
return generateProperty(def.field, generateTypeFromField(def));
|
|
281
|
+
}),
|
|
281
282
|
...generateAdditionalFields(msg),
|
|
282
283
|
]);
|
|
283
284
|
nodes.push(messageType);
|
package/dist/fit-parser.js
CHANGED
|
@@ -163,8 +163,10 @@ export default class FitParser {
|
|
|
163
163
|
case 'record':
|
|
164
164
|
if (!startDate) {
|
|
165
165
|
startDate = message.timestamp;
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
if (this.options.elapsedRecordField) {
|
|
167
|
+
message.elapsed_time = 0;
|
|
168
|
+
message.timer_time = 0;
|
|
169
|
+
}
|
|
168
170
|
}
|
|
169
171
|
records.push(message);
|
|
170
172
|
break;
|
package/dist/fit.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FitOptions, MesgNum } from './fit_types.js';
|
|
2
|
+
export type MessageName = Exclude<MesgNum, number | 'definition'>;
|
|
2
3
|
export interface FieldDefinition {
|
|
3
4
|
type: string | number;
|
|
4
5
|
rawType?: string | number;
|
|
@@ -12,10 +13,10 @@ export interface FieldDefinition {
|
|
|
12
13
|
dataType: string;
|
|
13
14
|
scale?: number | null;
|
|
14
15
|
offset?: number;
|
|
16
|
+
units?: string;
|
|
15
17
|
requiresBoundedDataView?: boolean;
|
|
16
18
|
developerDataIndex?: number;
|
|
17
19
|
isDeveloperField?: boolean;
|
|
18
|
-
aliases?: MessageObject[];
|
|
19
20
|
}
|
|
20
21
|
export interface MessageObject {
|
|
21
22
|
field: string;
|
|
@@ -25,20 +26,21 @@ export interface MessageObject {
|
|
|
25
26
|
scale: number | null;
|
|
26
27
|
offset: number;
|
|
27
28
|
units: string;
|
|
28
|
-
aliases?: MessageObject[];
|
|
29
29
|
}
|
|
30
30
|
export interface Message {
|
|
31
|
-
name:
|
|
31
|
+
name: MessageName;
|
|
32
32
|
[fieldId: number]: MessageObject;
|
|
33
33
|
}
|
|
34
34
|
export interface FitType {
|
|
35
35
|
scConst: number;
|
|
36
36
|
options: FitOptions;
|
|
37
|
-
messages:
|
|
38
|
-
|
|
39
|
-
};
|
|
40
|
-
types: {
|
|
41
|
-
[typeName: string]: Record<number, string | number>;
|
|
42
|
-
};
|
|
37
|
+
messages: Record<number, Message>;
|
|
38
|
+
types: Record<string, Record<number, string | number>>;
|
|
43
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>>;
|
|
44
46
|
export declare const FIT: FitType;
|