fit-file-parser 4.0.1 → 4.1.0
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 +48 -0
- package/README.md +190 -119
- package/dist/binary.d.ts +13 -1
- package/dist/binary.js +285 -164
- package/dist/cjs/binary.d.ts +13 -1
- package/dist/cjs/binary.js +285 -164
- package/dist/cjs/fit-parser.js +37 -19
- package/dist/cjs/fit.d.ts +6 -0
- package/dist/cjs/fit.js +167 -44
- package/dist/cjs/fit_types.d.ts +1297 -207
- package/dist/cjs/garmin_profile.generated.d.ts +9 -0
- package/dist/cjs/garmin_profile.generated.js +17838 -0
- package/dist/cjs/type_generator.d.ts +3 -0
- package/dist/cjs/type_generator.js +37 -9
- package/dist/fit-parser.js +37 -19
- package/dist/fit.d.ts +6 -0
- package/dist/fit.js +167 -44
- package/dist/fit_types.d.ts +1297 -207
- package/dist/garmin_profile.generated.d.ts +9 -0
- package/dist/garmin_profile.generated.js +17835 -0
- package/dist/type_generator.d.ts +3 -0
- package/dist/type_generator.js +36 -9
- package/package.json +9 -6
package/dist/type_generator.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ export declare function generateOptions(options: {
|
|
|
19
19
|
}): ts.Node[];
|
|
20
20
|
export declare function generateUtilities(): Statement[];
|
|
21
21
|
export declare function generateFitType(): Statement;
|
|
22
|
+
export declare function generateParsedMessages(messages: {
|
|
23
|
+
[messageId: number]: Message;
|
|
24
|
+
}): Statement;
|
|
22
25
|
export declare function generateMessages(messages: {
|
|
23
26
|
[messageId: number]: Message;
|
|
24
27
|
}): Statement[];
|
package/dist/type_generator.js
CHANGED
|
@@ -39,6 +39,9 @@ export function generateArrayProperty(name, type, optional = true) {
|
|
|
39
39
|
return generateProperty(name, ts.factory.createArrayTypeNode(type), optional);
|
|
40
40
|
}
|
|
41
41
|
export function generateTypeFromField(def) {
|
|
42
|
+
if (def.array === true) {
|
|
43
|
+
return ts.factory.createArrayTypeNode(generateTypeFromField(Object.assign(Object.assign({}, def), { array: false })));
|
|
44
|
+
}
|
|
42
45
|
switch (def.type) {
|
|
43
46
|
case 'uint32_array':
|
|
44
47
|
case 'uint16_array':
|
|
@@ -48,6 +51,8 @@ export function generateTypeFromField(def) {
|
|
|
48
51
|
case 'sint8_array':
|
|
49
52
|
case 'byte_array':
|
|
50
53
|
return ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
|
|
54
|
+
case 'exercise_category_array':
|
|
55
|
+
return ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode('ExerciseCategory'));
|
|
51
56
|
case 'bool':
|
|
52
57
|
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
53
58
|
case 'date_time':
|
|
@@ -89,11 +94,13 @@ export function generateTypes(types) {
|
|
|
89
94
|
const names = Object.values(type);
|
|
90
95
|
const typeAlias = ts.factory.createTypeAliasDeclaration([
|
|
91
96
|
ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
|
|
92
|
-
], snakeToCamel(name), undefined,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
], snakeToCamel(name), undefined, names.length === 0
|
|
98
|
+
? ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
|
|
99
|
+
: ts.factory.createUnionTypeNode([...names.map(n => ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(String(n)))), ...(name === 'mesg_num'
|
|
100
|
+
? [
|
|
101
|
+
ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('definition')),
|
|
102
|
+
]
|
|
103
|
+
: [])]));
|
|
97
104
|
nodes.push(typeAlias);
|
|
98
105
|
});
|
|
99
106
|
return nodes;
|
|
@@ -160,6 +167,7 @@ function generateAdditionalFields(msg) {
|
|
|
160
167
|
developer_data_ids: 'parsed_developer_data_id',
|
|
161
168
|
field_descriptions: 'parsed_field_description',
|
|
162
169
|
sports: 'parsed_sport',
|
|
170
|
+
sets: 'parsed_set',
|
|
163
171
|
splits: 'parsed_split',
|
|
164
172
|
split_summaries: 'parsed_split_summary',
|
|
165
173
|
};
|
|
@@ -191,6 +199,7 @@ export function generateFitType() {
|
|
|
191
199
|
tank_updates: 'parsed_tank_update',
|
|
192
200
|
tank_summaries: 'parsed_tank_summary',
|
|
193
201
|
jumps: 'parsed_jump',
|
|
202
|
+
sets: 'parsed_set',
|
|
194
203
|
splits: 'parsed_split',
|
|
195
204
|
split_summaries: 'parsed_split_summary',
|
|
196
205
|
time_in_zone: 'parsed_time_in_zone',
|
|
@@ -207,15 +216,27 @@ export function generateFitType() {
|
|
|
207
216
|
activity: 'parsed_activity',
|
|
208
217
|
zones_target: '?parsed_zones_target',
|
|
209
218
|
};
|
|
219
|
+
const existingMessageNames = new Set([
|
|
220
|
+
...Object.values(collectionProperties),
|
|
221
|
+
...Object.values(referenceProperties),
|
|
222
|
+
].map(name => name.replace('?', '').replace(/^parsed_/, '')));
|
|
223
|
+
const additionalReferenceProperties = Object.values(FIT.messages)
|
|
224
|
+
.filter(message => !existingMessageNames.has(message.name))
|
|
225
|
+
.map(message => generateProperty(message.name, ts.factory.createTypeReferenceNode(snakeToCamel(`parsed_${message.name}`))));
|
|
210
226
|
return ts.factory.createInterfaceDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], 'ParsedFit', undefined, undefined, [
|
|
211
227
|
generateProperty('protocolVersion', ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
|
|
212
228
|
generateProperty('profileVersion', ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
|
|
229
|
+
generateProperty('messages', ts.factory.createTypeReferenceNode('ParsedMessages')),
|
|
213
230
|
...Object.keys(referenceProperties).map(prop => generateProperty(prop, ts.factory.createTypeReferenceNode(snakeToCamel(referenceProperties[prop].replace('?', ''))), referenceProperties[prop].startsWith('?'))),
|
|
214
231
|
...Object.keys(collectionProperties).map(prop => generateArrayProperty(prop, collectionProperties[prop] === 'unknown'
|
|
215
232
|
? ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)
|
|
216
233
|
: ts.factory.createTypeReferenceNode(snakeToCamel(collectionProperties[prop])))),
|
|
234
|
+
...additionalReferenceProperties,
|
|
217
235
|
]);
|
|
218
236
|
}
|
|
237
|
+
export function generateParsedMessages(messages) {
|
|
238
|
+
return ts.factory.createInterfaceDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], 'ParsedMessages', undefined, undefined, Object.values(messages).map(message => generateArrayProperty(message.name, ts.factory.createTypeReferenceNode(snakeToCamel(`parsed_${message.name}`)))));
|
|
239
|
+
}
|
|
219
240
|
export function generateMessages(messages) {
|
|
220
241
|
const nodes = [];
|
|
221
242
|
Object.keys(messages).forEach((name) => {
|
|
@@ -225,11 +246,15 @@ export function generateMessages(messages) {
|
|
|
225
246
|
ts.factory.createModifier(ts.SyntaxKind.ExportKeyword),
|
|
226
247
|
], snakeToCamel(`parsed_${msg.name}`), undefined, undefined, [
|
|
227
248
|
...Object.keys(msg).filter(n => n !== 'name').reduce((acc, id) => {
|
|
249
|
+
var _a;
|
|
228
250
|
const def = msg[Number(id)];
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
251
|
+
const definitions = [def, ...((_a = def.aliases) !== null && _a !== void 0 ? _a : [])];
|
|
252
|
+
definitions.forEach((definition) => {
|
|
253
|
+
if (!usedFields.has(definition.field)) {
|
|
254
|
+
usedFields.add(definition.field);
|
|
255
|
+
acc.push(generateProperty(definition.field, generateTypeFromField(definition), !['start_time', 'timestamp'].includes(definition.field)));
|
|
256
|
+
}
|
|
257
|
+
});
|
|
233
258
|
return acc;
|
|
234
259
|
}, []),
|
|
235
260
|
...generateAdditionalFields(msg),
|
|
@@ -251,6 +276,8 @@ export function main() {
|
|
|
251
276
|
nodes.push(...generateOptions(FIT.options));
|
|
252
277
|
nodes.push(...comment('parsed from Fit.messages'));
|
|
253
278
|
nodes.push(...generateMessages(FIT.messages));
|
|
279
|
+
nodes.push(...comment('all recognized messages, retained in file order'));
|
|
280
|
+
nodes.push(generateParsedMessages(FIT.messages));
|
|
254
281
|
nodes.push(...comment('the returned type after parsing a .fit file'));
|
|
255
282
|
nodes.push(generateFitType());
|
|
256
283
|
const nodesArray = ts.factory.createNodeArray(nodes);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fit-file-parser",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0
|
|
4
|
+
"version": "4.1.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Parse your .FIT files easily, directly from JS (Garmin, Polar, Suunto)",
|
|
7
7
|
"author": {
|
|
@@ -54,10 +54,13 @@
|
|
|
54
54
|
}
|
|
55
55
|
],
|
|
56
56
|
"scripts": {
|
|
57
|
-
"dev": "tsx --watch --watch-path=src/type_generator.ts --watch-path=src/fit.ts codegen/codegen.ts",
|
|
58
|
-
"codegen": "tsx codegen/
|
|
59
|
-
"codegen:
|
|
60
|
-
"check": "
|
|
57
|
+
"dev": "tsx --watch --watch-path=src/type_generator.ts --watch-path=src/fit.ts --watch-path=src/garmin_profile.generated.ts codegen/codegen.ts",
|
|
58
|
+
"codegen:profile": "tsx codegen/garmin-profile.ts",
|
|
59
|
+
"codegen": "npm run codegen:profile && tsx codegen/codegen.ts",
|
|
60
|
+
"codegen:check": "tsx codegen/garmin-profile.ts --check && tsx codegen/codegen.ts --check",
|
|
61
|
+
"profile:audit": "npm run codegen:check && tsx scripts/profile-audit.ts",
|
|
62
|
+
"corpus:check": "tsx scripts/corpus-check.ts",
|
|
63
|
+
"check": "npm run profile:audit && npm run lint && npm run type-check && npm test -- --run && npm run build",
|
|
61
64
|
"example-output": "node examples/parse.js examples/example.fit > examples/output-example.json",
|
|
62
65
|
"example-output-tank": "node examples/parse.js examples/example-diving.fit > examples/output-diving.json",
|
|
63
66
|
"example-output-summary-first": "node examples/parse.js examples/triathlon_summary_first.fit > examples/output_summary_first.json",
|
|
@@ -77,7 +80,7 @@
|
|
|
77
80
|
},
|
|
78
81
|
"devDependencies": {
|
|
79
82
|
"@antfu/eslint-config": "^6.2.0",
|
|
80
|
-
"@garmin/fitsdk": "
|
|
83
|
+
"@garmin/fitsdk": "21.208.0",
|
|
81
84
|
"@types/node": "^24.10.1",
|
|
82
85
|
"@vitest/coverage-v8": "^4.0.13",
|
|
83
86
|
"eslint": "^9.10.0",
|