@springfield/ham-radio-utils 2.2.1 → 3.0.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.d.ts +0 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/memory/segmented-memory.js +2 -2
  7. package/dist/memory/segmented-memory.js.map +1 -1
  8. package/dist/utils/memory-channel-utils.d.ts.map +1 -1
  9. package/dist/utils/memory-channel-utils.js +1 -3
  10. package/dist/utils/memory-channel-utils.js.map +1 -1
  11. package/dist/utils/memory-data-utils.d.ts.map +1 -1
  12. package/dist/utils/memory-data-utils.js +1 -3
  13. package/dist/utils/memory-data-utils.js.map +1 -1
  14. package/dist/utils/schema-validator.d.ts.map +1 -1
  15. package/dist/utils/schema-validator.js +8 -5
  16. package/dist/utils/schema-validator.js.map +1 -1
  17. package/dist/utils/to-hex-words.js +3 -3
  18. package/dist/utils/to-hex-words.js.map +1 -1
  19. package/dist/utils/ui-logger-factory.d.ts +11 -2
  20. package/dist/utils/ui-logger-factory.d.ts.map +1 -1
  21. package/dist/utils/ui-logger-factory.js +19 -9
  22. package/dist/utils/ui-logger-factory.js.map +1 -1
  23. package/dist/utils/ui-logger.d.ts +7 -5
  24. package/dist/utils/ui-logger.d.ts.map +1 -1
  25. package/dist/utils/ui-logger.js +42 -23
  26. package/dist/utils/ui-logger.js.map +1 -1
  27. package/package.json +6 -6
  28. package/src/index.ts +0 -2
  29. package/src/memory/segmented-memory.ts +2 -2
  30. package/src/utils/memory-channel-utils.ts +1 -3
  31. package/src/utils/memory-data-utils.ts +1 -3
  32. package/src/utils/schema-validator.ts +14 -7
  33. package/src/utils/to-hex-words.ts +3 -3
  34. package/src/utils/ui-logger-factory.ts +36 -16
  35. package/src/utils/ui-logger.ts +57 -29
  36. package/dist/utils/memory-segment-utils.d.ts +0 -3
  37. package/dist/utils/memory-segment-utils.d.ts.map +0 -1
  38. package/dist/utils/memory-segment-utils.js +0 -6
  39. package/dist/utils/memory-segment-utils.js.map +0 -1
  40. package/src/utils/bcd-to-number.ts +0 -10
  41. package/src/utils/number-to-bcd.ts +0 -15
package/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [3.0.0](https://gitlab.com/springfield-ham-radio/app/ham-radio-utils/compare/v2.2.2...v3.0.0) (2025-08-17)
2
+
3
+
4
+ ### ⚠ BREAKING CHANGES
5
+
6
+ * update .oxlintrc.json and package.json for linting improvements and dependency upgrades
7
+
8
+ ### Features
9
+
10
+ * update .oxlintrc.json and package.json for linting improvements and dependency upgrades ([119f934](https://gitlab.com/springfield-ham-radio/app/ham-radio-utils/commit/119f934550846d86d034bce30d735463dcabe4eb))
11
+
12
+ ## [2.2.2](https://gitlab.com/springfield-ham-radio/app/ham-radio-utils/compare/v2.2.1...v2.2.2) (2025-08-08)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **deps:** update dependency @springfield/ham-radio-api to ^16.1.2 ([5e45772](https://gitlab.com/springfield-ham-radio/app/ham-radio-utils/commit/5e4577239236c3a32e43ce6c8dbbf6c75ab73196))
18
+
1
19
  ## [2.2.1](https://gitlab.com/springfield-ham-radio/app/ham-radio-utils/compare/v2.2.0...v2.2.1) (2025-07-11)
2
20
 
3
21
 
package/dist/index.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  export * from './memory/segmented-memory.js';
2
2
  export * from './test-utils/radio-channel-factory.js';
3
3
  export * from './test-utils/radio-programmed-channel-factory.js';
4
- export * from './utils/bcd-to-number.js';
5
4
  export * from './utils/band-plan.js';
6
5
  export * from './utils/frequency-display.js';
7
6
  export * from './utils/memory-channel-utils.js';
8
7
  export * from './utils/memory-data-utils.js';
9
- export * from './utils/number-to-bcd.js';
10
8
  export * from './utils/schema-validator.js';
11
9
  export * from './utils/to-hex-words.js';
12
10
  export * from './utils/ui-logger.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kDAAkD,CAAC;AAEjE,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sCAAsC,CAAuB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kDAAkD,CAAC;AAEjE,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sCAAsC,CAAuB"}
package/dist/index.js CHANGED
@@ -1,12 +1,10 @@
1
1
  export * from './memory/segmented-memory.js';
2
2
  export * from './test-utils/radio-channel-factory.js';
3
3
  export * from './test-utils/radio-programmed-channel-factory.js';
4
- export * from './utils/bcd-to-number.js';
5
4
  export * from './utils/band-plan.js';
6
5
  export * from './utils/frequency-display.js';
7
6
  export * from './utils/memory-channel-utils.js';
8
7
  export * from './utils/memory-data-utils.js';
9
- export * from './utils/number-to-bcd.js';
10
8
  export * from './utils/schema-validator.js';
11
9
  export * from './utils/to-hex-words.js';
12
10
  export * from './utils/ui-logger.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kDAAkD,CAAC;AAEjE,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAE7C,mCAAmC;AACnC,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sCAAsC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["export * from './memory/segmented-memory.js';\n\nexport * from './test-utils/radio-channel-factory.js';\nexport * from './test-utils/radio-programmed-channel-factory.js';\n\nexport * from './utils/bcd-to-number.js';\nexport * from './utils/band-plan.js';\nexport * from './utils/frequency-display.js';\nexport * from './utils/memory-channel-utils.js';\nexport * from './utils/memory-data-utils.js';\nexport * from './utils/number-to-bcd.js';\nexport * from './utils/schema-validator.js';\nexport * from './utils/to-hex-words.js';\nexport * from './utils/ui-logger.js';\nexport * from './utils/ui-logger-factory.js';\n\n// Export the radio protocol schema\nexport { default as radioProtocolSchema } from './schemas/radio-protocol-schema.json' with { type: 'json' };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kDAAkD,CAAC;AAEjE,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAE7C,mCAAmC;AACnC,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,sCAAsC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC","sourcesContent":["export * from './memory/segmented-memory.js';\n\nexport * from './test-utils/radio-channel-factory.js';\nexport * from './test-utils/radio-programmed-channel-factory.js';\n\nexport * from './utils/band-plan.js';\nexport * from './utils/frequency-display.js';\nexport * from './utils/memory-channel-utils.js';\nexport * from './utils/memory-data-utils.js';\nexport * from './utils/schema-validator.js';\nexport * from './utils/to-hex-words.js';\nexport * from './utils/ui-logger.js';\nexport * from './utils/ui-logger-factory.js';\n\n// Export the radio protocol schema\nexport { default as radioProtocolSchema } from './schemas/radio-protocol-schema.json' with { type: 'json' };\n"]}
@@ -2,7 +2,7 @@ export class RadioSegmentedMemory {
2
2
  segments;
3
3
  constructor(segments) {
4
4
  this.segments = new Map();
5
- if (segments != undefined) {
5
+ if (segments) {
6
6
  for (const segment of segments) {
7
7
  this.segments.set(segment.startAddress, segment);
8
8
  }
@@ -30,7 +30,7 @@ export class RadioSegmentedMemory {
30
30
  }
31
31
  result = iterator.next();
32
32
  }
33
- return undefined;
33
+ return {};
34
34
  }
35
35
  toArray() {
36
36
  return [...this.segments.values()];
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-memory.js","sourceRoot":"","sources":["../../src/memory/segmented-memory.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,oBAAoB;IACvB,QAAQ,CAAkC;IAElD,YAAY,QAA+B;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;QAE1B,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC1B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAEM,WAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAChC,CAAC;IAEM,UAAU,CAAC,YAAoB;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAEM,YAAY;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAEM,WAAW,CAAC,OAAe;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE7B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YAE7B,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,OAAO,EAAE,CAAC;gBACpE,OAAO,OAAO,CAAC;YACjB,CAAC;YAED,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAEM,OAAO;QACZ,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import type { RadioMemorySegment } from '@springfield/ham-radio-api';\n\nexport class RadioSegmentedMemory {\n private segments: Map<number, RadioMemorySegment>;\n\n constructor(segments?: RadioMemorySegment[]) {\n this.segments = new Map();\n\n if (segments != undefined) {\n for (const segment of segments) {\n this.segments.set(segment.startAddress, segment);\n }\n }\n }\n\n public addSegment(segment: RadioMemorySegment): void {\n this.segments.set(segment.startAddress, segment);\n }\n\n public getSegments(): IterableIterator<RadioMemorySegment> {\n return this.segments.values();\n }\n\n public getSegment(startAddress: number): RadioMemorySegment | undefined {\n return this.segments.get(startAddress);\n }\n\n public segmentCount(): number {\n return this.segments.size;\n }\n\n public findSegment(address: number): RadioMemorySegment | undefined {\n const iterator = this.segments.values();\n let result = iterator.next();\n\n while (!result.done) {\n const segment = result.value;\n\n if (segment.startAddress <= address && segment.endAddress > address) {\n return segment;\n }\n\n result = iterator.next();\n }\n\n return undefined;\n }\n\n public toArray(): RadioMemorySegment[] {\n return [...this.segments.values()];\n }\n}\n"]}
1
+ {"version":3,"file":"segmented-memory.js","sourceRoot":"","sources":["../../src/memory/segmented-memory.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,oBAAoB;IACvB,QAAQ,CAAkC;IAElD,YAAY,QAA+B;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;QAE1B,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAEM,UAAU,CAAC,OAA2B;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAEM,WAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAChC,CAAC;IAEM,UAAU,CAAC,YAAoB;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC;IAEM,YAAY;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAEM,WAAW,CAAC,OAAe;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,IAAI,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE7B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YAE7B,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,OAAO,EAAE,CAAC;gBACpE,OAAO,OAAO,CAAC;YACjB,CAAC;YAED,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO,EAAwB,CAAC;IAClC,CAAC;IAEM,OAAO;QACZ,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import type { RadioMemorySegment } from '@springfield/ham-radio-api';\n\nexport class RadioSegmentedMemory {\n private segments: Map<number, RadioMemorySegment>;\n\n constructor(segments?: RadioMemorySegment[]) {\n this.segments = new Map();\n\n if (segments) {\n for (const segment of segments) {\n this.segments.set(segment.startAddress, segment);\n }\n }\n }\n\n public addSegment(segment: RadioMemorySegment): void {\n this.segments.set(segment.startAddress, segment);\n }\n\n public getSegments(): IterableIterator<RadioMemorySegment> {\n return this.segments.values();\n }\n\n public getSegment(startAddress: number): RadioMemorySegment | undefined {\n return this.segments.get(startAddress);\n }\n\n public segmentCount(): number {\n return this.segments.size;\n }\n\n public findSegment(address: number): RadioMemorySegment | undefined {\n const iterator = this.segments.values();\n let result = iterator.next();\n\n while (!result.done) {\n const segment = result.value;\n\n if (segment.startAddress <= address && segment.endAddress > address) {\n return segment;\n }\n\n result = iterator.next();\n }\n\n return {} as RadioMemorySegment;\n }\n\n public toArray(): RadioMemorySegment[] {\n return [...this.segments.values()];\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-channel-utils.d.ts","sourceRoot":"","sources":["../../src/utils/memory-channel-utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,GAAI,eAAe,MAAM,EAAE,MAAM,UAAU,KAAG,MAEvE,CAAC"}
1
+ {"version":3,"file":"memory-channel-utils.d.ts","sourceRoot":"","sources":["../../src/utils/memory-channel-utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,GAAI,eAAe,MAAM,EAAE,MAAM,UAAU,KAAG,MAA8D,CAAC"}
@@ -1,6 +1,4 @@
1
1
  import { sprintf } from 'sprintf-js';
2
2
  import { toHexWords } from './to-hex-words.js';
3
- export const formatChannel = (channelNumber, data) => {
4
- return sprintf('%2d : %s', channelNumber, toHexWords(data));
5
- };
3
+ export const formatChannel = (channelNumber, data) => sprintf('%2d : %s', channelNumber, toHexWords(data));
6
4
  //# sourceMappingURL=memory-channel-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-channel-utils.js","sourceRoot":"","sources":["../../src/utils/memory-channel-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,aAAqB,EAAE,IAAgB,EAAU,EAAE;IAC/E,OAAO,OAAO,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC","sourcesContent":["import { sprintf } from 'sprintf-js';\nimport { toHexWords } from './to-hex-words.js';\n\nexport const formatChannel = (channelNumber: number, data: Uint8Array): string => {\n return sprintf('%2d : %s', channelNumber, toHexWords(data));\n};\n"]}
1
+ {"version":3,"file":"memory-channel-utils.js","sourceRoot":"","sources":["../../src/utils/memory-channel-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,aAAqB,EAAE,IAAgB,EAAU,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC","sourcesContent":["import { sprintf } from 'sprintf-js';\nimport { toHexWords } from './to-hex-words.js';\n\nexport const formatChannel = (channelNumber: number, data: Uint8Array): string => sprintf('%2d : %s', channelNumber, toHexWords(data));\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-data-utils.d.ts","sourceRoot":"","sources":["../../src/utils/memory-data-utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,MAAM,UAAU,KAAG,MAEpE,CAAC"}
1
+ {"version":3,"file":"memory-data-utils.d.ts","sourceRoot":"","sources":["../../src/utils/memory-data-utils.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,MAAM,UAAU,KAAG,MAAyD,CAAC"}
@@ -1,6 +1,4 @@
1
1
  import { sprintf } from 'sprintf-js';
2
2
  import { toHexWords } from './to-hex-words.js';
3
- export const formatMemoryData = (address, data) => {
4
- return sprintf('%04X : %s', address, toHexWords(data));
5
- };
3
+ export const formatMemoryData = (address, data) => sprintf('%04X : %s', address, toHexWords(data));
6
4
  //# sourceMappingURL=memory-data-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-data-utils.js","sourceRoot":"","sources":["../../src/utils/memory-data-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAE,IAAgB,EAAU,EAAE;IAC5E,OAAO,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC","sourcesContent":["import { sprintf } from 'sprintf-js';\nimport { toHexWords } from './to-hex-words.js';\n\nexport const formatMemoryData = (address: number, data: Uint8Array): string => {\n return sprintf('%04X : %s', address, toHexWords(data));\n};\n"]}
1
+ {"version":3,"file":"memory-data-utils.js","sourceRoot":"","sources":["../../src/utils/memory-data-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAE,IAAgB,EAAU,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC","sourcesContent":["import { sprintf } from 'sprintf-js';\nimport { toHexWords } from './to-hex-words.js';\n\nexport const formatMemoryData = (address: number, data: Uint8Array): string => sprintf('%04X : %s', address, toHexWords(data));\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAM;;IAUjB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB;CAmBzD"}
1
+ {"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAM;;IAUjB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB;CAqBzD"}
@@ -1,4 +1,4 @@
1
- import Ajv from 'ajv';
1
+ import { Ajv } from 'ajv';
2
2
  import addFormats from 'ajv-formats';
3
3
  import radioProtocolSchema from '../schemas/radio-protocol-schema.json' with { type: 'json' };
4
4
  export class SchemaValidator {
@@ -16,10 +16,13 @@ export class SchemaValidator {
16
16
  if (valid) {
17
17
  return { valid: true };
18
18
  }
19
- const errors = validate.errors?.map((error) => {
20
- const path = error.instancePath || 'root';
21
- return `${path}: ${error.message}`;
22
- }) || [];
19
+ let errors = [];
20
+ if (validate.errors && validate.errors.length > 0) {
21
+ errors = validate.errors.map((error) => {
22
+ const path = error.instancePath || 'root';
23
+ return `${path}: ${error.message}`;
24
+ });
25
+ }
23
26
  return {
24
27
  errors,
25
28
  valid: false,
@@ -1 +1 @@
1
- {"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,mBAAmB,MAAM,uCAAuC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAO9F,MAAM,OAAO,eAAe;IAClB,GAAG,CAAM;IAEjB;QACE,IAAI,CAAC,GAAG,GAAG,IAAK,GAAW,CAAC;YAC1B,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACF,UAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,qBAAqB,CAAC,MAAe;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE/B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,MAAM,GACV,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAkD,EAAE,EAAE;YAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC;YAC1C,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QACrC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEX,OAAO;YACL,MAAM;YACN,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;CACF","sourcesContent":["import Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport radioProtocolSchema from '../schemas/radio-protocol-schema.json' with { type: 'json' };\n\nexport interface ValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\nexport class SchemaValidator {\n private ajv: any;\n\n constructor() {\n this.ajv = new (Ajv as any)({\n allErrors: true,\n verbose: true,\n });\n (addFormats as any)(this.ajv);\n }\n\n validateRadioProtocol(config: unknown): ValidationResult {\n const validate = this.ajv.compile(radioProtocolSchema);\n const valid = validate(config);\n\n if (valid) {\n return { valid: true };\n }\n\n const errors =\n validate.errors?.map((error: { instancePath?: string; message?: string }) => {\n const path = error.instancePath || 'root';\n return `${path}: ${error.message}`;\n }) || [];\n\n return {\n errors,\n valid: false,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,mBAAmB,MAAM,uCAAuC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAY9F,MAAM,OAAO,eAAe;IAClB,GAAG,CAAM;IAEjB;QACE,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;YACjB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACF,UAA2C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,qBAAqB,CAAC,MAAe;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE/B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,IAAI,MAAM,GAAa,EAAE,CAAC;QAC1B,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAe,EAAE,EAAE;gBAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC;gBAC1C,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,MAAM;YACN,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { Ajv } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport radioProtocolSchema from '../schemas/radio-protocol-schema.json' with { type: 'json' };\n\nexport interface ValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\ninterface AjvError {\n instancePath?: string;\n message?: string;\n}\n\nexport class SchemaValidator {\n private ajv: Ajv;\n\n constructor() {\n this.ajv = new Ajv({\n allErrors: true,\n verbose: true,\n });\n (addFormats as unknown as (ajv: Ajv) => Ajv)(this.ajv);\n }\n\n validateRadioProtocol(config: unknown): ValidationResult {\n const validate = this.ajv.compile(radioProtocolSchema);\n const valid = validate(config);\n\n if (valid) {\n return { valid: true };\n }\n\n let errors: string[] = [];\n if (validate.errors && validate.errors.length > 0) {\n errors = validate.errors.map((error: AjvError) => {\n const path = error.instancePath || 'root';\n return `${path}: ${error.message}`;\n });\n }\n\n return {\n errors,\n valid: false,\n };\n }\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  export const toHexWords = (data) => {
2
2
  const hexData = Buffer.from(data).toString('hex');
3
3
  let formattedData = '';
4
- for (let i = 0; i < hexData.length; i += 4) {
5
- if (0 != i) {
4
+ for (let index = 0; index < hexData.length; index += 4) {
5
+ if (index !== 0) {
6
6
  formattedData += ' ';
7
7
  }
8
- formattedData += hexData.substring(i, i + 4);
8
+ formattedData += hexData.slice(index, index + 4);
9
9
  }
10
10
  return formattedData;
11
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"to-hex-words.js","sourceRoot":"","sources":["../../src/utils/to-hex-words.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAgB,EAAU,EAAE;IACrD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,aAAa,GAAG,EAAE,CAAC;IAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACX,aAAa,IAAI,GAAG,CAAC;QACvB,CAAC;QAED,aAAa,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC","sourcesContent":["export const toHexWords = (data: Uint8Array): string => {\n const hexData = Buffer.from(data).toString('hex');\n let formattedData = '';\n\n for (let i = 0; i < hexData.length; i += 4) {\n if (0 != i) {\n formattedData += ' ';\n }\n\n formattedData += hexData.substring(i, i + 4);\n }\n\n return formattedData;\n};\n"]}
1
+ {"version":3,"file":"to-hex-words.js","sourceRoot":"","sources":["../../src/utils/to-hex-words.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAgB,EAAU,EAAE;IACrD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,aAAa,GAAG,EAAE,CAAC;IAEvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACvD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,aAAa,IAAI,GAAG,CAAC;QACvB,CAAC;QAED,aAAa,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC","sourcesContent":["export const toHexWords = (data: Uint8Array): string => {\n const hexData = Buffer.from(data).toString('hex');\n let formattedData = '';\n\n for (let index = 0; index < hexData.length; index += 4) {\n if (index !== 0) {\n formattedData += ' ';\n }\n\n formattedData += hexData.slice(index, index + 4);\n }\n\n return formattedData;\n};\n"]}
@@ -1,8 +1,17 @@
1
+ import type { LogLayerTransport } from '@loglayer/shared';
1
2
  import { UILogger } from './ui-logger.js';
3
+ interface LogEntry {
4
+ data: unknown;
5
+ hasData: boolean;
6
+ level: string;
7
+ message: string;
8
+ timestamp: string;
9
+ }
2
10
  export interface UILoggerConfig {
3
- customTransport?: any;
11
+ customTransport?: LogLayerTransport;
4
12
  enableConsoleDebug?: boolean;
5
13
  }
6
14
  export declare const createUILogger: (config?: UILoggerConfig) => UILogger;
7
- export declare const createUILoggerWithCallback: (callback: (logEntry: any) => void, config?: UILoggerConfig) => UILogger;
15
+ export declare const createUILoggerWithCallback: (callback: (logEntry: LogEntry) => void, config?: UILoggerConfig) => UILogger;
16
+ export {};
8
17
  //# sourceMappingURL=ui-logger-factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-logger-factory.d.ts","sourceRoot":"","sources":["../../src/utils/ui-logger-factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AA2B1C,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,GAA2B,SAAQ,cAAmB,KAAG,QAYnF,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAuC,UAAU,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,EAAE,SAAQ,cAAmB,KAAG,QAQ9I,CAAC"}
1
+ {"version":3,"file":"ui-logger-factory.d.ts","sourceRoot":"","sources":["../../src/utils/ui-logger-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,UAAU,QAAQ;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAmCD,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAQD,eAAO,MAAM,cAAc,GAA2B,SAAQ,cAAmB,KAAG,QAQnF,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAuC,UAAU,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAAE,SAAQ,cAAmB,KAAG,QAQnJ,CAAC"}
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line no-duplicate-imports, sort-imports
1
2
  import { BaseTransport } from '@loglayer/transport';
2
3
  import { LogLayer } from 'loglayer';
3
4
  import { UILogger } from './ui-logger.js';
@@ -5,29 +6,38 @@ import { UILogger } from './ui-logger.js';
5
6
  * Custom LogLayer transport for capturing UI log entries.
6
7
  */
7
8
  const UILogTransport = class extends BaseTransport {
8
- #callback;
9
+ callback;
9
10
  constructor(callback) {
10
11
  // Pass a dummy logger to BaseTransport
11
- super({ enabled: true, id: 'ui-logger-transport', logger: { log: () => { } } });
12
- this.#callback = callback;
12
+ super({
13
+ enabled: true,
14
+ id: 'ui-logger-transport',
15
+ logger: {
16
+ log: () => {
17
+ // Empty function for dummy logger
18
+ },
19
+ },
20
+ });
21
+ this.callback = callback;
13
22
  }
14
23
  shipToLogger(params) {
15
24
  const logEntry = {
16
25
  data: params.data,
17
- hasData: params.hasData,
26
+ hasData: params.hasData ?? false,
18
27
  level: params.logLevel,
19
28
  message: params.messages.join(' '),
20
29
  timestamp: new Date().toISOString(),
21
30
  };
22
- this.#callback(logEntry);
31
+ this.callback(logEntry);
23
32
  return [];
24
33
  }
25
34
  };
35
+ // Move defaultCallback to outer scope to avoid recreating it on every call
36
+ const defaultCallback = (logEntry) => {
37
+ // eslint-disable-next-line no-console
38
+ console.log(JSON.stringify(logEntry));
39
+ };
26
40
  export const createUILogger = function createUILogger(config = {}) {
27
- // By default, just print to console as JSON
28
- const defaultCallback = (logEntry) => {
29
- console.log(JSON.stringify(logEntry));
30
- };
31
41
  const transport = config.customTransport || new UILogTransport(defaultCallback);
32
42
  const logger = new LogLayer({
33
43
  consoleDebug: config.enableConsoleDebug ?? false,
@@ -1 +1 @@
1
- {"version":3,"file":"ui-logger-factory.js","sourceRoot":"","sources":["../../src/utils/ui-logger-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;GAEG;AACH,MAAM,cAAc,GAAG,KAAM,SAAQ,aAAkB;IACrD,SAAS,CAA0B;IAEnC,YAAY,QAAiC;QAC3C,uCAAuC;QACvC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/E,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAED,YAAY,CAAC,MAAW;QACtB,MAAM,QAAQ,GAAG;YACf,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,QAAQ;YACtB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC;AAOF,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,cAAc,CAAC,SAAyB,EAAE;IAC/E,4CAA4C;IAC5C,MAAM,eAAe,GAAG,CAAC,QAAa,EAAE,EAAE;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,IAAI,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC,kBAAkB,IAAI,KAAK;QAChD,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,SAAS,0BAA0B,CAAC,QAAiC,EAAE,SAAyB,EAAE;IAC1I,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC,kBAAkB,IAAI,KAAK;QAChD,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["import { BaseTransport } from '@loglayer/transport';\nimport { LogLayer } from 'loglayer';\nimport { UILogger } from './ui-logger.js';\n\n/**\n * Custom LogLayer transport for capturing UI log entries.\n */\nconst UILogTransport = class extends BaseTransport<any> {\n #callback: (logEntry: any) => void;\n\n constructor(callback: (logEntry: any) => void) {\n // Pass a dummy logger to BaseTransport\n super({ enabled: true, id: 'ui-logger-transport', logger: { log: () => {} } });\n this.#callback = callback;\n }\n\n shipToLogger(params: any) {\n const logEntry = {\n data: params.data,\n hasData: params.hasData,\n level: params.logLevel,\n message: params.messages.join(' '),\n timestamp: new Date().toISOString(),\n };\n this.#callback(logEntry);\n return [];\n }\n};\n\nexport interface UILoggerConfig {\n customTransport?: any;\n enableConsoleDebug?: boolean;\n}\n\nexport const createUILogger = function createUILogger(config: UILoggerConfig = {}): UILogger {\n // By default, just print to console as JSON\n const defaultCallback = (logEntry: any) => {\n console.log(JSON.stringify(logEntry));\n };\n const transport = config.customTransport || new UILogTransport(defaultCallback);\n const logger = new LogLayer({\n consoleDebug: config.enableConsoleDebug ?? false,\n transport,\n });\n logger.setLevel('debug');\n return new UILogger(logger);\n};\n\nexport const createUILoggerWithCallback = function createUILoggerWithCallback(callback: (logEntry: any) => void, config: UILoggerConfig = {}): UILogger {\n const transport = new UILogTransport(callback);\n const logger = new LogLayer({\n consoleDebug: config.enableConsoleDebug ?? false,\n transport,\n });\n logger.setLevel('debug');\n return new UILogger(logger);\n};\n"]}
1
+ {"version":3,"file":"ui-logger-factory.js","sourceRoot":"","sources":["../../src/utils/ui-logger-factory.ts"],"names":[],"mappings":"AACA,8DAA8D;AAC9D,OAAO,EAAE,aAAa,EAAgC,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAU1C;;GAEG;AACH,MAAM,cAAc,GAAG,KAAM,SAAQ,aAAsB;IACjD,QAAQ,CAA+B;IAE/C,YAAY,QAAsC;QAChD,uCAAuC;QACvC,KAAK,CAAC;YACJ,OAAO,EAAE,IAAI;YACb,EAAE,EAAE,qBAAqB;YACzB,MAAM,EAAE;gBACN,GAAG,EAAE,GAAS,EAAE;oBACd,kCAAkC;gBACpC,CAAC;aACF;SACF,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,YAAY,CAAC,MAA+B;QAC1C,MAAM,QAAQ,GAAa;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;YAChC,KAAK,EAAE,MAAM,CAAC,QAAQ;YACtB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC;AAOF,2EAA2E;AAC3E,MAAM,eAAe,GAAG,CAAC,QAAkB,EAAQ,EAAE;IACnD,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,cAAc,CAAC,SAAyB,EAAE;IAC/E,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,IAAI,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC,kBAAkB,IAAI,KAAK;QAChD,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,SAAS,0BAA0B,CAAC,QAAsC,EAAE,SAAyB,EAAE;IAC/I,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC,kBAAkB,IAAI,KAAK;QAChD,SAAS;KACV,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC","sourcesContent":["import type { LogLayerTransport } from '@loglayer/shared';\n// eslint-disable-next-line no-duplicate-imports, sort-imports\nimport { BaseTransport, type LogLayerTransportParams } from '@loglayer/transport';\nimport { LogLayer } from 'loglayer';\nimport { UILogger } from './ui-logger.js';\n\ninterface LogEntry {\n data: unknown;\n hasData: boolean;\n level: string;\n message: string;\n timestamp: string;\n}\n\n/**\n * Custom LogLayer transport for capturing UI log entries.\n */\nconst UILogTransport = class extends BaseTransport<unknown> {\n private callback: (logEntry: LogEntry) => void;\n\n constructor(callback: (logEntry: LogEntry) => void) {\n // Pass a dummy logger to BaseTransport\n super({\n enabled: true,\n id: 'ui-logger-transport',\n logger: {\n log: (): void => {\n // Empty function for dummy logger\n },\n },\n });\n this.callback = callback;\n }\n\n shipToLogger(params: LogLayerTransportParams): unknown[] {\n const logEntry: LogEntry = {\n data: params.data,\n hasData: params.hasData ?? false,\n level: params.logLevel,\n message: params.messages.join(' '),\n timestamp: new Date().toISOString(),\n };\n this.callback(logEntry);\n return [];\n }\n};\n\nexport interface UILoggerConfig {\n customTransport?: LogLayerTransport;\n enableConsoleDebug?: boolean;\n}\n\n// Move defaultCallback to outer scope to avoid recreating it on every call\nconst defaultCallback = (logEntry: LogEntry): void => {\n // eslint-disable-next-line no-console\n console.log(JSON.stringify(logEntry));\n};\n\nexport const createUILogger = function createUILogger(config: UILoggerConfig = {}): UILogger {\n const transport = config.customTransport || new UILogTransport(defaultCallback);\n const logger = new LogLayer({\n consoleDebug: config.enableConsoleDebug ?? false,\n transport,\n });\n logger.setLevel('debug');\n return new UILogger(logger);\n};\n\nexport const createUILoggerWithCallback = function createUILoggerWithCallback(callback: (logEntry: LogEntry) => void, config: UILoggerConfig = {}): UILogger {\n const transport = new UILogTransport(callback);\n const logger = new LogLayer({\n consoleDebug: config.enableConsoleDebug ?? false,\n transport,\n });\n logger.setLevel('debug');\n return new UILogger(logger);\n};\n"]}
@@ -20,12 +20,13 @@ import type { ILogLayer } from 'loglayer';
20
20
  * - Structured data supports rich UI representations
21
21
  * - Separate from debug logging avoids UI noise
22
22
  */
23
+ interface ProtocolContext {
24
+ variables?: Map<string, unknown>;
25
+ }
23
26
  /**
24
27
  * Generic protocol step interface for UI logging
25
28
  */
26
- export interface UIProtocolStep {
27
- [key: string]: any;
28
- }
29
+ export type UIProtocolStep = Record<string, unknown>;
29
30
  /**
30
31
  * UI Logger for capturing command-level information for UI display
31
32
  */
@@ -34,10 +35,11 @@ export declare class UILogger {
34
35
  private commandStartTimes;
35
36
  constructor(logger: ILogLayer);
36
37
  startCommand(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep): void;
37
- logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: any): void;
38
- logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: any): void;
38
+ logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: ProtocolContext): void;
39
+ logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: ProtocolContext): void;
39
40
  private getCommandType;
40
41
  private getStepDescription;
41
42
  private getExpectedData;
42
43
  }
44
+ export {};
43
45
  //# sourceMappingURL=ui-logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-logger.d.ts","sourceRoot":"","sources":["../../src/utils/ui-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,MAAM,EAAE,SAAS;IAK7B,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IAsBlG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI;IA6CrH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI;IAkCnI,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,eAAe;CAiBxB"}
1
+ {"version":3,"file":"ui-logger.d.ts","sourceRoot":"","sources":["../../src/utils/ui-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA0BrD;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,MAAM,EAAE,SAAS;IAK7B,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IAsBlG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IA2CjI,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAmC/I,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,eAAe;CAoBxB"}
@@ -1,3 +1,20 @@
1
+ /**
2
+ * Type guards for protocol step properties
3
+ */
4
+ const hasDescription = (obj) => typeof obj === 'object' && obj !== null && 'description' in obj && typeof obj.description === 'string';
5
+ const hasReceive = (obj) => typeof obj === 'object' && obj !== null && 'receive' in obj;
6
+ const hasEndChunk = (obj) => typeof obj === 'object' &&
7
+ obj !== null &&
8
+ 'endChunk' in obj &&
9
+ typeof obj.endChunk === 'object' &&
10
+ obj.endChunk !== null &&
11
+ 'receive' in obj.endChunk;
12
+ const hasStartChunk = (obj) => typeof obj === 'object' &&
13
+ obj !== null &&
14
+ 'startChunk' in obj &&
15
+ typeof obj.startChunk === 'object' &&
16
+ obj.startChunk !== null &&
17
+ 'receive' in obj.startChunk;
1
18
  /**
2
19
  * UI Logger for capturing command-level information for UI display
3
20
  */
@@ -35,18 +52,16 @@ export class UILogger {
35
52
  const commandType = this.getCommandType(step);
36
53
  const description = this.getStepDescription(step);
37
54
  // Extract sent and received data from context
38
- const dataSent = context.variables?.get('lastSentData');
39
- const dataReceived = context.variables?.get('lastReceivedData');
55
+ const dataSent = context.variables && context.variables.get('lastSentData');
56
+ const dataReceived = context.variables && context.variables.get('lastReceivedData');
40
57
  const dataExpected = this.getExpectedData(step);
41
58
  // For readSegment, also extract chunk logs if present
42
- let dataChunks = undefined;
43
- if ('readSegment' === commandType) {
44
- dataChunks = context.variables?.get('lastReadSegmentChunks');
45
- // For readSegment, we don't need the flattened dataSent/dataReceived since we have dataChunks
46
- }
59
+ const dataChunks = commandType === 'readSegment' && context.variables && context.variables.get('lastReadSegmentChunks');
47
60
  // Convert dataSent and dataReceived to byte array format if they exist
48
- const dataSentArray = dataSent ? [...dataSent] : undefined;
49
- const dataReceivedArray = dataReceived ? [...dataReceived] : undefined;
61
+ // eslint-disable-next-line unicorn/prefer-spread
62
+ const dataSentArray = dataSent && Array.from(dataSent);
63
+ // eslint-disable-next-line unicorn/prefer-spread
64
+ const dataReceivedArray = dataReceived && Array.from(dataReceived);
50
65
  this.logger
51
66
  .withMetadata({
52
67
  commandType,
@@ -74,10 +89,11 @@ export class UILogger {
74
89
  const commandType = this.getCommandType(step);
75
90
  const description = this.getStepDescription(step);
76
91
  // Extract sent data from context
77
- const dataSent = context.variables?.get('lastSentData');
92
+ const dataSent = context.variables && context.variables.get('lastSentData');
78
93
  const dataExpected = this.getExpectedData(step);
79
94
  // Convert dataSent to byte array format if it exists
80
- const dataSentArray = dataSent ? [...dataSent] : undefined;
95
+ // eslint-disable-next-line unicorn/prefer-spread
96
+ const dataSentArray = dataSent && Array.from(dataSent);
81
97
  this.logger
82
98
  .withMetadata({
83
99
  commandType,
@@ -117,25 +133,25 @@ export class UILogger {
117
133
  return 'unknown';
118
134
  }
119
135
  getStepDescription(step) {
120
- if ('sendReceive' in step && step.sendReceive.description) {
136
+ if ('sendReceive' in step && hasDescription(step.sendReceive)) {
121
137
  return step.sendReceive.description;
122
138
  }
123
- if ('send' in step && step.send.description) {
139
+ if ('send' in step && hasDescription(step.send)) {
124
140
  return step.send.description;
125
141
  }
126
- if ('receive' in step && step.receive.description) {
142
+ if ('receive' in step && hasDescription(step.receive)) {
127
143
  return step.receive.description;
128
144
  }
129
- if ('readSegment' in step && step.readSegment.description) {
145
+ if ('readSegment' in step && hasDescription(step.readSegment)) {
130
146
  return step.readSegment.description;
131
147
  }
132
- if ('writeSegment' in step && step.writeSegment.description) {
148
+ if ('writeSegment' in step && hasDescription(step.writeSegment)) {
133
149
  return step.writeSegment.description;
134
150
  }
135
151
  return 'No description';
136
152
  }
137
153
  getExpectedData(step) {
138
- if ('sendReceive' in step && step.sendReceive.receive) {
154
+ if ('sendReceive' in step && hasReceive(step.sendReceive)) {
139
155
  return step.sendReceive.receive;
140
156
  }
141
157
  if ('receive' in step) {
@@ -143,13 +159,16 @@ export class UILogger {
143
159
  }
144
160
  if ('readSegment' in step) {
145
161
  // For readSegment, return both start and end chunk receive patterns
146
- return {
147
- endChunk: step.readSegment.endChunk.receive,
148
- startChunk: step.readSegment.startChunk.receive,
149
- type: 'readSegment',
150
- };
162
+ const { readSegment } = step;
163
+ if (hasEndChunk(readSegment) && hasStartChunk(readSegment)) {
164
+ return {
165
+ endChunk: readSegment.endChunk.receive,
166
+ startChunk: readSegment.startChunk.receive,
167
+ type: 'readSegment',
168
+ };
169
+ }
151
170
  }
152
- return undefined;
171
+ return {};
153
172
  }
154
173
  }
155
174
  //# sourceMappingURL=ui-logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-logger.js","sourceRoot":"","sources":["../../src/utils/ui-logger.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ILogLayer } from 'loglayer';\n\n/**\n * UI Logger: Command-Level Logging for UI Display\n *\n * This module provides a specialized logger for capturing command-level information\n * that can be easily parsed and displayed in a UI. It captures details about\n * commands, data sent, data expected, and data received in a structured format.\n *\n * Purpose:\n * - Captures command-level information for UI display\n * - Provides structured JSON logging for easy parsing\n * - Tracks command execution details including timing\n * - Supports protocol debugging in UI environments\n * - Maintains separation from debug logging\n *\n * Design Rationale:\n * - Single log entry per command provides clean UI display\n * - JSON structure enables easy parsing and filtering\n * - Command-level granularity is appropriate for UI debugging\n * - Structured data supports rich UI representations\n * - Separate from debug logging avoids UI noise\n */\n\n/**\n * Generic protocol step interface for UI logging\n */\nexport interface UIProtocolStep {\n [key: string]: any;\n}\n\n/**\n * UI Logger for capturing command-level information for UI display\n */\nexport class UILogger {\n private logger: ILogLayer;\n private commandStartTimes = new Map<string, number>();\n\n constructor(logger: ILogLayer) {\n this.logger = logger;\n }\n\n // eslint-disable-next-line max-params\n startCommand(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = Date.now();\n this.commandStartTimes.set(commandId, startTime);\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n this.logger\n .withMetadata({\n commandId,\n commandType,\n description,\n operation,\n startTime,\n stepIndex,\n totalSteps,\n })\n .info('Command started');\n }\n\n // eslint-disable-next-line max-params\n logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: any): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = this.commandStartTimes.get(commandId) || Date.now();\n const endTime = Date.now();\n const duration = endTime - startTime;\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n // Extract sent and received data from context\n const dataSent = context.variables?.get('lastSentData');\n const dataReceived = context.variables?.get('lastReceivedData');\n const dataExpected = this.getExpectedData(step);\n\n // For readSegment, also extract chunk logs if present\n let dataChunks = undefined;\n if ('readSegment' === commandType) {\n dataChunks = context.variables?.get('lastReadSegmentChunks');\n // For readSegment, we don't need the flattened dataSent/dataReceived since we have dataChunks\n }\n\n // Convert dataSent and dataReceived to byte array format if they exist\n const dataSentArray = dataSent ? [...dataSent] : undefined;\n const dataReceivedArray = dataReceived ? [...dataReceived] : undefined;\n\n this.logger\n .withMetadata({\n commandType,\n dataChunks,\n dataExpected,\n dataReceived: dataReceivedArray,\n dataSent: dataSentArray,\n description,\n duration,\n endTime,\n operation,\n startTime,\n stepIndex,\n success: true,\n totalSteps,\n })\n .info('Command completed successfully');\n }\n\n // eslint-disable-next-line max-params\n logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: any): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = this.commandStartTimes.get(commandId) || Date.now();\n const endTime = Date.now();\n const duration = endTime - startTime;\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n // Extract sent data from context\n const dataSent = context.variables?.get('lastSentData');\n const dataExpected = this.getExpectedData(step);\n\n // Convert dataSent to byte array format if it exists\n const dataSentArray = dataSent ? [...dataSent] : undefined;\n\n this.logger\n .withMetadata({\n commandType,\n dataExpected,\n dataSent: dataSentArray,\n description,\n duration,\n endTime,\n error: error.message,\n operation,\n startTime,\n stepIndex,\n success: false,\n totalSteps,\n })\n .info('Command failed');\n }\n\n private getCommandType(step: UIProtocolStep): string {\n if ('sendReceive' in step) {\n return 'sendReceive';\n }\n if ('send' in step) {\n return 'send';\n }\n if ('receive' in step) {\n return 'receive';\n }\n if ('readSegment' in step) {\n return 'readSegment';\n }\n if ('writeSegment' in step) {\n return 'writeSegment';\n }\n if ('setVariable' in step) {\n return 'setVariable';\n }\n return 'unknown';\n }\n\n private getStepDescription(step: UIProtocolStep): string {\n if ('sendReceive' in step && step.sendReceive.description) {\n return step.sendReceive.description;\n }\n if ('send' in step && step.send.description) {\n return step.send.description;\n }\n if ('receive' in step && step.receive.description) {\n return step.receive.description;\n }\n if ('readSegment' in step && step.readSegment.description) {\n return step.readSegment.description;\n }\n if ('writeSegment' in step && step.writeSegment.description) {\n return step.writeSegment.description;\n }\n return 'No description';\n }\n\n private getExpectedData(step: UIProtocolStep): any {\n if ('sendReceive' in step && step.sendReceive.receive) {\n return step.sendReceive.receive;\n }\n if ('receive' in step) {\n return step.receive;\n }\n if ('readSegment' in step) {\n // For readSegment, return both start and end chunk receive patterns\n return {\n endChunk: step.readSegment.endChunk.receive,\n startChunk: step.readSegment.startChunk.receive,\n type: 'readSegment',\n };\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"ui-logger.js","sourceRoot":"","sources":["../../src/utils/ui-logger.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ILogLayer } from 'loglayer';\n\n/**\n * UI Logger: Command-Level Logging for UI Display\n *\n * This module provides a specialized logger for capturing command-level information\n * that can be easily parsed and displayed in a UI. It captures details about\n * commands, data sent, data expected, and data received in a structured format.\n *\n * Purpose:\n * - Captures command-level information for UI display\n * - Provides structured JSON logging for easy parsing\n * - Tracks command execution details including timing\n * - Supports protocol debugging in UI environments\n * - Maintains separation from debug logging\n *\n * Design Rationale:\n * - Single log entry per command provides clean UI display\n * - JSON structure enables easy parsing and filtering\n * - Command-level granularity is appropriate for UI debugging\n * - Structured data supports rich UI representations\n * - Separate from debug logging avoids UI noise\n */\n\ninterface ProtocolContext {\n variables?: Map<string, unknown>;\n}\n\n/**\n * Generic protocol step interface for UI logging\n */\nexport type UIProtocolStep = Record<string, unknown>;\n\n/**\n * Type guards for protocol step properties\n */\nconst hasDescription = (obj: unknown): obj is { description: string } =>\n typeof obj === 'object' && obj !== null && 'description' in obj && typeof (obj as Record<string, unknown>).description === 'string';\n\nconst hasReceive = (obj: unknown): obj is { receive: unknown } => typeof obj === 'object' && obj !== null && 'receive' in obj;\n\nconst hasEndChunk = (obj: unknown): obj is { endChunk: { receive: unknown } } =>\n typeof obj === 'object' &&\n obj !== null &&\n 'endChunk' in obj &&\n typeof (obj as Record<string, unknown>).endChunk === 'object' &&\n (obj as Record<string, unknown>).endChunk !== null &&\n 'receive' in ((obj as Record<string, unknown>).endChunk as Record<string, unknown>);\n\nconst hasStartChunk = (obj: unknown): obj is { startChunk: { receive: unknown } } =>\n typeof obj === 'object' &&\n obj !== null &&\n 'startChunk' in obj &&\n typeof (obj as Record<string, unknown>).startChunk === 'object' &&\n (obj as Record<string, unknown>).startChunk !== null &&\n 'receive' in ((obj as Record<string, unknown>).startChunk as Record<string, unknown>);\n\n/**\n * UI Logger for capturing command-level information for UI display\n */\nexport class UILogger {\n private logger: ILogLayer;\n private commandStartTimes = new Map<string, number>();\n\n constructor(logger: ILogLayer) {\n this.logger = logger;\n }\n\n // eslint-disable-next-line max-params\n startCommand(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = Date.now();\n this.commandStartTimes.set(commandId, startTime);\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n this.logger\n .withMetadata({\n commandId,\n commandType,\n description,\n operation,\n startTime,\n stepIndex,\n totalSteps,\n })\n .info('Command started');\n }\n\n // eslint-disable-next-line max-params\n logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: ProtocolContext): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = this.commandStartTimes.get(commandId) || Date.now();\n const endTime = Date.now();\n const duration = endTime - startTime;\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n // Extract sent and received data from context\n const dataSent = context.variables && context.variables.get('lastSentData');\n const dataReceived = context.variables && context.variables.get('lastReceivedData');\n const dataExpected = this.getExpectedData(step);\n\n // For readSegment, also extract chunk logs if present\n const dataChunks = commandType === 'readSegment' && context.variables && context.variables.get('lastReadSegmentChunks');\n\n // Convert dataSent and dataReceived to byte array format if they exist\n // eslint-disable-next-line unicorn/prefer-spread\n const dataSentArray = dataSent && Array.from(dataSent as Uint8Array);\n // eslint-disable-next-line unicorn/prefer-spread\n const dataReceivedArray = dataReceived && Array.from(dataReceived as Uint8Array);\n\n this.logger\n .withMetadata({\n commandType,\n dataChunks,\n dataExpected,\n dataReceived: dataReceivedArray,\n dataSent: dataSentArray,\n description,\n duration,\n endTime,\n operation,\n startTime,\n stepIndex,\n success: true,\n totalSteps,\n })\n .info('Command completed successfully');\n }\n\n // eslint-disable-next-line max-params\n logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: ProtocolContext): void {\n const commandId = `${operation}-${stepIndex}`;\n const startTime = this.commandStartTimes.get(commandId) || Date.now();\n const endTime = Date.now();\n const duration = endTime - startTime;\n\n const commandType = this.getCommandType(step);\n const description = this.getStepDescription(step);\n\n // Extract sent data from context\n const dataSent = context.variables && context.variables.get('lastSentData');\n const dataExpected = this.getExpectedData(step);\n\n // Convert dataSent to byte array format if it exists\n // eslint-disable-next-line unicorn/prefer-spread\n const dataSentArray = dataSent && Array.from(dataSent as Uint8Array);\n\n this.logger\n .withMetadata({\n commandType,\n dataExpected,\n dataSent: dataSentArray,\n description,\n duration,\n endTime,\n error: error.message,\n operation,\n startTime,\n stepIndex,\n success: false,\n totalSteps,\n })\n .info('Command failed');\n }\n\n private getCommandType(step: UIProtocolStep): string {\n if ('sendReceive' in step) {\n return 'sendReceive';\n }\n if ('send' in step) {\n return 'send';\n }\n if ('receive' in step) {\n return 'receive';\n }\n if ('readSegment' in step) {\n return 'readSegment';\n }\n if ('writeSegment' in step) {\n return 'writeSegment';\n }\n if ('setVariable' in step) {\n return 'setVariable';\n }\n return 'unknown';\n }\n\n private getStepDescription(step: UIProtocolStep): string {\n if ('sendReceive' in step && hasDescription(step.sendReceive)) {\n return step.sendReceive.description;\n }\n if ('send' in step && hasDescription(step.send)) {\n return step.send.description;\n }\n if ('receive' in step && hasDescription(step.receive)) {\n return step.receive.description;\n }\n if ('readSegment' in step && hasDescription(step.readSegment)) {\n return step.readSegment.description;\n }\n if ('writeSegment' in step && hasDescription(step.writeSegment)) {\n return step.writeSegment.description;\n }\n return 'No description';\n }\n\n private getExpectedData(step: UIProtocolStep): unknown {\n if ('sendReceive' in step && hasReceive(step.sendReceive)) {\n return step.sendReceive.receive;\n }\n if ('receive' in step) {\n return step.receive;\n }\n if ('readSegment' in step) {\n // For readSegment, return both start and end chunk receive patterns\n const { readSegment } = step;\n if (hasEndChunk(readSegment) && hasStartChunk(readSegment)) {\n return {\n endChunk: readSegment.endChunk.receive,\n startChunk: readSegment.startChunk.receive,\n type: 'readSegment',\n };\n }\n }\n return {};\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springfield/ham-radio-utils",
3
- "version": "2.2.1",
3
+ "version": "3.0.0",
4
4
  "author": "Bryan Hunt",
5
5
  "license": "MIT",
6
6
  "packageManager": "yarn@4.9.2",
@@ -15,8 +15,8 @@
15
15
  "scripts": {
16
16
  "build": "tsc && cp src/db/* dist/db/ && cp src/schemas/* dist/schemas/",
17
17
  "commitlint": "commitlint --edit",
18
- "lint": "oxlint",
19
- "lint:fix": "oxlint --fix --fix-suggestions",
18
+ "lint": "oxlint --import-plugin --tsconfig tsconfig.json",
19
+ "lint:fix": "oxlint --import-plugin --tsconfig tsconfig.json --fix --fix-suggestions",
20
20
  "release": "semantic-release",
21
21
  "prepare": "husky"
22
22
  },
@@ -51,7 +51,7 @@
51
51
  "access": "public"
52
52
  },
53
53
  "dependencies": {
54
- "@springfield/ham-radio-api": "^16.1.1",
54
+ "@springfield/ham-radio-api": "^16.1.3",
55
55
  "ajv": "^8.17.1",
56
56
  "ajv-formats": "^3.0.1",
57
57
  "fishery": "^2.3.1",
@@ -68,9 +68,9 @@
68
68
  "@types/sprintf-js": "1.1.4",
69
69
  "chai": "5.2.1",
70
70
  "husky": "9.1.7",
71
- "oxlint": "1.3.0",
71
+ "oxlint": "1.11.2",
72
72
  "semantic-release": "23.1.1",
73
73
  "semantic-release-yarn": "3.0.2",
74
- "typescript": "5.8.3"
74
+ "typescript": "5.9.2"
75
75
  }
76
76
  }
package/src/index.ts CHANGED
@@ -3,12 +3,10 @@ export * from './memory/segmented-memory.js';
3
3
  export * from './test-utils/radio-channel-factory.js';
4
4
  export * from './test-utils/radio-programmed-channel-factory.js';
5
5
 
6
- export * from './utils/bcd-to-number.js';
7
6
  export * from './utils/band-plan.js';
8
7
  export * from './utils/frequency-display.js';
9
8
  export * from './utils/memory-channel-utils.js';
10
9
  export * from './utils/memory-data-utils.js';
11
- export * from './utils/number-to-bcd.js';
12
10
  export * from './utils/schema-validator.js';
13
11
  export * from './utils/to-hex-words.js';
14
12
  export * from './utils/ui-logger.js';
@@ -6,7 +6,7 @@ export class RadioSegmentedMemory {
6
6
  constructor(segments?: RadioMemorySegment[]) {
7
7
  this.segments = new Map();
8
8
 
9
- if (segments != undefined) {
9
+ if (segments) {
10
10
  for (const segment of segments) {
11
11
  this.segments.set(segment.startAddress, segment);
12
12
  }
@@ -43,7 +43,7 @@ export class RadioSegmentedMemory {
43
43
  result = iterator.next();
44
44
  }
45
45
 
46
- return undefined;
46
+ return {} as RadioMemorySegment;
47
47
  }
48
48
 
49
49
  public toArray(): RadioMemorySegment[] {
@@ -1,6 +1,4 @@
1
1
  import { sprintf } from 'sprintf-js';
2
2
  import { toHexWords } from './to-hex-words.js';
3
3
 
4
- export const formatChannel = (channelNumber: number, data: Uint8Array): string => {
5
- return sprintf('%2d : %s', channelNumber, toHexWords(data));
6
- };
4
+ export const formatChannel = (channelNumber: number, data: Uint8Array): string => sprintf('%2d : %s', channelNumber, toHexWords(data));
@@ -1,6 +1,4 @@
1
1
  import { sprintf } from 'sprintf-js';
2
2
  import { toHexWords } from './to-hex-words.js';
3
3
 
4
- export const formatMemoryData = (address: number, data: Uint8Array): string => {
5
- return sprintf('%04X : %s', address, toHexWords(data));
6
- };
4
+ export const formatMemoryData = (address: number, data: Uint8Array): string => sprintf('%04X : %s', address, toHexWords(data));
@@ -1,4 +1,4 @@
1
- import Ajv from 'ajv';
1
+ import { Ajv } from 'ajv';
2
2
  import addFormats from 'ajv-formats';
3
3
  import radioProtocolSchema from '../schemas/radio-protocol-schema.json' with { type: 'json' };
4
4
 
@@ -7,15 +7,20 @@ export interface ValidationResult {
7
7
  errors?: string[];
8
8
  }
9
9
 
10
+ interface AjvError {
11
+ instancePath?: string;
12
+ message?: string;
13
+ }
14
+
10
15
  export class SchemaValidator {
11
- private ajv: any;
16
+ private ajv: Ajv;
12
17
 
13
18
  constructor() {
14
- this.ajv = new (Ajv as any)({
19
+ this.ajv = new Ajv({
15
20
  allErrors: true,
16
21
  verbose: true,
17
22
  });
18
- (addFormats as any)(this.ajv);
23
+ (addFormats as unknown as (ajv: Ajv) => Ajv)(this.ajv);
19
24
  }
20
25
 
21
26
  validateRadioProtocol(config: unknown): ValidationResult {
@@ -26,11 +31,13 @@ export class SchemaValidator {
26
31
  return { valid: true };
27
32
  }
28
33
 
29
- const errors =
30
- validate.errors?.map((error: { instancePath?: string; message?: string }) => {
34
+ let errors: string[] = [];
35
+ if (validate.errors && validate.errors.length > 0) {
36
+ errors = validate.errors.map((error: AjvError) => {
31
37
  const path = error.instancePath || 'root';
32
38
  return `${path}: ${error.message}`;
33
- }) || [];
39
+ });
40
+ }
34
41
 
35
42
  return {
36
43
  errors,
@@ -2,12 +2,12 @@ export const toHexWords = (data: Uint8Array): string => {
2
2
  const hexData = Buffer.from(data).toString('hex');
3
3
  let formattedData = '';
4
4
 
5
- for (let i = 0; i < hexData.length; i += 4) {
6
- if (0 != i) {
5
+ for (let index = 0; index < hexData.length; index += 4) {
6
+ if (index !== 0) {
7
7
  formattedData += ' ';
8
8
  }
9
9
 
10
- formattedData += hexData.substring(i, i + 4);
10
+ formattedData += hexData.slice(index, index + 4);
11
11
  }
12
12
 
13
13
  return formattedData;
@@ -1,42 +1,62 @@
1
- import { BaseTransport } from '@loglayer/transport';
1
+ import type { LogLayerTransport } from '@loglayer/shared';
2
+ // eslint-disable-next-line no-duplicate-imports, sort-imports
3
+ import { BaseTransport, type LogLayerTransportParams } from '@loglayer/transport';
2
4
  import { LogLayer } from 'loglayer';
3
5
  import { UILogger } from './ui-logger.js';
4
6
 
7
+ interface LogEntry {
8
+ data: unknown;
9
+ hasData: boolean;
10
+ level: string;
11
+ message: string;
12
+ timestamp: string;
13
+ }
14
+
5
15
  /**
6
16
  * Custom LogLayer transport for capturing UI log entries.
7
17
  */
8
- const UILogTransport = class extends BaseTransport<any> {
9
- #callback: (logEntry: any) => void;
18
+ const UILogTransport = class extends BaseTransport<unknown> {
19
+ private callback: (logEntry: LogEntry) => void;
10
20
 
11
- constructor(callback: (logEntry: any) => void) {
21
+ constructor(callback: (logEntry: LogEntry) => void) {
12
22
  // Pass a dummy logger to BaseTransport
13
- super({ enabled: true, id: 'ui-logger-transport', logger: { log: () => {} } });
14
- this.#callback = callback;
23
+ super({
24
+ enabled: true,
25
+ id: 'ui-logger-transport',
26
+ logger: {
27
+ log: (): void => {
28
+ // Empty function for dummy logger
29
+ },
30
+ },
31
+ });
32
+ this.callback = callback;
15
33
  }
16
34
 
17
- shipToLogger(params: any) {
18
- const logEntry = {
35
+ shipToLogger(params: LogLayerTransportParams): unknown[] {
36
+ const logEntry: LogEntry = {
19
37
  data: params.data,
20
- hasData: params.hasData,
38
+ hasData: params.hasData ?? false,
21
39
  level: params.logLevel,
22
40
  message: params.messages.join(' '),
23
41
  timestamp: new Date().toISOString(),
24
42
  };
25
- this.#callback(logEntry);
43
+ this.callback(logEntry);
26
44
  return [];
27
45
  }
28
46
  };
29
47
 
30
48
  export interface UILoggerConfig {
31
- customTransport?: any;
49
+ customTransport?: LogLayerTransport;
32
50
  enableConsoleDebug?: boolean;
33
51
  }
34
52
 
53
+ // Move defaultCallback to outer scope to avoid recreating it on every call
54
+ const defaultCallback = (logEntry: LogEntry): void => {
55
+ // eslint-disable-next-line no-console
56
+ console.log(JSON.stringify(logEntry));
57
+ };
58
+
35
59
  export const createUILogger = function createUILogger(config: UILoggerConfig = {}): UILogger {
36
- // By default, just print to console as JSON
37
- const defaultCallback = (logEntry: any) => {
38
- console.log(JSON.stringify(logEntry));
39
- };
40
60
  const transport = config.customTransport || new UILogTransport(defaultCallback);
41
61
  const logger = new LogLayer({
42
62
  consoleDebug: config.enableConsoleDebug ?? false,
@@ -46,7 +66,7 @@ export const createUILogger = function createUILogger(config: UILoggerConfig = {
46
66
  return new UILogger(logger);
47
67
  };
48
68
 
49
- export const createUILoggerWithCallback = function createUILoggerWithCallback(callback: (logEntry: any) => void, config: UILoggerConfig = {}): UILogger {
69
+ export const createUILoggerWithCallback = function createUILoggerWithCallback(callback: (logEntry: LogEntry) => void, config: UILoggerConfig = {}): UILogger {
50
70
  const transport = new UILogTransport(callback);
51
71
  const logger = new LogLayer({
52
72
  consoleDebug: config.enableConsoleDebug ?? false,
@@ -22,12 +22,38 @@ import type { ILogLayer } from 'loglayer';
22
22
  * - Separate from debug logging avoids UI noise
23
23
  */
24
24
 
25
+ interface ProtocolContext {
26
+ variables?: Map<string, unknown>;
27
+ }
28
+
25
29
  /**
26
30
  * Generic protocol step interface for UI logging
27
31
  */
28
- export interface UIProtocolStep {
29
- [key: string]: any;
30
- }
32
+ export type UIProtocolStep = Record<string, unknown>;
33
+
34
+ /**
35
+ * Type guards for protocol step properties
36
+ */
37
+ const hasDescription = (obj: unknown): obj is { description: string } =>
38
+ typeof obj === 'object' && obj !== null && 'description' in obj && typeof (obj as Record<string, unknown>).description === 'string';
39
+
40
+ const hasReceive = (obj: unknown): obj is { receive: unknown } => typeof obj === 'object' && obj !== null && 'receive' in obj;
41
+
42
+ const hasEndChunk = (obj: unknown): obj is { endChunk: { receive: unknown } } =>
43
+ typeof obj === 'object' &&
44
+ obj !== null &&
45
+ 'endChunk' in obj &&
46
+ typeof (obj as Record<string, unknown>).endChunk === 'object' &&
47
+ (obj as Record<string, unknown>).endChunk !== null &&
48
+ 'receive' in ((obj as Record<string, unknown>).endChunk as Record<string, unknown>);
49
+
50
+ const hasStartChunk = (obj: unknown): obj is { startChunk: { receive: unknown } } =>
51
+ typeof obj === 'object' &&
52
+ obj !== null &&
53
+ 'startChunk' in obj &&
54
+ typeof (obj as Record<string, unknown>).startChunk === 'object' &&
55
+ (obj as Record<string, unknown>).startChunk !== null &&
56
+ 'receive' in ((obj as Record<string, unknown>).startChunk as Record<string, unknown>);
31
57
 
32
58
  /**
33
59
  * UI Logger for capturing command-level information for UI display
@@ -63,7 +89,7 @@ export class UILogger {
63
89
  }
64
90
 
65
91
  // eslint-disable-next-line max-params
66
- logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: any): void {
92
+ logCommandSuccess(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, context: ProtocolContext): void {
67
93
  const commandId = `${operation}-${stepIndex}`;
68
94
  const startTime = this.commandStartTimes.get(commandId) || Date.now();
69
95
  const endTime = Date.now();
@@ -73,20 +99,18 @@ export class UILogger {
73
99
  const description = this.getStepDescription(step);
74
100
 
75
101
  // Extract sent and received data from context
76
- const dataSent = context.variables?.get('lastSentData');
77
- const dataReceived = context.variables?.get('lastReceivedData');
102
+ const dataSent = context.variables && context.variables.get('lastSentData');
103
+ const dataReceived = context.variables && context.variables.get('lastReceivedData');
78
104
  const dataExpected = this.getExpectedData(step);
79
105
 
80
106
  // For readSegment, also extract chunk logs if present
81
- let dataChunks = undefined;
82
- if ('readSegment' === commandType) {
83
- dataChunks = context.variables?.get('lastReadSegmentChunks');
84
- // For readSegment, we don't need the flattened dataSent/dataReceived since we have dataChunks
85
- }
107
+ const dataChunks = commandType === 'readSegment' && context.variables && context.variables.get('lastReadSegmentChunks');
86
108
 
87
109
  // Convert dataSent and dataReceived to byte array format if they exist
88
- const dataSentArray = dataSent ? [...dataSent] : undefined;
89
- const dataReceivedArray = dataReceived ? [...dataReceived] : undefined;
110
+ // eslint-disable-next-line unicorn/prefer-spread
111
+ const dataSentArray = dataSent && Array.from(dataSent as Uint8Array);
112
+ // eslint-disable-next-line unicorn/prefer-spread
113
+ const dataReceivedArray = dataReceived && Array.from(dataReceived as Uint8Array);
90
114
 
91
115
  this.logger
92
116
  .withMetadata({
@@ -108,7 +132,7 @@ export class UILogger {
108
132
  }
109
133
 
110
134
  // eslint-disable-next-line max-params
111
- logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: any): void {
135
+ logCommandFailure(stepIndex: number, totalSteps: number, operation: string, step: UIProtocolStep, error: Error, context: ProtocolContext): void {
112
136
  const commandId = `${operation}-${stepIndex}`;
113
137
  const startTime = this.commandStartTimes.get(commandId) || Date.now();
114
138
  const endTime = Date.now();
@@ -118,11 +142,12 @@ export class UILogger {
118
142
  const description = this.getStepDescription(step);
119
143
 
120
144
  // Extract sent data from context
121
- const dataSent = context.variables?.get('lastSentData');
145
+ const dataSent = context.variables && context.variables.get('lastSentData');
122
146
  const dataExpected = this.getExpectedData(step);
123
147
 
124
148
  // Convert dataSent to byte array format if it exists
125
- const dataSentArray = dataSent ? [...dataSent] : undefined;
149
+ // eslint-disable-next-line unicorn/prefer-spread
150
+ const dataSentArray = dataSent && Array.from(dataSent as Uint8Array);
126
151
 
127
152
  this.logger
128
153
  .withMetadata({
@@ -165,26 +190,26 @@ export class UILogger {
165
190
  }
166
191
 
167
192
  private getStepDescription(step: UIProtocolStep): string {
168
- if ('sendReceive' in step && step.sendReceive.description) {
193
+ if ('sendReceive' in step && hasDescription(step.sendReceive)) {
169
194
  return step.sendReceive.description;
170
195
  }
171
- if ('send' in step && step.send.description) {
196
+ if ('send' in step && hasDescription(step.send)) {
172
197
  return step.send.description;
173
198
  }
174
- if ('receive' in step && step.receive.description) {
199
+ if ('receive' in step && hasDescription(step.receive)) {
175
200
  return step.receive.description;
176
201
  }
177
- if ('readSegment' in step && step.readSegment.description) {
202
+ if ('readSegment' in step && hasDescription(step.readSegment)) {
178
203
  return step.readSegment.description;
179
204
  }
180
- if ('writeSegment' in step && step.writeSegment.description) {
205
+ if ('writeSegment' in step && hasDescription(step.writeSegment)) {
181
206
  return step.writeSegment.description;
182
207
  }
183
208
  return 'No description';
184
209
  }
185
210
 
186
- private getExpectedData(step: UIProtocolStep): any {
187
- if ('sendReceive' in step && step.sendReceive.receive) {
211
+ private getExpectedData(step: UIProtocolStep): unknown {
212
+ if ('sendReceive' in step && hasReceive(step.sendReceive)) {
188
213
  return step.sendReceive.receive;
189
214
  }
190
215
  if ('receive' in step) {
@@ -192,12 +217,15 @@ export class UILogger {
192
217
  }
193
218
  if ('readSegment' in step) {
194
219
  // For readSegment, return both start and end chunk receive patterns
195
- return {
196
- endChunk: step.readSegment.endChunk.receive,
197
- startChunk: step.readSegment.startChunk.receive,
198
- type: 'readSegment',
199
- };
220
+ const { readSegment } = step;
221
+ if (hasEndChunk(readSegment) && hasStartChunk(readSegment)) {
222
+ return {
223
+ endChunk: readSegment.endChunk.receive,
224
+ startChunk: readSegment.startChunk.receive,
225
+ type: 'readSegment',
226
+ };
227
+ }
200
228
  }
201
- return undefined;
229
+ return {};
202
230
  }
203
231
  }
@@ -1,3 +0,0 @@
1
- import type { RadioMemorySegment } from '@springfield/ham-radio-api';
2
- export declare const formatSegment: (segment: RadioMemorySegment) => string;
3
- //# sourceMappingURL=memory-segment-utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-segment-utils.d.ts","sourceRoot":"","sources":["../../src/utils/memory-segment-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,eAAO,MAAM,aAAa,GAAI,SAAS,kBAAkB,KAAG,MAE3D,CAAC"}
@@ -1,6 +0,0 @@
1
- import { sprintf } from 'sprintf-js';
2
- import { toHexWords } from './to-hex-words.js';
3
- export const formatSegment = (segment) => {
4
- return sprintf('%04X : %s', segment.startAddress, toHexWords(segment.data));
5
- };
6
- //# sourceMappingURL=memory-segment-utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-segment-utils.js","sourceRoot":"","sources":["../../src/utils/memory-segment-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAA2B,EAAU,EAAE;IACnE,OAAO,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9E,CAAC,CAAC","sourcesContent":["import type { RadioMemorySegment } from '@springfield/ham-radio-api';\nimport { sprintf } from 'sprintf-js';\nimport { toHexWords } from './to-hex-words.js';\n\nexport const formatSegment = (segment: RadioMemorySegment): string => {\n return sprintf('%04X : %s', segment.startAddress, toHexWords(segment.data));\n};\n"]}
@@ -1,10 +0,0 @@
1
- export const bcdToNumber = (data: Uint8Array, offset?: number, length?: number): number => {
2
- let bcd = 0;
3
- const size = length ?? data.length;
4
-
5
- for (let i = offset ?? 0; i < size; i++) {
6
- bcd |= data[i] << (8 * i);
7
- }
8
-
9
- return parseInt(bcd.toString(16), 10) * 10;
10
- };
@@ -1,15 +0,0 @@
1
- export const numberToBcd = (value: number): Uint8Array => {
2
- const digits = value.toString(10);
3
- const numberOfBytes = Math.ceil(digits.length / 2);
4
-
5
- const data = new Uint8Array(numberOfBytes);
6
-
7
- let bcd = parseInt(digits, 16);
8
-
9
- for (let i = 0; i < numberOfBytes; i++) {
10
- data[i] = bcd & 0xff;
11
- bcd >>= 8;
12
- }
13
-
14
- return data;
15
- };