@garmin/fitsdk 21.202.0 → 21.205.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/package.json +24 -22
- package/src/accumulator.js +2 -2
- package/src/bit-stream.js +56 -9
- package/src/crc-calculator.js +2 -2
- package/src/decoder.js +43 -81
- package/src/encoder.js +2 -39
- package/src/fit.js +5 -2
- package/src/index.d.ts +22 -0
- package/src/index.js +2 -2
- package/src/mesg-definition.js +2 -2
- package/src/output-stream.js +2 -2
- package/src/profile.js +8 -4
- package/src/stream.js +107 -90
- package/src/types/crc-calculator.d.ts +34 -0
- package/src/types/decoder.d.ts +140 -0
- package/src/types/encoder.d.ts +69 -0
- package/src/types/mesg.d.ts +35 -0
- package/src/types/mesgs.d.ts +2638 -0
- package/src/types/profile.d.ts +96 -0
- package/src/types/stream.d.ts +118 -0
- package/src/types/types.d.ts +4871 -0
- package/src/types/utils.d.ts +55 -0
- package/src/utils-hr-mesg.js +2 -2
- package/src/utils-internal.js +14 -6
- package/src/utils-memo-glob.js +2 -2
- package/src/utils.js +2 -16
package/package.json
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
2
|
+
"name": "@garmin/fitsdk",
|
|
3
|
+
"version": "21.205.0",
|
|
4
|
+
"description": "FIT JavaScript SDK",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "vitest run --silent=passed-only --typecheck"
|
|
10
|
+
},
|
|
11
|
+
"author": "Garmin International, Inc.",
|
|
12
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/garmin/fit-javascript-sdk"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"src/"
|
|
19
|
+
],
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^22.0.0",
|
|
22
|
+
"typescript": "^5.0.0",
|
|
23
|
+
"vitest": "^4.1.5"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/accumulator.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/bit-stream.js
CHANGED
|
@@ -5,25 +5,28 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
import FIT from "./fit.js";
|
|
14
14
|
|
|
15
15
|
class BitStream {
|
|
16
|
+
#data = null;
|
|
16
17
|
#array = null;
|
|
17
18
|
#currentArrayPosition = 0;
|
|
18
19
|
#bitPerPosition = 0;
|
|
20
|
+
#isBigInt = false;
|
|
19
21
|
#currentByte = 0;
|
|
20
22
|
#currentBit = 0;
|
|
21
23
|
#bitsAvailable = 0;
|
|
22
24
|
|
|
23
25
|
constructor(data, baseType = FIT.BaseType.UINT8) {
|
|
24
|
-
this.#
|
|
26
|
+
this.#data = Array.isArray(data) ? data : [data];
|
|
25
27
|
const baseTypeSize = FIT.BaseTypeDefinitions[baseType].size;
|
|
26
28
|
this.#bitPerPosition = baseTypeSize * 8;
|
|
29
|
+
this.#isBigInt = this.#bitPerPosition > 32;
|
|
27
30
|
this.reset();
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -36,9 +39,11 @@ class BitStream {
|
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
reset() {
|
|
42
|
+
this.#array = null;
|
|
39
43
|
this.#currentArrayPosition = 0;
|
|
40
|
-
this.#bitsAvailable = this.#bitPerPosition * this.#
|
|
41
|
-
this.#
|
|
44
|
+
this.#bitsAvailable = this.#bitPerPosition * this.#data.length;
|
|
45
|
+
this.#currentByte = 0;
|
|
46
|
+
this.#currentBit = 0;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
readBit() {
|
|
@@ -46,12 +51,24 @@ class BitStream {
|
|
|
46
51
|
this.#throwError();
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
if (this.#array === null) {
|
|
55
|
+
this.#array = this.#data;
|
|
56
|
+
this.#currentArrayPosition = this.#data.length - (this.#bitsAvailable / this.#bitPerPosition);
|
|
57
|
+
this.#nextByte();
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
if (this.#currentBit >= this.#bitPerPosition) {
|
|
50
61
|
this.#nextByte();
|
|
51
62
|
}
|
|
52
63
|
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
let bit;
|
|
65
|
+
if (this.#isBigInt) {
|
|
66
|
+
bit = Number(this.#currentByte & 1n);
|
|
67
|
+
this.#currentByte >>= 1n;
|
|
68
|
+
} else {
|
|
69
|
+
bit = this.#currentByte & 0x01;
|
|
70
|
+
this.#currentByte >>= 1;
|
|
71
|
+
}
|
|
55
72
|
this.#currentBit++;
|
|
56
73
|
this.#bitsAvailable--;
|
|
57
74
|
|
|
@@ -59,10 +76,36 @@ class BitStream {
|
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
readBits(nBitsToRead) {
|
|
79
|
+
// Fast path: reading exactly one value's worth of bits and #array not yet initialized
|
|
80
|
+
if (nBitsToRead === this.#bitPerPosition && this.#array === null) {
|
|
81
|
+
if (!this.hasBitsAvailable) {
|
|
82
|
+
this.#throwError();
|
|
83
|
+
}
|
|
84
|
+
const index = this.#data.length - (this.#bitsAvailable / this.#bitPerPosition);
|
|
85
|
+
const value = this.#data[index];
|
|
86
|
+
this.#bitsAvailable -= nBitsToRead;
|
|
87
|
+
|
|
88
|
+
if (this.#isBigInt) {
|
|
89
|
+
return Number(BigInt.asUintN(nBitsToRead, value));
|
|
90
|
+
}
|
|
91
|
+
if (nBitsToRead < 32) {
|
|
92
|
+
return (value & ((1 << nBitsToRead) - 1)) >>> 0;
|
|
93
|
+
}
|
|
94
|
+
return value >>> 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (nBitsToRead <= 32) {
|
|
98
|
+
let value = 0;
|
|
99
|
+
for (let i = 0; i < nBitsToRead; i++) {
|
|
100
|
+
value |= this.readBit() << i;
|
|
101
|
+
}
|
|
102
|
+
return value >>> 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
62
105
|
let value = 0n;
|
|
63
106
|
|
|
64
|
-
for (let i = 0n; i < nBitsToRead; i++) {
|
|
65
|
-
value |= BigInt(this.readBit()) <<
|
|
107
|
+
for (let i = 0, shift = 0n; i < nBitsToRead; i++, shift++) {
|
|
108
|
+
value |= BigInt(this.readBit()) << shift;
|
|
66
109
|
}
|
|
67
110
|
|
|
68
111
|
return Number(value);
|
|
@@ -77,6 +120,10 @@ class BitStream {
|
|
|
77
120
|
this.#currentBit = 0;
|
|
78
121
|
}
|
|
79
122
|
|
|
123
|
+
get array() {
|
|
124
|
+
return this.#array;
|
|
125
|
+
}
|
|
126
|
+
|
|
80
127
|
#throwError(error = "") {
|
|
81
128
|
throw Error("FIT Runtime Error no bits available.");
|
|
82
129
|
}
|
package/src/crc-calculator.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/decoder.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -61,12 +61,8 @@ class Decoder {
|
|
|
61
61
|
#optIncludeUnknownData = false;
|
|
62
62
|
#optMergeHeartRates = true;
|
|
63
63
|
#optDecodeMemoGlobs = false;
|
|
64
|
+
#optLegacyArrayMode = false;
|
|
64
65
|
|
|
65
|
-
/**
|
|
66
|
-
* Creates a FIT File Decoder
|
|
67
|
-
* @constructor
|
|
68
|
-
* @param {Stream} stream - representing the FIT file to decode
|
|
69
|
-
*/
|
|
70
66
|
constructor(stream) {
|
|
71
67
|
if (stream == null) {
|
|
72
68
|
throw Error("FIT Runtime Error stream parameter is null or undefined");
|
|
@@ -75,12 +71,6 @@ class Decoder {
|
|
|
75
71
|
this.#stream = stream;
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
/**
|
|
79
|
-
* Inspects the file header to determine if the input stream is a FIT file
|
|
80
|
-
* @param {Stream} stream
|
|
81
|
-
* @returns {Boolean} True if the stream is a FIT file
|
|
82
|
-
* @static
|
|
83
|
-
*/
|
|
84
74
|
static isFIT(stream) {
|
|
85
75
|
try {
|
|
86
76
|
const fileHeaderSize = stream.peekByte();
|
|
@@ -104,18 +94,10 @@ class Decoder {
|
|
|
104
94
|
return true;
|
|
105
95
|
}
|
|
106
96
|
|
|
107
|
-
/**
|
|
108
|
-
* Inspects the file header to determine if the input stream is a FIT file
|
|
109
|
-
* @returns {Boolean} True if the stream is a FIT file
|
|
110
|
-
*/
|
|
111
97
|
isFIT() {
|
|
112
98
|
return Decoder.isFIT(this.#stream);
|
|
113
99
|
}
|
|
114
100
|
|
|
115
|
-
/**
|
|
116
|
-
* Checks that the input stream is a FIT file and verifies both the header and file CRC values
|
|
117
|
-
* @returns {Boolean} True if the stream passes the isFit() and CRC checks
|
|
118
|
-
*/
|
|
119
101
|
checkIntegrity() {
|
|
120
102
|
try {
|
|
121
103
|
if (!this.isFIT()) {
|
|
@@ -128,7 +110,7 @@ class Decoder {
|
|
|
128
110
|
return false;
|
|
129
111
|
}
|
|
130
112
|
|
|
131
|
-
const buf =
|
|
113
|
+
const buf = this.#stream.asUint8Array();
|
|
132
114
|
|
|
133
115
|
if (fileHeader.headerSize === HEADER_WITH_CRC_SIZE && fileHeader.headerCRC !== 0x0000
|
|
134
116
|
&& fileHeader.headerCRC != CrcCalculator.calculateCRC(buf, 0, 12)) {
|
|
@@ -147,48 +129,6 @@ class Decoder {
|
|
|
147
129
|
return true;
|
|
148
130
|
}
|
|
149
131
|
|
|
150
|
-
/**
|
|
151
|
-
* Message Listener Callback
|
|
152
|
-
*
|
|
153
|
-
* @callback Decoder~mesgListener
|
|
154
|
-
* @param {Number} mesgNum - Profile.MesgNum
|
|
155
|
-
* @param {Object} message - The message
|
|
156
|
-
*/
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Message Definition Listener Callback
|
|
160
|
-
*
|
|
161
|
-
* @callback Decoder~mesgDefinitionListener
|
|
162
|
-
* @param {Object} messageDefinition - The message Definition
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Developer Field Description Listener Callback
|
|
167
|
-
*
|
|
168
|
-
* @callback Decoder~fieldDescriptionListener
|
|
169
|
-
* @param {Number} key - The key associated with this pairing of of Developer Data Id and Field Description Mesgs
|
|
170
|
-
* @param {Object} developerDataIdMesg - The Developer Data Id Mesg associated with this pairing
|
|
171
|
-
* @param {Object} fieldDescriptionMesg - The Field Description Mesg associated with this pairing
|
|
172
|
-
*/
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Read the messages from the stream.
|
|
176
|
-
* @param {Object=} [options] - Read options (optional)
|
|
177
|
-
* @param {Decoder~mesgListener} [options.mesgListener=null] - (optional, default null) mesgListener(mesgNum, message)
|
|
178
|
-
* @param {Decoder~mesgDefinitionListener} [options.mesgDefinitionListener=null] - (optional, default null) mesgDefinitionListener(mesgDefinition)
|
|
179
|
-
* @param {Decoder~fieldDescriptionListener} [options.fieldDescriptionListener=null] - (optional, default null) fieldDescriptionListener(key, developerDataIdMesg, fieldDescriptionMesg)
|
|
180
|
-
* @param {Boolean} [options.expandSubFields=true] - (optional, default true)
|
|
181
|
-
* @param {Boolean} [options.expandComponents=true] - (optional, default true)
|
|
182
|
-
* @param {Boolean} [options.applyScaleAndOffset=true] - (optional, default true)
|
|
183
|
-
* @param {Boolean} [options.convertTypesToStrings=true] - (optional, default true)
|
|
184
|
-
* @param {boolean} [options.convertDateTimesToDates=true] - (optional, default true)
|
|
185
|
-
* @param {Boolean} [options.includeUnknownData=false] - (optional, default false)
|
|
186
|
-
* @param {boolean} [options.mergeHeartRates=true] - (optional, default true)
|
|
187
|
-
* @param {boolean} [options.decodeMemoGlobs=true] - (optional, default false)
|
|
188
|
-
* @param {boolean} [options.skipHeader=false] - (optional, default false)
|
|
189
|
-
* @param {boolean} [options.dataOnly=false] - (optional, default false)
|
|
190
|
-
* @return {Object} result - {messages:Array, errors:Array}
|
|
191
|
-
*/
|
|
192
132
|
read({
|
|
193
133
|
mesgListener = null,
|
|
194
134
|
mesgDefinitionListener = null,
|
|
@@ -202,7 +142,8 @@ class Decoder {
|
|
|
202
142
|
mergeHeartRates = true,
|
|
203
143
|
decodeMemoGlobs = false,
|
|
204
144
|
skipHeader = false,
|
|
205
|
-
dataOnly = false,
|
|
145
|
+
dataOnly = false,
|
|
146
|
+
legacyArrayMode = false, } = {}) {
|
|
206
147
|
|
|
207
148
|
this.#mesgListener = mesgListener;
|
|
208
149
|
this.#mesgDefinitionListener = mesgDefinitionListener;
|
|
@@ -215,6 +156,7 @@ class Decoder {
|
|
|
215
156
|
this.#optIncludeUnknownData = includeUnknownData;
|
|
216
157
|
this.#optMergeHeartRates = mergeHeartRates;
|
|
217
158
|
this.#optDecodeMemoGlobs = decodeMemoGlobs;
|
|
159
|
+
this.#optLegacyArrayMode = legacyArrayMode;
|
|
218
160
|
|
|
219
161
|
this.#localMessageDefinitions = [];
|
|
220
162
|
this.#developerDataDefinitions = {};
|
|
@@ -224,6 +166,10 @@ class Decoder {
|
|
|
224
166
|
const errors = [];
|
|
225
167
|
|
|
226
168
|
try {
|
|
169
|
+
if (this.#optLegacyArrayMode) {
|
|
170
|
+
console.log("Decoder Warning: legacyArrayMode is deprecated and will be removed in the future. Afterwards, the default behavior will be equivalent to legacyArrayMode=false.");
|
|
171
|
+
}
|
|
172
|
+
|
|
227
173
|
if (this.#optMergeHeartRates && (!this.#optApplyScaleAndOffset || !this.#optExpandComponents)) {
|
|
228
174
|
this.#throwError("mergeHeartRates requires applyScaleAndOffset and expandComponents to be enabled");
|
|
229
175
|
}
|
|
@@ -233,6 +179,7 @@ class Decoder {
|
|
|
233
179
|
}
|
|
234
180
|
|
|
235
181
|
this.#decodeMode = skipHeader ? DecodeMode.SKIP_HEADER : dataOnly ? DecodeMode.DATA_ONLY : DecodeMode.NORMAL;
|
|
182
|
+
this.#stream.legacyArrayMode = this.#optLegacyArrayMode;
|
|
236
183
|
|
|
237
184
|
while (this.#stream.position < this.#stream.length) {
|
|
238
185
|
this.#decodeNextFile();
|
|
@@ -304,9 +251,9 @@ class Decoder {
|
|
|
304
251
|
messageDefinition["reserved"] = this.#stream.readByte();
|
|
305
252
|
|
|
306
253
|
messageDefinition["architecture"] = this.#stream.readByte();
|
|
307
|
-
messageDefinition["endianness"] = messageDefinition.architecture === 0
|
|
254
|
+
messageDefinition["endianness"] = messageDefinition.architecture === 0;
|
|
308
255
|
|
|
309
|
-
messageDefinition["globalMessageNumber"] = this.#stream.readUInt16({
|
|
256
|
+
messageDefinition["globalMessageNumber"] = this.#stream.readUInt16({ littleEndian: messageDefinition["endianness"] });
|
|
310
257
|
messageDefinition["numFields"] = this.#stream.readByte();
|
|
311
258
|
messageDefinition["fieldDefinitions"] = [];
|
|
312
259
|
messageDefinition["developerFieldDefinitions"] = [];
|
|
@@ -346,7 +293,7 @@ class Decoder {
|
|
|
346
293
|
}
|
|
347
294
|
}
|
|
348
295
|
|
|
349
|
-
this.#mesgDefinitionListener?.({...messageDefinition});
|
|
296
|
+
this.#mesgDefinitionListener?.({ ...messageDefinition });
|
|
350
297
|
|
|
351
298
|
let messageProfile = Profile.messages[messageDefinition.globalMessageNumber];
|
|
352
299
|
|
|
@@ -417,7 +364,7 @@ class Decoder {
|
|
|
417
364
|
developerFieldDefinition["invalidValue"] = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType].invalid;
|
|
418
365
|
developerFieldDefinition["baseTypeSize"] = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType].size;
|
|
419
366
|
|
|
420
|
-
const
|
|
367
|
+
const fieldValue = this.#readDeveloperFieldValue(messageDefinition, developerFieldDefinition, field);
|
|
421
368
|
|
|
422
369
|
if (fieldValue != null) {
|
|
423
370
|
developerFields[field.key] = fieldValue;
|
|
@@ -458,7 +405,7 @@ class Decoder {
|
|
|
458
405
|
return developerDataIdMesg.developerDataIndex === message.developerDataIndex;
|
|
459
406
|
}) ?? {};
|
|
460
407
|
|
|
461
|
-
this.#fieldDescriptionListener(message.key, {...developerDataIdMesg}, {...message});
|
|
408
|
+
this.#fieldDescriptionListener(message.key, { ...developerDataIdMesg }, { ...message });
|
|
462
409
|
}
|
|
463
410
|
}
|
|
464
411
|
}
|
|
@@ -485,10 +432,22 @@ class Decoder {
|
|
|
485
432
|
fieldDefinition.baseType,
|
|
486
433
|
fieldDefinition.size,
|
|
487
434
|
{
|
|
488
|
-
|
|
489
|
-
convertInvalidToNull: !field?.hasComponents ?? false
|
|
490
|
-
|
|
435
|
+
littleEndian: messageDefinition["endianness"],
|
|
436
|
+
convertInvalidToNull: !field?.hasComponents ?? false,
|
|
437
|
+
isArray: field?.array ?? fieldDefinition.size > fieldDefinition.baseTypeSize,
|
|
438
|
+
},
|
|
491
439
|
);
|
|
440
|
+
|
|
441
|
+
return rawFieldValue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
#readDeveloperFieldValue(messageDefinition, developerFieldDefinition, field) {
|
|
445
|
+
|
|
446
|
+
// Preserve arrays for developer fields
|
|
447
|
+
this.#stream.legacyArrayMode = true;
|
|
448
|
+
const rawFieldValue = this.#readRawFieldValue(messageDefinition, developerFieldDefinition, field);
|
|
449
|
+
this.#stream.legacyArrayMode = this.#optLegacyArrayMode;
|
|
450
|
+
|
|
492
451
|
return rawFieldValue;
|
|
493
452
|
}
|
|
494
453
|
|
|
@@ -570,8 +529,9 @@ class Decoder {
|
|
|
570
529
|
continue;
|
|
571
530
|
}
|
|
572
531
|
if (referenceField.rawFieldValue === map.value) {
|
|
573
|
-
|
|
574
|
-
|
|
532
|
+
const src = message[field.name];
|
|
533
|
+
const rawFieldValue = Array.isArray(src.rawFieldValue) ? [...src.rawFieldValue] : src.rawFieldValue;
|
|
534
|
+
message[subField.name] = { ...src, rawFieldValue, isSubField: true };
|
|
575
535
|
|
|
576
536
|
if (subField.hasComponents) {
|
|
577
537
|
this.#fieldsToExpand.push(subField.name);
|
|
@@ -625,6 +585,7 @@ class Decoder {
|
|
|
625
585
|
rawFieldValue: [],
|
|
626
586
|
fieldDefinitionNumber: targetField.num,
|
|
627
587
|
isExpandedField: true,
|
|
588
|
+
isArray: targetField?.array ?? false,
|
|
628
589
|
invalidValue,
|
|
629
590
|
};
|
|
630
591
|
}
|
|
@@ -663,8 +624,9 @@ class Decoder {
|
|
|
663
624
|
}
|
|
664
625
|
|
|
665
626
|
Object.keys(mesg).forEach((key) => {
|
|
666
|
-
|
|
667
|
-
mesg[key].
|
|
627
|
+
const field = mesg[key];
|
|
628
|
+
mesg[key].fieldValue = UtilsInternal.sanitizeValues(field.fieldValue, { legacyArrayMode: this.#optLegacyArrayMode, isArray: field.isArray });
|
|
629
|
+
mesg[key].rawFieldValue = UtilsInternal.sanitizeValues(field.rawFieldValue, { legacyArrayMode: this.#optLegacyArrayMode, isArray: field.isArray });
|
|
668
630
|
|
|
669
631
|
message[key] = mesg[key];
|
|
670
632
|
});
|
|
@@ -693,7 +655,7 @@ class Decoder {
|
|
|
693
655
|
if (field == null) {
|
|
694
656
|
fieldValue = rawFieldValue;
|
|
695
657
|
}
|
|
696
|
-
else if (FIT.
|
|
658
|
+
else if (FIT.NumericFieldTypesSet.has(field?.type ?? -1)) {
|
|
697
659
|
fieldValue = this.#applyScaleAndOffset(messageDefinition, field, rawFieldValue);
|
|
698
660
|
}
|
|
699
661
|
else if (field.type === "string") {
|
|
@@ -717,7 +679,7 @@ class Decoder {
|
|
|
717
679
|
return rawFieldValue;
|
|
718
680
|
}
|
|
719
681
|
|
|
720
|
-
if (FIT.
|
|
682
|
+
if (FIT.NumericFieldTypesSet.has(field?.type ?? -1) === false) {
|
|
721
683
|
return rawFieldValue;
|
|
722
684
|
}
|
|
723
685
|
|
|
@@ -760,7 +722,7 @@ class Decoder {
|
|
|
760
722
|
components.forEach((componentFieldNum, i) => {
|
|
761
723
|
const targetField = messageDefinition.fields[componentFieldNum];
|
|
762
724
|
|
|
763
|
-
if(targetField?.num == field.num && targetField?.isAccumulated) {
|
|
725
|
+
if (targetField?.num == field.num && targetField?.isAccumulated) {
|
|
764
726
|
value = (((value / field.scale) - field.offset) + containingField.offset[i]) * containingField.scale[i];
|
|
765
727
|
}
|
|
766
728
|
});
|
|
@@ -775,7 +737,7 @@ class Decoder {
|
|
|
775
737
|
return rawFieldValue;
|
|
776
738
|
}
|
|
777
739
|
|
|
778
|
-
if (FIT.
|
|
740
|
+
if (FIT.NumericFieldTypesSet.has(field?.type ?? -1)) {
|
|
779
741
|
return rawFieldValue;
|
|
780
742
|
}
|
|
781
743
|
|
package/src/encoder.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -20,17 +20,7 @@ import Utils from "./utils.js";
|
|
|
20
20
|
const HEADER_WITH_CRC_SIZE = 14;
|
|
21
21
|
const HEADER_WITHOUT_CRC_SIZE = 12;
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
* A class for encoding FIT files.
|
|
25
|
-
* @class
|
|
26
|
-
*/
|
|
27
23
|
class Encoder {
|
|
28
|
-
/**
|
|
29
|
-
Creates a FIT File Encoder
|
|
30
|
-
* @param {Object} [options] - Encoder options (optional)
|
|
31
|
-
* @param {Object.<number,{object, object }} [options.fieldDescriptions=null] - (optional, default null) fieldDescriptions
|
|
32
|
-
* @constructor
|
|
33
|
-
*/
|
|
34
24
|
constructor({ fieldDescriptions = null, } = {}) {
|
|
35
25
|
this.#fieldDescriptions = {};
|
|
36
26
|
|
|
@@ -41,10 +31,6 @@ class Encoder {
|
|
|
41
31
|
this.#writeEmptyFileHeader();
|
|
42
32
|
}
|
|
43
33
|
|
|
44
|
-
/**
|
|
45
|
-
* Closes the encoder and returns the file data
|
|
46
|
-
* @returns {Uint8Array} A Uint8Array containing the file data
|
|
47
|
-
*/
|
|
48
34
|
close() {
|
|
49
35
|
this.#updateFileHeader();
|
|
50
36
|
this.#writeFileCrc();
|
|
@@ -52,23 +38,10 @@ class Encoder {
|
|
|
52
38
|
return this.#outputStream.uint8Array;
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
/**
|
|
56
|
-
* Encodes a mesg into the file.
|
|
57
|
-
* @param {Object} mesg - The message data
|
|
58
|
-
* @param {Number} mesg.mesgNum - The mesg number for this message
|
|
59
|
-
* @return {this}
|
|
60
|
-
*/
|
|
61
41
|
writeMesg(mesg) {
|
|
62
42
|
return this.onMesg(mesg.mesgNum, mesg);
|
|
63
43
|
}
|
|
64
44
|
|
|
65
|
-
/**
|
|
66
|
-
* Encodes a mesg into the file.
|
|
67
|
-
* This method can be used as a Decoder~mesgListener callback.
|
|
68
|
-
* @param {Number} mesgNum - The message number for this message
|
|
69
|
-
* @param {Object} mesg - The message data
|
|
70
|
-
* @return {this}
|
|
71
|
-
*/
|
|
72
45
|
onMesg(mesgNum, mesg) {
|
|
73
46
|
try {
|
|
74
47
|
const mesgDefinition = this.#createMesgDefinition(mesgNum, mesg);
|
|
@@ -113,16 +86,6 @@ class Encoder {
|
|
|
113
86
|
return this;
|
|
114
87
|
};
|
|
115
88
|
|
|
116
|
-
/**
|
|
117
|
-
* Adds a Developer Data Field Description and associated Developer Data Id Message to the Endoder
|
|
118
|
-
* This provides the Encoder with the context required to write Developer Fields to the output-stream.
|
|
119
|
-
* *** This method does not write the messages to the output-stream ***
|
|
120
|
-
* This method can be used as a Decoder~fieldDescriptionListener callback.
|
|
121
|
-
* @param {Number} key - The message number for this message
|
|
122
|
-
* @param {Object} developerDataIdMesg - The Developer Data Id mesg
|
|
123
|
-
* @param {Object} fieldDescriptionMesg - The Field Description mesg
|
|
124
|
-
* @return {this}
|
|
125
|
-
*/
|
|
126
89
|
addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg) {
|
|
127
90
|
if(developerDataIdMesg.developerDataIndex == null || fieldDescriptionMesg.developerDataIndex == null) {
|
|
128
91
|
throw new Error("addDeveloperField() - one or more developerDataIndex values are null.", {
|
package/src/fit.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
|
@@ -73,6 +73,8 @@ const NumericFieldTypes = [
|
|
|
73
73
|
"uint64z"
|
|
74
74
|
];
|
|
75
75
|
|
|
76
|
+
const NumericFieldTypesSet = new Set(NumericFieldTypes);
|
|
77
|
+
|
|
76
78
|
const FieldTypeToJsType = {
|
|
77
79
|
"enum": "number",
|
|
78
80
|
"sint8": "number",
|
|
@@ -202,6 +204,7 @@ export default {
|
|
|
202
204
|
BaseTypeMask,
|
|
203
205
|
BaseTypeDefinitions,
|
|
204
206
|
NumericFieldTypes,
|
|
207
|
+
NumericFieldTypesSet,
|
|
205
208
|
BigIntFieldTypes,
|
|
206
209
|
FloatingPointFieldTypes,
|
|
207
210
|
FieldTypeToBaseType,
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright 2026 Garmin International, Inc.
|
|
3
|
+
// Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
|
|
4
|
+
// may not use this file except in compliance with the Flexible and Interoperable Data
|
|
5
|
+
// Transfer (FIT) Protocol License.
|
|
6
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
|
+
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
|
+
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export * from './types/crc-calculator';
|
|
14
|
+
export * from './types/decoder';
|
|
15
|
+
export * from './types/encoder';
|
|
16
|
+
export * from './types/mesg';
|
|
17
|
+
export * from './types/mesgs';
|
|
18
|
+
export * from './types/profile';
|
|
19
|
+
export * from './types/stream';
|
|
20
|
+
export * from './types/types';
|
|
21
|
+
export { default as Types } from './types/types';
|
|
22
|
+
export * from './types/utils';
|
package/src/index.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/mesg-definition.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|
package/src/output-stream.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// Transfer (FIT) Protocol License.
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// ****WARNING**** This file is auto-generated! Do NOT edit this file.
|
|
8
|
-
// Profile Version = 21.
|
|
9
|
-
// Tag = production/release/21.
|
|
8
|
+
// Profile Version = 21.205.0Release
|
|
9
|
+
// Tag = production/release/21.205.0-0-gb3c261eb
|
|
10
10
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
|
11
11
|
|
|
12
12
|
|