@marcuspuchalla/nachos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +674 -0
  3. package/README.md +345 -0
  4. package/dist/chunk-2FUTHZQQ.cjs +755 -0
  5. package/dist/chunk-2FUTHZQQ.cjs.map +1 -0
  6. package/dist/chunk-2HBCILJS.cjs +2034 -0
  7. package/dist/chunk-2HBCILJS.cjs.map +1 -0
  8. package/dist/chunk-7CFYWHS6.js +742 -0
  9. package/dist/chunk-7CFYWHS6.js.map +1 -0
  10. package/dist/chunk-PD72MVTX.cjs +160 -0
  11. package/dist/chunk-PD72MVTX.cjs.map +1 -0
  12. package/dist/chunk-ZDZ2B5PE.js +149 -0
  13. package/dist/chunk-ZDZ2B5PE.js.map +1 -0
  14. package/dist/chunk-ZRPJUEIZ.js +2020 -0
  15. package/dist/chunk-ZRPJUEIZ.js.map +1 -0
  16. package/dist/encoder/index.cjs +57 -0
  17. package/dist/encoder/index.cjs.map +1 -0
  18. package/dist/encoder/index.d.cts +72 -0
  19. package/dist/encoder/index.d.ts +72 -0
  20. package/dist/encoder/index.js +4 -0
  21. package/dist/encoder/index.js.map +1 -0
  22. package/dist/index.cjs +606 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.cts +494 -0
  25. package/dist/index.d.ts +494 -0
  26. package/dist/index.js +523 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/metafile-cjs.json +1 -0
  29. package/dist/metafile-esm.json +1 -0
  30. package/dist/parser/index.cjs +85 -0
  31. package/dist/parser/index.cjs.map +1 -0
  32. package/dist/parser/index.d.cts +72 -0
  33. package/dist/parser/index.d.ts +72 -0
  34. package/dist/parser/index.js +4 -0
  35. package/dist/parser/index.js.map +1 -0
  36. package/dist/types-DvNlfbKB.d.cts +301 -0
  37. package/dist/types-DvNlfbKB.d.ts +301 -0
  38. package/dist/useCborSimpleEncoder-ButVU988.d.cts +268 -0
  39. package/dist/useCborSimpleEncoder-TVxzNJ_9.d.ts +268 -0
  40. package/dist/useCborTag-B_iaShG6.d.ts +142 -0
  41. package/dist/useCborTag-BfTIV8HM.d.cts +142 -0
  42. package/package.json +102 -0
  43. package/src/__tests__/public-api.test.ts +326 -0
  44. package/src/encoder/__tests__/cbor-collection-encoder.test.ts +331 -0
  45. package/src/encoder/__tests__/cbor-integer-encoder.test.ts +283 -0
  46. package/src/encoder/__tests__/cbor-simple-encoder.test.ts +224 -0
  47. package/src/encoder/__tests__/cbor-string-encoder.test.ts +345 -0
  48. package/src/encoder/__tests__/cbor-tag-encoder.test.ts +565 -0
  49. package/src/encoder/composables/#useCborTagEncoder.ts# +158 -0
  50. package/src/encoder/composables/useCborCollectionEncoder.ts +424 -0
  51. package/src/encoder/composables/useCborEncoder.ts +203 -0
  52. package/src/encoder/composables/useCborIntegerEncoder.ts +188 -0
  53. package/src/encoder/composables/useCborSimpleEncoder.ts +266 -0
  54. package/src/encoder/composables/useCborStringEncoder.ts +266 -0
  55. package/src/encoder/composables/useCborTagEncoder.ts +158 -0
  56. package/src/encoder/index.ts +35 -0
  57. package/src/encoder/types.ts +88 -0
  58. package/src/encoder/utils.ts +80 -0
  59. package/src/index.ts +434 -0
  60. package/src/parser/__tests__/ast-tree-structure.test.ts +311 -0
  61. package/src/parser/__tests__/cbor-collection-errors.test.ts +296 -0
  62. package/src/parser/__tests__/cbor-collection.test.ts +369 -0
  63. package/src/parser/__tests__/cbor-deterministic-encoding.test.ts +432 -0
  64. package/src/parser/__tests__/cbor-diagnostic.test.ts +333 -0
  65. package/src/parser/__tests__/cbor-duplicate-keys.test.ts +235 -0
  66. package/src/parser/__tests__/cbor-float-errors.test.ts +222 -0
  67. package/src/parser/__tests__/cbor-float.test.ts +502 -0
  68. package/src/parser/__tests__/cbor-integer-errors.test.ts +139 -0
  69. package/src/parser/__tests__/cbor-integer.test.ts +200 -0
  70. package/src/parser/__tests__/cbor-map-duplicate-keys.test.ts +403 -0
  71. package/src/parser/__tests__/cbor-parser-errors.test.ts +126 -0
  72. package/src/parser/__tests__/cbor-security-dos-protection.test.ts +503 -0
  73. package/src/parser/__tests__/cbor-sequences.test.ts +150 -0
  74. package/src/parser/__tests__/cbor-source-map.test.ts +321 -0
  75. package/src/parser/__tests__/cbor-standard-tags.test.ts +340 -0
  76. package/src/parser/__tests__/cbor-string-errors.test.ts +227 -0
  77. package/src/parser/__tests__/cbor-string.test.ts +224 -0
  78. package/src/parser/__tests__/cbor-tag-advanced.test.ts +500 -0
  79. package/src/parser/__tests__/cbor-tag-errors.test.ts +447 -0
  80. package/src/parser/__tests__/cbor-tag-source-map.test.ts +360 -0
  81. package/src/parser/__tests__/cbor-tag.test.ts +684 -0
  82. package/src/parser/__tests__/extreme-edge-cases.test.ts +146 -0
  83. package/src/parser/__tests__/pathBuilder.test.ts +256 -0
  84. package/src/parser/__tests__/rfc-test-vectors.test.ts +607 -0
  85. package/src/parser/__tests__/security-limits.test.ts +248 -0
  86. package/src/parser/__tests__/utils-errors.test.ts +127 -0
  87. package/src/parser/composables/useCborCollection.ts +509 -0
  88. package/src/parser/composables/useCborDiagnostic.ts +381 -0
  89. package/src/parser/composables/useCborFloat.ts +256 -0
  90. package/src/parser/composables/useCborInteger.ts +114 -0
  91. package/src/parser/composables/useCborParser.ts +951 -0
  92. package/src/parser/composables/useCborString.ts +330 -0
  93. package/src/parser/composables/useCborStringTypes.ts +129 -0
  94. package/src/parser/composables/useCborTag.ts +739 -0
  95. package/src/parser/index.ts +56 -0
  96. package/src/parser/types.ts +371 -0
  97. package/src/parser/utils/pathBuilder.ts +259 -0
  98. package/src/parser/utils.ts +398 -0
  99. package/src/utils/__tests__/logger.test.ts +186 -0
  100. package/src/utils/logger.ts +96 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * CBOR Sequences Tests (RFC 8742)
3
+ * TDD: Tests written BEFORE implementation
4
+ *
5
+ * A CBOR Sequence is a concatenation of zero or more CBOR data items.
6
+ * Unlike a CBOR array, sequences have no length prefix.
7
+ */
8
+
9
+ import { describe, it, expect } from 'vitest'
10
+ import { useCborParser } from '../composables/useCborParser'
11
+
12
+ describe('CBOR Sequences (RFC 8742)', () => {
13
+ const { parse, parseSequence } = useCborParser()
14
+
15
+ describe('parseSequence', () => {
16
+ it('should parse empty sequence', () => {
17
+ const hex = ''
18
+ const result = parseSequence(hex)
19
+
20
+ expect(result).toEqual([])
21
+ })
22
+
23
+ it('should parse single item sequence', () => {
24
+ const hex = '01' // integer 1
25
+ const result = parseSequence(hex)
26
+
27
+ expect(result).toEqual([1])
28
+ })
29
+
30
+ it('should parse sequence of integers', () => {
31
+ // 01 02 03 = three separate integers
32
+ const hex = '010203'
33
+ const result = parseSequence(hex)
34
+
35
+ expect(result).toEqual([1, 2, 3])
36
+ })
37
+
38
+ it('should parse sequence of mixed types', () => {
39
+ // 01 (int 1) + 6568656c6c6f (text "hello") + f5 (true)
40
+ const hex = '016568656c6c6ff5'
41
+ const result = parseSequence(hex)
42
+
43
+ expect(result).toHaveLength(3)
44
+ expect(result[0]).toBe(1)
45
+ expect(result[1]).toBe('hello')
46
+ expect(result[2]).toBe(true)
47
+ })
48
+
49
+ it('should parse sequence with arrays', () => {
50
+ // 83010203 (array [1,2,3]) + 82040 5 (array [4,5])
51
+ const hex = '8301020382 0405'.replace(/\s/g, '')
52
+ const result = parseSequence(hex)
53
+
54
+ expect(result).toHaveLength(2)
55
+ expect(result[0]).toEqual([1, 2, 3])
56
+ expect(result[1]).toEqual([4, 5])
57
+ })
58
+
59
+ it('should parse sequence with maps', () => {
60
+ // a1616101 ({"a": 1}) + a1616202 ({"b": 2})
61
+ const hex = 'a1616101a1616202'
62
+ const result = parseSequence(hex)
63
+
64
+ expect(result).toHaveLength(2)
65
+ })
66
+
67
+ it('should parse sequence with tagged values', () => {
68
+ // c11a514b67b0 (tag 1, epoch) + c11a514b67b1 (tag 1, epoch+1)
69
+ const hex = 'c11a514b67b0c11a514b67b1'
70
+ const result = parseSequence(hex)
71
+
72
+ expect(result).toHaveLength(2)
73
+ expect((result[0] as any).tag).toBe(1)
74
+ expect((result[1] as any).tag).toBe(1)
75
+ })
76
+
77
+ it('should handle indefinite-length items in sequence', () => {
78
+ // 9f010203ff (indefinite array [1,2,3]) + 05 (int 5)
79
+ const hex = '9f010203ff05'
80
+ const result = parseSequence(hex)
81
+
82
+ expect(result).toHaveLength(2)
83
+ expect([...(result[0] as any)]).toEqual([1, 2, 3])
84
+ expect(result[1]).toBe(5)
85
+ })
86
+
87
+ it('should throw on malformed sequence item', () => {
88
+ // 83 01 02 (incomplete array - needs 3 items)
89
+ const hex = '830102'
90
+
91
+ expect(() => parseSequence(hex)).toThrow()
92
+ })
93
+
94
+ it('should respect options for all items', () => {
95
+ // Two non-canonical integers
96
+ const hex = '18001801' // 0 encoded as 2 bytes, 1 encoded as 2 bytes
97
+
98
+ expect(() => parseSequence(hex, { validateCanonical: true }))
99
+ .toThrow(/non-canonical/i)
100
+ })
101
+ })
102
+
103
+ describe('parseSequenceWithSourceMap', () => {
104
+ it('should return source maps for each item', () => {
105
+ const hex = '010203'
106
+ const { parseSequenceWithSourceMap } = useCborParser()
107
+ const result = parseSequenceWithSourceMap(hex)
108
+
109
+ expect(result.values).toEqual([1, 2, 3])
110
+ expect(result.sourceMaps).toHaveLength(3)
111
+
112
+ // Each item should have its own source map
113
+ expect(result.sourceMaps[0][0].start).toBe(0)
114
+ expect(result.sourceMaps[0][0].end).toBe(1)
115
+
116
+ expect(result.sourceMaps[1][0].start).toBe(1)
117
+ expect(result.sourceMaps[1][0].end).toBe(2)
118
+
119
+ expect(result.sourceMaps[2][0].start).toBe(2)
120
+ expect(result.sourceMaps[2][0].end).toBe(3)
121
+ })
122
+ })
123
+
124
+ describe('Edge cases', () => {
125
+ it('should handle sequence with only break code (invalid)', () => {
126
+ const hex = 'ff' // break code outside indefinite context
127
+
128
+ expect(() => parseSequence(hex)).toThrow()
129
+ })
130
+
131
+ it('should handle large sequence', () => {
132
+ // 100 integers: 00 01 02 ... 63 (0-99 in hex)
133
+ let hex = ''
134
+ for (let i = 0; i < 100; i++) {
135
+ if (i < 24) {
136
+ hex += i.toString(16).padStart(2, '0')
137
+ } else {
138
+ hex += '18' + i.toString(16).padStart(2, '0')
139
+ }
140
+ }
141
+
142
+ const result = parseSequence(hex)
143
+ expect(result).toHaveLength(100)
144
+ expect(result[0]).toBe(0)
145
+ expect(result[23]).toBe(23)
146
+ expect(result[24]).toBe(24)
147
+ expect(result[99]).toBe(99)
148
+ })
149
+ })
150
+ })
@@ -0,0 +1,321 @@
1
+ /**
2
+ * CBOR Source Map Generation Tests
3
+ * Tests the parseWithSourceMap function for bidirectional highlighting
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest'
7
+ import { useCborParser } from '../composables/useCborParser'
8
+
9
+ describe('useCborParser - Source Map Generation', () => {
10
+ describe('Simple Values', () => {
11
+ it('should generate source map for integer', () => {
12
+ const { parseWithSourceMap } = useCborParser()
13
+ const result = parseWithSourceMap('1864') // 100
14
+
15
+ expect(result.value).toBe(100)
16
+ expect(result.bytesRead).toBe(2)
17
+ expect(result.sourceMap).toHaveLength(1)
18
+ expect(result.sourceMap[0]).toEqual({
19
+ path: '',
20
+ start: 0,
21
+ end: 2,
22
+ majorType: 0,
23
+ type: 'Unsigned Integer'
24
+ })
25
+ })
26
+
27
+ it('should generate source map for text string', () => {
28
+ const { parseWithSourceMap } = useCborParser()
29
+ const result = parseWithSourceMap('6449455446') // "IETF"
30
+
31
+ expect(result.value).toBe('IETF')
32
+ expect(result.sourceMap).toHaveLength(2) // header + content
33
+
34
+ // Header
35
+ expect(result.sourceMap[0]).toMatchObject({
36
+ path: '',
37
+ start: 0,
38
+ majorType: 3,
39
+ isHeader: true
40
+ })
41
+
42
+ // Content
43
+ expect(result.sourceMap[1]).toMatchObject({
44
+ path: '#content',
45
+ majorType: 3,
46
+ parent: ''
47
+ })
48
+ })
49
+
50
+ it('should generate source map for boolean', () => {
51
+ const { parseWithSourceMap } = useCborParser()
52
+ const result = parseWithSourceMap('f5') // true
53
+
54
+ expect(result.value).toBe(true)
55
+ expect(result.sourceMap).toHaveLength(1)
56
+ expect(result.sourceMap[0]).toEqual({
57
+ path: '',
58
+ start: 0,
59
+ end: 1,
60
+ majorType: 7,
61
+ type: 'Simple: true'
62
+ })
63
+ })
64
+ })
65
+
66
+ describe('Arrays', () => {
67
+ it('should generate source map for simple array', () => {
68
+ const { parseWithSourceMap } = useCborParser()
69
+ const result = parseWithSourceMap('83010203') // [1, 2, 3]
70
+
71
+ expect(result.value).toEqual([1, 2, 3])
72
+ expect(result.sourceMap).toHaveLength(4) // array + 3 elements
73
+
74
+ // Array itself (header only)
75
+ expect(result.sourceMap[0]).toMatchObject({
76
+ path: '',
77
+ start: 0,
78
+ end: 1, // header only (83)
79
+ majorType: 4,
80
+ type: 'array(3)',
81
+ children: ['[0]', '[1]', '[2]']
82
+ })
83
+
84
+ // First element
85
+ expect(result.sourceMap[1]).toMatchObject({
86
+ path: '[0]',
87
+ start: 1,
88
+ end: 2,
89
+ majorType: 0,
90
+ type: 'Unsigned Integer'
91
+ })
92
+
93
+ // Second element
94
+ expect(result.sourceMap[2]).toMatchObject({
95
+ path: '[1]',
96
+ start: 2,
97
+ end: 3,
98
+ majorType: 0,
99
+ type: 'Unsigned Integer'
100
+ })
101
+
102
+ // Third element
103
+ expect(result.sourceMap[3]).toMatchObject({
104
+ path: '[2]',
105
+ start: 3,
106
+ end: 4,
107
+ majorType: 0,
108
+ type: 'Unsigned Integer'
109
+ })
110
+ })
111
+
112
+ it('should generate source map for nested array', () => {
113
+ const { parseWithSourceMap } = useCborParser()
114
+ const result = parseWithSourceMap('8201820203') // [1, [2, 3]]
115
+
116
+ expect(result.value).toEqual([1, [2, 3]])
117
+ expect(result.sourceMap.length).toBeGreaterThan(3)
118
+
119
+ // Root array
120
+ expect(result.sourceMap[0].path).toBe('')
121
+ expect(result.sourceMap[0].majorType).toBe(4)
122
+
123
+ // First element (integer 1)
124
+ expect(result.sourceMap[1].path).toBe('[0]')
125
+ expect(result.sourceMap[1].majorType).toBe(0)
126
+
127
+ // Nested array
128
+ expect(result.sourceMap[2].path).toBe('[1]')
129
+ expect(result.sourceMap[2].majorType).toBe(4)
130
+
131
+ // Elements in nested array
132
+ expect(result.sourceMap[3].path).toBe('[1][0]')
133
+ expect(result.sourceMap[4].path).toBe('[1][1]')
134
+ })
135
+ })
136
+
137
+ describe('Maps', () => {
138
+ it('should generate source map for simple map', () => {
139
+ const { parseWithSourceMap } = useCborParser()
140
+ const result = parseWithSourceMap('a16161 01'.replace(/\s/g, '')) // {a: 1}
141
+
142
+ expect(result.value).toEqual(new Map([['a', 1]]))
143
+ expect(result.sourceMap.length).toBeGreaterThan(0)
144
+
145
+ // Map itself (header only)
146
+ expect(result.sourceMap[0]).toMatchObject({
147
+ path: '',
148
+ start: 0,
149
+ end: 1, // header only (a1)
150
+ majorType: 5,
151
+ type: 'map(1)',
152
+ children: ['.a']
153
+ })
154
+
155
+ // Value for key "a"
156
+ const valueEntry = result.sourceMap.find(e => e.path === '.a')
157
+ expect(valueEntry).toBeDefined()
158
+ expect(valueEntry?.majorType).toBe(0)
159
+ expect(valueEntry?.type).toBe('Unsigned Integer')
160
+ })
161
+
162
+ it('should generate source map for Cardano amount example', () => {
163
+ const { parseWithSourceMap } = useCborParser()
164
+ // {"amount": 1000000}
165
+ const result = parseWithSourceMap('a166616d6f756e741a000f4240')
166
+
167
+ expect(result.value).toEqual(new Map([['amount', 1000000]]))
168
+ expect(result.sourceMap.length).toBeGreaterThan(0)
169
+
170
+ // Find the amount value in source map
171
+ const amountEntry = result.sourceMap.find(e => e.path === '.amount')
172
+ expect(amountEntry).toBeDefined()
173
+ expect(amountEntry?.majorType).toBe(0) // unsigned integer
174
+ expect(amountEntry?.type).toBe('Unsigned Integer')
175
+
176
+ // The amount value should be at bytes 8-13 (1a 00 0f 42 40)
177
+ // a1 (map) + 66 61 6d 6f 75 6e 74 ("amount") = 8 bytes, then value starts
178
+ expect(amountEntry?.start).toBe(8)
179
+ expect(amountEntry?.end).toBe(13)
180
+ })
181
+
182
+ it('should generate source map for nested map', () => {
183
+ const { parseWithSourceMap } = useCborParser()
184
+ // {a: {b: 2}}
185
+ const result = parseWithSourceMap('a16161a16162 02'.replace(/\s/g, ''))
186
+
187
+ expect(result.value).toEqual(new Map([['a', new Map([['b', 2]])]]))
188
+
189
+ // Check nested path
190
+ const nestedEntry = result.sourceMap.find(e => e.path === '.a.b')
191
+ expect(nestedEntry).toBeDefined()
192
+ expect(nestedEntry?.majorType).toBe(0)
193
+ })
194
+ })
195
+
196
+ describe('Complex Structures', () => {
197
+ it('should generate source map for array of maps', () => {
198
+ const { parseWithSourceMap } = useCborParser()
199
+ // [{x: 1}, {y: 2}]
200
+ const result = parseWithSourceMap('82a16178 01a16179 02'.replace(/\s/g, ''))
201
+
202
+ expect(result.value).toEqual([new Map([['x', 1]]), new Map([['y', 2]])])
203
+
204
+ // Check paths
205
+ const xEntry = result.sourceMap.find(e => e.path === '[0].x')
206
+ const yEntry = result.sourceMap.find(e => e.path === '[1].y')
207
+
208
+ expect(xEntry).toBeDefined()
209
+ expect(yEntry).toBeDefined()
210
+ })
211
+
212
+ it('should generate source map for Cardano UTXO structure', () => {
213
+ const { parseWithSourceMap } = useCborParser()
214
+ // Simplified UTXO: [[txHash, index], [address, amount]]
215
+ // Using short byte strings for simplicity
216
+ const hex = '82' + // array of 2
217
+ '82' + // first element: array of 2
218
+ '4448bd01d5' + // 4-byte tx hash
219
+ '00' + // index 0
220
+ '82' + // second element: array of 2
221
+ '44000dae07' + // 4-byte address
222
+ '1a000f4240' // amount: 1000000
223
+
224
+ const result = parseWithSourceMap(hex)
225
+
226
+ expect(Array.isArray(result.value)).toBe(true)
227
+ expect(result.sourceMap.length).toBeGreaterThan(5)
228
+
229
+ // Root array
230
+ expect(result.sourceMap[0].path).toBe('')
231
+ expect(result.sourceMap[0].majorType).toBe(4)
232
+
233
+ // First nested array [txHash, index]
234
+ const firstArray = result.sourceMap.find(e => e.path === '[0]')
235
+ expect(firstArray?.majorType).toBe(4)
236
+
237
+ // Amount value
238
+ const amountEntry = result.sourceMap.find(e => e.path === '[1][1]')
239
+ expect(amountEntry?.majorType).toBe(0)
240
+ })
241
+ })
242
+
243
+ describe('Byte Positions', () => {
244
+ it('should have correct byte positions for all entries', () => {
245
+ const { parseWithSourceMap } = useCborParser()
246
+ const result = parseWithSourceMap('83010203')
247
+
248
+ // Verify all entries have valid byte ranges
249
+ result.sourceMap.forEach(entry => {
250
+ expect(entry.start).toBeGreaterThanOrEqual(0)
251
+ expect(entry.end).toBeGreaterThan(entry.start)
252
+ expect(entry.end).toBeLessThanOrEqual(4) // total bytes
253
+ })
254
+ })
255
+
256
+ it('should have non-overlapping byte ranges for siblings', () => {
257
+ const { parseWithSourceMap } = useCborParser()
258
+ const result = parseWithSourceMap('83010203')
259
+
260
+ // Get sibling elements (array elements)
261
+ const elements = result.sourceMap.filter(e => e.path.match(/^\[\d+\]$/))
262
+
263
+ // Verify no overlaps between siblings
264
+ for (let i = 0; i < elements.length - 1; i++) {
265
+ expect(elements[i].end).toBeLessThanOrEqual(elements[i + 1].start)
266
+ }
267
+ })
268
+ })
269
+
270
+ describe('Byte String Content Highlighting', () => {
271
+ it('should create separate header and content entries for byte strings', () => {
272
+ const { parseWithSourceMap } = useCborParser()
273
+ // 58 20 = bytes(32), followed by 32 bytes of data
274
+ const result = parseWithSourceMap('582048bd01d51e580cde15afa6d28f63d89c9137b93a910e5941192e26b12906106700')
275
+
276
+ // Should have 2 entries: header + content
277
+ expect(result.sourceMap).toHaveLength(2)
278
+
279
+ // Header entry
280
+ const headerEntry = result.sourceMap[0]
281
+ expect(headerEntry.path).toBe('')
282
+ expect(headerEntry.start).toBe(0)
283
+ expect(headerEntry.end).toBe(2) // 58 20
284
+ expect(headerEntry.isHeader).toBe(true)
285
+ expect(headerEntry.contentPath).toBe('#content')
286
+ expect(headerEntry.children).toContain('#content')
287
+
288
+ // Content entry
289
+ const contentEntry = result.sourceMap[1]
290
+ expect(contentEntry.path).toBe('#content')
291
+ expect(contentEntry.start).toBe(2) // After header
292
+ expect(contentEntry.end).toBe(34) // 32 bytes of data
293
+ expect(contentEntry.isContent).toBe(true)
294
+ expect(contentEntry.parent).toBe('')
295
+ })
296
+
297
+ it('should create separate header and content entries for nested byte strings', () => {
298
+ const { parseWithSourceMap } = useCborParser()
299
+ // Array containing a 32-byte byte string
300
+ // 82 = array(2), 58 20 = bytes(32), followed by 32 bytes, then 00 = integer 0
301
+ const result = parseWithSourceMap('82582048bd01d51e580cde15afa6d28f63d89c9137b93a910e5941192e26b12906106700 00'.replace(/\s/g, ''))
302
+
303
+ // Find the byte string header and content entries
304
+ const byteStringHeader = result.sourceMap.find(e => e.path === '[0]' && e.isHeader)
305
+ const byteStringContent = result.sourceMap.find(e => e.path === '[0]#content' && e.isContent)
306
+
307
+ expect(byteStringHeader).toBeDefined()
308
+ expect(byteStringContent).toBeDefined()
309
+
310
+ // Header should be at bytes 1-3 (82 58 20)
311
+ expect(byteStringHeader?.start).toBe(1)
312
+ expect(byteStringHeader?.end).toBe(3)
313
+ expect(byteStringHeader?.contentPath).toBe('[0]#content')
314
+
315
+ // Content should be at bytes 3-35 (32 bytes of data)
316
+ expect(byteStringContent?.start).toBe(3)
317
+ expect(byteStringContent?.end).toBe(35)
318
+ expect(byteStringContent?.parent).toBe('[0]')
319
+ })
320
+ })
321
+ })