fit-file-parser 4.0.0 → 4.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.0.2
4
+
5
+ - Preserve record alignment when developer-field descriptions are missing or
6
+ appear after their message definitions.
7
+ - Decode subsequent developer-field values once their descriptions become
8
+ available, in both strict and force modes.
9
+
3
10
  ## 4.0.0
4
11
 
5
12
  ### FIT decoder performance
package/dist/binary.d.ts CHANGED
@@ -7,8 +7,16 @@ export interface MessageTypeDefinition {
7
7
  globalMessageNumber: number;
8
8
  numberOfFields: number;
9
9
  fieldDefs: FieldDefinition[];
10
+ developerFieldDefs?: DeveloperFieldDefinition[];
10
11
  rawData?: any[];
11
12
  }
13
+ export interface DeveloperFieldDefinition {
14
+ developerDataIndex: number;
15
+ fieldDefinitionNumber: number;
16
+ size: number;
17
+ resolvedFieldDef?: FieldDefinition;
18
+ resolvedFrom?: unknown;
19
+ }
12
20
  export declare function addEndian(littleEndian: boolean, bytes: number[]): number;
13
21
  export declare function readRecord(blob: Uint8Array, messageTypes: MessageTypeDefinition[], developerFields: any[], startIndex: number, options: FitParserOptions, startDate: number | undefined, pausedTime: number, dataView?: DataView): {
14
22
  messageType: MesgNum | '';
package/dist/binary.js CHANGED
@@ -319,8 +319,63 @@ function applyOptions(data, field, options, fields) {
319
319
  return data;
320
320
  }
321
321
  }
322
+ function applyGarminProductName(fields) {
323
+ if (fields.product_name !== undefined || fields.manufacturer !== 'garmin') {
324
+ return;
325
+ }
326
+ const product = fields.product;
327
+ if (typeof product !== 'number') {
328
+ return;
329
+ }
330
+ const productName = FIT.types.garmin_product[product];
331
+ if (typeof productName === 'string') {
332
+ // Keep the raw protocol ID and expose the SDK product name separately.
333
+ fields.product_name = productName;
334
+ }
335
+ }
336
+ function resolveDeveloperFieldDefinition(developerFieldDef, littleEndian, developerFields, options) {
337
+ var _a, _b, _c, _d;
338
+ const description = (_a = developerFields[developerFieldDef.developerDataIndex]) === null || _a === void 0 ? void 0 : _a[developerFieldDef.fieldDefinitionNumber];
339
+ if (!description) {
340
+ developerFieldDef.resolvedFieldDef = undefined;
341
+ developerFieldDef.resolvedFrom = undefined;
342
+ return undefined;
343
+ }
344
+ if (developerFieldDef.resolvedFrom === description
345
+ && developerFieldDef.resolvedFieldDef) {
346
+ return developerFieldDef.resolvedFieldDef;
347
+ }
348
+ const baseType = description.fit_base_type_id;
349
+ const type = FIT.types.fit_base_type[baseType];
350
+ if (typeof baseType !== 'number' || type === undefined) {
351
+ developerFieldDef.resolvedFieldDef = undefined;
352
+ developerFieldDef.resolvedFrom = undefined;
353
+ if (options.force) {
354
+ return undefined;
355
+ }
356
+ throw new Error(`Unsupported base type for developer data index ${developerFieldDef.developerDataIndex}, field ${developerFieldDef.fieldDefinitionNumber}`);
357
+ }
358
+ const resolvedFieldDef = {
359
+ type,
360
+ fDefNo: developerFieldDef.fieldDefinitionNumber,
361
+ size: developerFieldDef.size,
362
+ endianAbility: (baseType & 128) === 128,
363
+ littleEndian,
364
+ baseTypeNo: baseType,
365
+ name: (_b = description.field_name) !== null && _b !== void 0 ? _b : '',
366
+ dataType: getFitMessageBaseType(baseType & 15),
367
+ scale: (_c = description.scale) !== null && _c !== void 0 ? _c : 1,
368
+ offset: (_d = description.offset) !== null && _d !== void 0 ? _d : 0,
369
+ requiresBoundedDataView: requiresBoundedEndianDataView(type, developerFieldDef.size),
370
+ developerDataIndex: developerFieldDef.developerDataIndex,
371
+ isDeveloperField: true,
372
+ };
373
+ developerFieldDef.resolvedFieldDef = resolvedFieldDef;
374
+ developerFieldDef.resolvedFrom = description;
375
+ return resolvedFieldDef;
376
+ }
322
377
  export function readRecord(blob, messageTypes, developerFields, startIndex, options, startDate, pausedTime, dataView = new DataView(blob.buffer, blob.byteOffset, blob.byteLength)) {
323
- var _a, _b, _c, _d, _e;
378
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
324
379
  const recordHeader = blob[startIndex];
325
380
  let localMessageType = recordHeader & 15;
326
381
  if ((recordHeader & CompressedHeaderMask) === CompressedHeaderMask) {
@@ -344,6 +399,7 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
344
399
  ]),
345
400
  numberOfFields: numberOfFields + numberOfDeveloperDataFields,
346
401
  fieldDefs: [],
402
+ developerFieldDefs: [],
347
403
  rawData: [],
348
404
  };
349
405
  const message = getFitMessage(mTypeDef.globalMessageNumber);
@@ -366,41 +422,15 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
366
422
  };
367
423
  mTypeDef.fieldDefs.push(fDef);
368
424
  }
369
- // numberOfDeveloperDataFields = 0 so it wont crash here and wont loop
370
425
  for (let i = 0; i < numberOfDeveloperDataFields; i++) {
371
- // If we fail to parse then try catch
372
- try {
373
- const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;
374
- const fieldNum = blob[fDefIndex];
375
- const size = blob[fDefIndex + 1];
376
- const devDataIndex = blob[fDefIndex + 2];
377
- const devDef = developerFields[devDataIndex][fieldNum];
378
- const baseType = devDef.fit_base_type_id;
379
- const fDef = {
380
- type: FIT.types.fit_base_type[baseType],
381
- fDefNo: fieldNum,
382
- size,
383
- endianAbility: (baseType & 128) === 128,
384
- littleEndian: lEnd,
385
- baseTypeNo: baseType,
386
- name: devDef.field_name,
387
- dataType: getFitMessageBaseType(baseType & 15),
388
- scale: devDef.scale || 1,
389
- offset: devDef.offset || 0,
390
- requiresBoundedDataView: requiresBoundedEndianDataView(FIT.types.fit_base_type[baseType], size),
391
- developerDataIndex: devDataIndex,
392
- isDeveloperField: true,
393
- };
394
- mTypeDef.fieldDefs.push(fDef);
395
- }
396
- catch (e) {
397
- if (options.force) {
398
- continue;
399
- }
400
- throw e;
401
- }
426
+ const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;
427
+ (_a = mTypeDef.developerFieldDefs) === null || _a === void 0 ? void 0 : _a.push({
428
+ fieldDefinitionNumber: blob[fDefIndex],
429
+ size: blob[fDefIndex + 1],
430
+ developerDataIndex: blob[fDefIndex + 2],
431
+ });
402
432
  }
403
- mTypeDef.rawData = Array.from({ length: mTypeDef.fieldDefs.length }, () => InvalidFieldData);
433
+ mTypeDef.rawData = Array.from({ length: mTypeDef.numberOfFields }, () => InvalidFieldData);
404
434
  messageTypes[localMessageType] = mTypeDef;
405
435
  const nextIndex = startIndex + 6 + mTypeDef.numberOfFields * 3;
406
436
  const nextIndexWithDeveloperData = nextIndex + 1;
@@ -416,7 +446,9 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
416
446
  let readDataFromIndex = startIndex + 1;
417
447
  const fields = {};
418
448
  const message = getFitMessage(messageType.globalMessageNumber);
419
- const rawData = (_a = messageType.rawData) !== null && _a !== void 0 ? _a : (messageType.rawData = Array.from({ length: messageType.fieldDefs.length }, () => InvalidFieldData));
449
+ const developerFieldDefs = (_b = messageType.developerFieldDefs) !== null && _b !== void 0 ? _b : [];
450
+ const totalFieldCount = messageType.fieldDefs.length + developerFieldDefs.length;
451
+ const rawData = (_c = messageType.rawData) !== null && _c !== void 0 ? _c : (messageType.rawData = Array.from({ length: totalFieldCount }, () => InvalidFieldData));
420
452
  let validFieldCount = 0;
421
453
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
422
454
  const fDef = messageType.fieldDefs[i];
@@ -431,6 +463,26 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
431
463
  readDataFromIndex += fDef.size;
432
464
  messageSize += fDef.size;
433
465
  }
466
+ for (let i = 0; i < developerFieldDefs.length; i++) {
467
+ const developerFieldDef = developerFieldDefs[i];
468
+ const rawDataIndex = messageType.fieldDefs.length + i;
469
+ const fDef = resolveDeveloperFieldDefinition(developerFieldDef, messageType.littleEndian, developerFields, options);
470
+ if (fDef) {
471
+ const data = readData(blob, dataView, fDef, readDataFromIndex, options);
472
+ if (!isInvalidValue(data, fDef.type) && !isInvalidBaseTypeValue(data, fDef.baseTypeNo)) {
473
+ rawData[rawDataIndex] = data;
474
+ validFieldCount++;
475
+ }
476
+ else {
477
+ rawData[rawDataIndex] = InvalidFieldData;
478
+ }
479
+ }
480
+ else {
481
+ rawData[rawDataIndex] = InvalidFieldData;
482
+ }
483
+ readDataFromIndex += developerFieldDef.size;
484
+ messageSize += developerFieldDef.size;
485
+ }
434
486
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
435
487
  const data = rawData[i];
436
488
  if (data === InvalidFieldData) {
@@ -442,6 +494,17 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
442
494
  fields[field] = data;
443
495
  }
444
496
  }
497
+ for (let i = 0; i < developerFieldDefs.length; i++) {
498
+ const data = rawData[messageType.fieldDefs.length + i];
499
+ const fDef = developerFieldDefs[i].resolvedFieldDef;
500
+ if (data === InvalidFieldData || !fDef) {
501
+ continue;
502
+ }
503
+ const field = fDef.name;
504
+ if (field !== 'unknown' && field !== '') {
505
+ fields[field] = data;
506
+ }
507
+ }
445
508
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
446
509
  const data = rawData[i];
447
510
  if (data === InvalidFieldData) {
@@ -451,19 +514,31 @@ export function readRecord(blob, messageTypes, developerFields, startIndex, opti
451
514
  if (fDef.isDeveloperField) {
452
515
  const field = fDef.name;
453
516
  const { type } = fDef;
454
- const scale = (_b = fDef.scale) !== null && _b !== void 0 ? _b : null;
455
- const offset = (_c = fDef.offset) !== null && _c !== void 0 ? _c : 0;
517
+ const scale = (_d = fDef.scale) !== null && _d !== void 0 ? _d : null;
518
+ const offset = (_e = fDef.offset) !== null && _e !== void 0 ? _e : 0;
456
519
  fields[fDef.name] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);
457
520
  }
458
521
  else {
459
522
  const { name: field, type } = fDef;
460
- const scale = (_d = fDef.scale) !== null && _d !== void 0 ? _d : null;
461
- const offset = (_e = fDef.offset) !== null && _e !== void 0 ? _e : 0;
523
+ const scale = (_f = fDef.scale) !== null && _f !== void 0 ? _f : null;
524
+ const offset = (_g = fDef.offset) !== null && _g !== void 0 ? _g : 0;
462
525
  if (field !== 'unknown' && field !== '' && field !== undefined) {
463
526
  fields[field] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);
464
527
  }
465
528
  }
466
529
  }
530
+ for (let i = 0; i < developerFieldDefs.length; i++) {
531
+ const data = rawData[messageType.fieldDefs.length + i];
532
+ const fDef = developerFieldDefs[i].resolvedFieldDef;
533
+ if (data === InvalidFieldData || !fDef) {
534
+ continue;
535
+ }
536
+ const field = fDef.name;
537
+ if (field !== 'unknown' && field !== '') {
538
+ fields[field] = applyOptions(formatByType(data, fDef.type, (_h = fDef.scale) !== null && _h !== void 0 ? _h : null, (_j = fDef.offset) !== null && _j !== void 0 ? _j : 0), field, options, fields);
539
+ }
540
+ }
541
+ applyGarminProductName(fields);
467
542
  if (validFieldCount > 0 && message.name === 'record' && options.elapsedRecordField) {
468
543
  fields.elapsed_time = (fields.timestamp - (startDate || 0)) / 1000;
469
544
  fields.timer_time = fields.elapsed_time - pausedTime;
@@ -7,8 +7,16 @@ export interface MessageTypeDefinition {
7
7
  globalMessageNumber: number;
8
8
  numberOfFields: number;
9
9
  fieldDefs: FieldDefinition[];
10
+ developerFieldDefs?: DeveloperFieldDefinition[];
10
11
  rawData?: any[];
11
12
  }
13
+ export interface DeveloperFieldDefinition {
14
+ developerDataIndex: number;
15
+ fieldDefinitionNumber: number;
16
+ size: number;
17
+ resolvedFieldDef?: FieldDefinition;
18
+ resolvedFrom?: unknown;
19
+ }
12
20
  export declare function addEndian(littleEndian: boolean, bytes: number[]): number;
13
21
  export declare function readRecord(blob: Uint8Array, messageTypes: MessageTypeDefinition[], developerFields: any[], startIndex: number, options: FitParserOptions, startDate: number | undefined, pausedTime: number, dataView?: DataView): {
14
22
  messageType: MesgNum | '';
@@ -325,8 +325,63 @@ function applyOptions(data, field, options, fields) {
325
325
  return data;
326
326
  }
327
327
  }
328
+ function applyGarminProductName(fields) {
329
+ if (fields.product_name !== undefined || fields.manufacturer !== 'garmin') {
330
+ return;
331
+ }
332
+ const product = fields.product;
333
+ if (typeof product !== 'number') {
334
+ return;
335
+ }
336
+ const productName = fit_js_1.FIT.types.garmin_product[product];
337
+ if (typeof productName === 'string') {
338
+ // Keep the raw protocol ID and expose the SDK product name separately.
339
+ fields.product_name = productName;
340
+ }
341
+ }
342
+ function resolveDeveloperFieldDefinition(developerFieldDef, littleEndian, developerFields, options) {
343
+ var _a, _b, _c, _d;
344
+ const description = (_a = developerFields[developerFieldDef.developerDataIndex]) === null || _a === void 0 ? void 0 : _a[developerFieldDef.fieldDefinitionNumber];
345
+ if (!description) {
346
+ developerFieldDef.resolvedFieldDef = undefined;
347
+ developerFieldDef.resolvedFrom = undefined;
348
+ return undefined;
349
+ }
350
+ if (developerFieldDef.resolvedFrom === description
351
+ && developerFieldDef.resolvedFieldDef) {
352
+ return developerFieldDef.resolvedFieldDef;
353
+ }
354
+ const baseType = description.fit_base_type_id;
355
+ const type = fit_js_1.FIT.types.fit_base_type[baseType];
356
+ if (typeof baseType !== 'number' || type === undefined) {
357
+ developerFieldDef.resolvedFieldDef = undefined;
358
+ developerFieldDef.resolvedFrom = undefined;
359
+ if (options.force) {
360
+ return undefined;
361
+ }
362
+ throw new Error(`Unsupported base type for developer data index ${developerFieldDef.developerDataIndex}, field ${developerFieldDef.fieldDefinitionNumber}`);
363
+ }
364
+ const resolvedFieldDef = {
365
+ type,
366
+ fDefNo: developerFieldDef.fieldDefinitionNumber,
367
+ size: developerFieldDef.size,
368
+ endianAbility: (baseType & 128) === 128,
369
+ littleEndian,
370
+ baseTypeNo: baseType,
371
+ name: (_b = description.field_name) !== null && _b !== void 0 ? _b : '',
372
+ dataType: (0, messages_js_1.getFitMessageBaseType)(baseType & 15),
373
+ scale: (_c = description.scale) !== null && _c !== void 0 ? _c : 1,
374
+ offset: (_d = description.offset) !== null && _d !== void 0 ? _d : 0,
375
+ requiresBoundedDataView: requiresBoundedEndianDataView(type, developerFieldDef.size),
376
+ developerDataIndex: developerFieldDef.developerDataIndex,
377
+ isDeveloperField: true,
378
+ };
379
+ developerFieldDef.resolvedFieldDef = resolvedFieldDef;
380
+ developerFieldDef.resolvedFrom = description;
381
+ return resolvedFieldDef;
382
+ }
328
383
  function readRecord(blob, messageTypes, developerFields, startIndex, options, startDate, pausedTime, dataView = new DataView(blob.buffer, blob.byteOffset, blob.byteLength)) {
329
- var _a, _b, _c, _d, _e;
384
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
330
385
  const recordHeader = blob[startIndex];
331
386
  let localMessageType = recordHeader & 15;
332
387
  if ((recordHeader & CompressedHeaderMask) === CompressedHeaderMask) {
@@ -350,6 +405,7 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
350
405
  ]),
351
406
  numberOfFields: numberOfFields + numberOfDeveloperDataFields,
352
407
  fieldDefs: [],
408
+ developerFieldDefs: [],
353
409
  rawData: [],
354
410
  };
355
411
  const message = (0, messages_js_1.getFitMessage)(mTypeDef.globalMessageNumber);
@@ -372,41 +428,15 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
372
428
  };
373
429
  mTypeDef.fieldDefs.push(fDef);
374
430
  }
375
- // numberOfDeveloperDataFields = 0 so it wont crash here and wont loop
376
431
  for (let i = 0; i < numberOfDeveloperDataFields; i++) {
377
- // If we fail to parse then try catch
378
- try {
379
- const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;
380
- const fieldNum = blob[fDefIndex];
381
- const size = blob[fDefIndex + 1];
382
- const devDataIndex = blob[fDefIndex + 2];
383
- const devDef = developerFields[devDataIndex][fieldNum];
384
- const baseType = devDef.fit_base_type_id;
385
- const fDef = {
386
- type: fit_js_1.FIT.types.fit_base_type[baseType],
387
- fDefNo: fieldNum,
388
- size,
389
- endianAbility: (baseType & 128) === 128,
390
- littleEndian: lEnd,
391
- baseTypeNo: baseType,
392
- name: devDef.field_name,
393
- dataType: (0, messages_js_1.getFitMessageBaseType)(baseType & 15),
394
- scale: devDef.scale || 1,
395
- offset: devDef.offset || 0,
396
- requiresBoundedDataView: requiresBoundedEndianDataView(fit_js_1.FIT.types.fit_base_type[baseType], size),
397
- developerDataIndex: devDataIndex,
398
- isDeveloperField: true,
399
- };
400
- mTypeDef.fieldDefs.push(fDef);
401
- }
402
- catch (e) {
403
- if (options.force) {
404
- continue;
405
- }
406
- throw e;
407
- }
432
+ const fDefIndex = startIndex + 6 + numberOfFields * 3 + 1 + i * 3;
433
+ (_a = mTypeDef.developerFieldDefs) === null || _a === void 0 ? void 0 : _a.push({
434
+ fieldDefinitionNumber: blob[fDefIndex],
435
+ size: blob[fDefIndex + 1],
436
+ developerDataIndex: blob[fDefIndex + 2],
437
+ });
408
438
  }
409
- mTypeDef.rawData = Array.from({ length: mTypeDef.fieldDefs.length }, () => InvalidFieldData);
439
+ mTypeDef.rawData = Array.from({ length: mTypeDef.numberOfFields }, () => InvalidFieldData);
410
440
  messageTypes[localMessageType] = mTypeDef;
411
441
  const nextIndex = startIndex + 6 + mTypeDef.numberOfFields * 3;
412
442
  const nextIndexWithDeveloperData = nextIndex + 1;
@@ -422,7 +452,9 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
422
452
  let readDataFromIndex = startIndex + 1;
423
453
  const fields = {};
424
454
  const message = (0, messages_js_1.getFitMessage)(messageType.globalMessageNumber);
425
- const rawData = (_a = messageType.rawData) !== null && _a !== void 0 ? _a : (messageType.rawData = Array.from({ length: messageType.fieldDefs.length }, () => InvalidFieldData));
455
+ const developerFieldDefs = (_b = messageType.developerFieldDefs) !== null && _b !== void 0 ? _b : [];
456
+ const totalFieldCount = messageType.fieldDefs.length + developerFieldDefs.length;
457
+ const rawData = (_c = messageType.rawData) !== null && _c !== void 0 ? _c : (messageType.rawData = Array.from({ length: totalFieldCount }, () => InvalidFieldData));
426
458
  let validFieldCount = 0;
427
459
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
428
460
  const fDef = messageType.fieldDefs[i];
@@ -437,6 +469,26 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
437
469
  readDataFromIndex += fDef.size;
438
470
  messageSize += fDef.size;
439
471
  }
472
+ for (let i = 0; i < developerFieldDefs.length; i++) {
473
+ const developerFieldDef = developerFieldDefs[i];
474
+ const rawDataIndex = messageType.fieldDefs.length + i;
475
+ const fDef = resolveDeveloperFieldDefinition(developerFieldDef, messageType.littleEndian, developerFields, options);
476
+ if (fDef) {
477
+ const data = readData(blob, dataView, fDef, readDataFromIndex, options);
478
+ if (!isInvalidValue(data, fDef.type) && !isInvalidBaseTypeValue(data, fDef.baseTypeNo)) {
479
+ rawData[rawDataIndex] = data;
480
+ validFieldCount++;
481
+ }
482
+ else {
483
+ rawData[rawDataIndex] = InvalidFieldData;
484
+ }
485
+ }
486
+ else {
487
+ rawData[rawDataIndex] = InvalidFieldData;
488
+ }
489
+ readDataFromIndex += developerFieldDef.size;
490
+ messageSize += developerFieldDef.size;
491
+ }
440
492
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
441
493
  const data = rawData[i];
442
494
  if (data === InvalidFieldData) {
@@ -448,6 +500,17 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
448
500
  fields[field] = data;
449
501
  }
450
502
  }
503
+ for (let i = 0; i < developerFieldDefs.length; i++) {
504
+ const data = rawData[messageType.fieldDefs.length + i];
505
+ const fDef = developerFieldDefs[i].resolvedFieldDef;
506
+ if (data === InvalidFieldData || !fDef) {
507
+ continue;
508
+ }
509
+ const field = fDef.name;
510
+ if (field !== 'unknown' && field !== '') {
511
+ fields[field] = data;
512
+ }
513
+ }
451
514
  for (let i = 0; i < messageType.fieldDefs.length; i++) {
452
515
  const data = rawData[i];
453
516
  if (data === InvalidFieldData) {
@@ -457,19 +520,31 @@ function readRecord(blob, messageTypes, developerFields, startIndex, options, st
457
520
  if (fDef.isDeveloperField) {
458
521
  const field = fDef.name;
459
522
  const { type } = fDef;
460
- const scale = (_b = fDef.scale) !== null && _b !== void 0 ? _b : null;
461
- const offset = (_c = fDef.offset) !== null && _c !== void 0 ? _c : 0;
523
+ const scale = (_d = fDef.scale) !== null && _d !== void 0 ? _d : null;
524
+ const offset = (_e = fDef.offset) !== null && _e !== void 0 ? _e : 0;
462
525
  fields[fDef.name] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);
463
526
  }
464
527
  else {
465
528
  const { name: field, type } = fDef;
466
- const scale = (_d = fDef.scale) !== null && _d !== void 0 ? _d : null;
467
- const offset = (_e = fDef.offset) !== null && _e !== void 0 ? _e : 0;
529
+ const scale = (_f = fDef.scale) !== null && _f !== void 0 ? _f : null;
530
+ const offset = (_g = fDef.offset) !== null && _g !== void 0 ? _g : 0;
468
531
  if (field !== 'unknown' && field !== '' && field !== undefined) {
469
532
  fields[field] = applyOptions(formatByType(data, type, scale, offset), field, options, fields);
470
533
  }
471
534
  }
472
535
  }
536
+ for (let i = 0; i < developerFieldDefs.length; i++) {
537
+ const data = rawData[messageType.fieldDefs.length + i];
538
+ const fDef = developerFieldDefs[i].resolvedFieldDef;
539
+ if (data === InvalidFieldData || !fDef) {
540
+ continue;
541
+ }
542
+ const field = fDef.name;
543
+ if (field !== 'unknown' && field !== '') {
544
+ fields[field] = applyOptions(formatByType(data, fDef.type, (_h = fDef.scale) !== null && _h !== void 0 ? _h : null, (_j = fDef.offset) !== null && _j !== void 0 ? _j : 0), field, options, fields);
545
+ }
546
+ }
547
+ applyGarminProductName(fields);
473
548
  if (validFieldCount > 0 && message.name === 'record' && options.elapsedRecordField) {
474
549
  fields.elapsed_time = (fields.timestamp - (startDate || 0)) / 1000;
475
550
  fields.timer_time = fields.elapsed_time - pausedTime;