@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,369 @@
1
+ /**
2
+ * CBOR Collection Parser Tests
3
+ * Major Type 4 (Arrays) and Major Type 5 (Maps)
4
+ * Following RFC 8949 specification
5
+ */
6
+
7
+ import { describe, it, expect } from 'vitest'
8
+ import { useCborCollection } from '../composables/useCborCollection'
9
+
10
+ describe('useCborCollection', () => {
11
+ describe('parseArray (Major Type 4)', () => {
12
+ describe('Empty and Small Arrays', () => {
13
+ it('should parse empty array', () => {
14
+ const { parseArray } = useCborCollection()
15
+
16
+ // RFC 8949: [] = 0x80
17
+ const result = parseArray('80')
18
+ expect(result.value).toEqual([])
19
+ expect(result.bytesRead).toBe(1)
20
+ })
21
+
22
+ it('should parse array with small integers [1, 2, 3]', () => {
23
+ const { parseArray } = useCborCollection()
24
+
25
+ // RFC 8949: [1, 2, 3] = 0x83 0x01 0x02 0x03
26
+ const result = parseArray('83010203')
27
+ expect(result.value).toEqual([1, 2, 3])
28
+ expect(result.bytesRead).toBe(4)
29
+ })
30
+
31
+ it('should parse array with mixed values [1, 23, 100]', () => {
32
+ const { parseArray } = useCborCollection()
33
+
34
+ // [1, 23, 100] = 0x83 0x01 0x17 0x18 0x64
35
+ const result = parseArray('8301171864')
36
+ expect(result.value).toEqual([1, 23, 100])
37
+ expect(result.bytesRead).toBe(5)
38
+ })
39
+ })
40
+
41
+ describe('Arrays with Strings', () => {
42
+ it('should parse array with text strings ["a", "b", "c"]', () => {
43
+ const { parseArray } = useCborCollection()
44
+
45
+ // ["a", "b", "c"] = 0x83 0x61 0x61 0x61 0x62 0x61 0x63
46
+ const result = parseArray('83616161626163')
47
+ expect(result.value).toEqual(['a', 'b', 'c'])
48
+ expect(result.bytesRead).toBe(7)
49
+ })
50
+
51
+ it('should parse array with empty string [""]', () => {
52
+ const { parseArray } = useCborCollection()
53
+
54
+ // [""] = 0x81 0x60
55
+ const result = parseArray('8160')
56
+ expect(result.value).toEqual([''])
57
+ expect(result.bytesRead).toBe(2)
58
+ })
59
+
60
+ it('should parse array with UTF-8 strings ["Hello", "世界"]', () => {
61
+ const { parseArray } = useCborCollection()
62
+
63
+ // ["Hello", "世界"]
64
+ // "Hello" = 0x65 "H" "e" "l" "l" "o"
65
+ // "世界" = 0x66 0xe4 0xb8 0x96 0xe7 0x95 0x8c
66
+ const result = parseArray('826548656c6c6f66e4b896e7958c')
67
+ expect(result.value).toEqual(['Hello', '世界'])
68
+ expect(result.bytesRead).toBe(14)
69
+ })
70
+ })
71
+
72
+ describe('Nested Arrays', () => {
73
+ it('should parse nested array [[1, 2], [3, 4]]', () => {
74
+ const { parseArray } = useCborCollection()
75
+
76
+ // [[1, 2], [3, 4]] = 0x82 [0x82 0x01 0x02] [0x82 0x03 0x04]
77
+ const result = parseArray('828201028203 04')
78
+ expect(result.value).toEqual([[1, 2], [3, 4]])
79
+ expect(result.bytesRead).toBe(7)
80
+ })
81
+
82
+ it('should parse deeply nested arrays [[[1]]]', () => {
83
+ const { parseArray } = useCborCollection()
84
+
85
+ // [[[1]]] = 0x81 0x81 0x81 0x01
86
+ const result = parseArray('81818101')
87
+ expect(result.value).toEqual([[[1]]])
88
+ expect(result.bytesRead).toBe(4)
89
+ })
90
+
91
+ it('should parse mixed nested structure [1, [2, 3], 4]', () => {
92
+ const { parseArray } = useCborCollection()
93
+
94
+ // [1, [2, 3], 4] = 0x83 0x01 [0x82 0x02 0x03] 0x04
95
+ const result = parseArray('83018202 0304')
96
+ expect(result.value).toEqual([1, [2, 3], 4])
97
+ expect(result.bytesRead).toBe(6)
98
+ })
99
+ })
100
+
101
+ describe('Arrays with 1-byte Length Encoding', () => {
102
+ it('should parse array with 24 elements (1-byte length)', () => {
103
+ const { parseArray } = useCborCollection()
104
+
105
+ // Array of 24 zeros = 0x98 0x18 + 24 times 0x00
106
+ const hex = '9818' + '00'.repeat(24)
107
+ const result = parseArray(hex)
108
+ expect(result.value).toHaveLength(24)
109
+ expect(result.value.every(v => v === 0)).toBe(true)
110
+ expect(result.bytesRead).toBe(2 + 24)
111
+ })
112
+
113
+ it('should parse array with 100 integers (1-byte length)', () => {
114
+ const { parseArray } = useCborCollection()
115
+
116
+ // Array of 100 ones = 0x98 0x64 + 100 times 0x01
117
+ const hex = '9864' + '01'.repeat(100)
118
+ const result = parseArray(hex)
119
+ expect(result.value).toHaveLength(100)
120
+ expect(result.value.every(v => v === 1)).toBe(true)
121
+ expect(result.bytesRead).toBe(2 + 100)
122
+ })
123
+ })
124
+
125
+ describe('Indefinite-Length Arrays', () => {
126
+ it('should parse indefinite-length array [_ 1, 2, 3]', () => {
127
+ const { parseArray } = useCborCollection()
128
+
129
+ // [_ 1, 2, 3] = 0x9f 0x01 0x02 0x03 0xff (break)
130
+ const result = parseArray('9f010203ff')
131
+ expect(Array.isArray(result.value)).toBe(true)
132
+ const arr = result.value as any[]
133
+ expect(arr[0]).toBe(1)
134
+ expect(arr[1]).toBe(2)
135
+ expect(arr[2]).toBe(3)
136
+ expect(result.bytesRead).toBe(5)
137
+ })
138
+
139
+ it('should parse indefinite-length empty array [_]', () => {
140
+ const { parseArray } = useCborCollection()
141
+
142
+ // [_] = 0x9f 0xff
143
+ const result = parseArray('9fff')
144
+ expect(Array.isArray(result.value)).toBe(true)
145
+ expect(result.value).toHaveLength(0)
146
+ expect(result.bytesRead).toBe(2)
147
+ })
148
+
149
+ it('should parse indefinite-length nested array [_ 1, [2, 3], [4, 5]]', () => {
150
+ const { parseArray } = useCborCollection()
151
+
152
+ // [_ 1, [2, 3], [4, 5]] = 0x9f 0x01 0x82 0x02 0x03 0x82 0x04 0x05 0xff
153
+ const result = parseArray('9f018202038204 05ff')
154
+ expect(Array.isArray(result.value)).toBe(true)
155
+ const arr = result.value as any[]
156
+ expect(arr[0]).toBe(1)
157
+ expect(arr[1]).toEqual([2, 3])
158
+ expect(arr[2]).toEqual([4, 5])
159
+ expect(result.bytesRead).toBe(9)
160
+ })
161
+ })
162
+
163
+ describe('Real Cardano Examples', () => {
164
+ it('should parse Cardano UTXO array structure', () => {
165
+ const { parseArray } = useCborCollection()
166
+
167
+ // Simplified Cardano UTXO: [[txHash, outputIndex]]
168
+ // Array of 1 element: [32-byte hash, integer 0]
169
+ // 0x81 = array(1)
170
+ // 0x82 = array(2) - the UTXO pair
171
+ // 0x5820 = bytes(32) - transaction hash
172
+ // 32 bytes of hash data
173
+ // 0x00 = integer 0 (output index)
174
+ const txHash = '48bd01d51e580cde15afa6d28f63d89c9137b93a910e5941192e26b129061067'
175
+ const hex = `81825820${txHash}00`
176
+
177
+ const result = parseArray(hex)
178
+ expect(result.value).toHaveLength(1)
179
+ expect(Array.isArray(result.value[0])).toBe(true)
180
+ expect(result.value[0]).toHaveLength(2)
181
+ expect(result.value[0][1]).toBe(0) // output index
182
+ })
183
+
184
+ it('should parse Cardano amount array [lovelace]', () => {
185
+ const { parseArray } = useCborCollection()
186
+
187
+ // Array with Cardano amounts: [1000000, 2000000, 5000000]
188
+ // 1000000 = 0x1a 0x000f4240
189
+ // 2000000 = 0x1a 0x001e8480
190
+ // 5000000 = 0x1a 0x004c4b40
191
+ const result = parseArray('831a000f42401a001e84801a004c4b40')
192
+ expect(result.value).toEqual([1000000, 2000000, 5000000])
193
+ expect(result.bytesRead).toBe(16)
194
+ })
195
+ })
196
+ })
197
+
198
+ describe('parseMap (Major Type 5)', () => {
199
+ describe('Empty and Small Maps', () => {
200
+ it('should parse empty map {}', () => {
201
+ const { parseMap } = useCborCollection()
202
+
203
+ // RFC 8949: {} = 0xa0
204
+ const result = parseMap('a0')
205
+ expect(result.value).toEqual(new Map())
206
+ expect(result.bytesRead).toBe(1)
207
+ })
208
+
209
+ it('should parse map with one key-value pair {"a": 1}', () => {
210
+ const { parseMap } = useCborCollection()
211
+
212
+ // {"a": 1} = 0xa1 0x61 "a" 0x01
213
+ const result = parseMap('a16161 01')
214
+ expect(result.value).toEqual(new Map([['a', 1]]))
215
+ expect(result.bytesRead).toBe(4)
216
+ })
217
+
218
+ it('should parse map with multiple pairs {"a": 1, "b": 2}', () => {
219
+ const { parseMap } = useCborCollection()
220
+
221
+ // {"a": 1, "b": 2} = 0xa2 0x61 "a" 0x01 0x61 "b" 0x02
222
+ const result = parseMap('a26161016162 02')
223
+ expect(result.value).toEqual(new Map([['a', 1], ['b', 2]]))
224
+ expect(result.bytesRead).toBe(7)
225
+ })
226
+
227
+ it('should parse map with integer keys {1: "a", 2: "b"}', () => {
228
+ const { parseMap } = useCborCollection()
229
+
230
+ // {1: "a", 2: "b"} = 0xa2 0x01 0x61 "a" 0x02 0x61 "b"
231
+ const result = parseMap('a2016161026162')
232
+ expect(result.value).toEqual(new Map([[1, 'a'], [2, 'b']]))
233
+ expect(result.bytesRead).toBe(7)
234
+ })
235
+ })
236
+
237
+ describe('Maps with Different Value Types', () => {
238
+ it('should parse map with string values {"name": "Alice", "age": "30"}', () => {
239
+ const { parseMap } = useCborCollection()
240
+
241
+ // {"name": "Alice", "age": "30"}
242
+ // "name" = 0x64 0x6e 0x61 0x6d 0x65
243
+ // "Alice" = 0x65 0x41 0x6c 0x69 0x63 0x65
244
+ // "age" = 0x63 0x61 0x67 0x65
245
+ // "30" = 0x62 0x33 0x30
246
+ const result = parseMap('a2646e616d656541 6c696365636167656233 30')
247
+ expect(result.value).toEqual(new Map([['name', 'Alice'], ['age', '30']]))
248
+ })
249
+
250
+ it('should parse map with mixed value types {"count": 42, "active": true}', () => {
251
+ const { parseMap } = useCborCollection()
252
+
253
+ // {"count": 42, "active": true}
254
+ // Note: true requires simple value parser, will parse integer for now
255
+ // "count" = 0x65 0x63 0x6f 0x75 0x6e 0x74
256
+ // 42 = 0x18 0x2a
257
+ const result = parseMap('a165636f756e74182a')
258
+ expect(result.value).toEqual(new Map([['count', 42]]))
259
+ expect(result.bytesRead).toBe(9)
260
+ })
261
+ })
262
+
263
+ describe('Nested Maps', () => {
264
+ it('should parse nested map {"outer": {"inner": 1}}', () => {
265
+ const { parseMap } = useCborCollection()
266
+
267
+ // {"outer": {"inner": 1}}
268
+ // "outer" = 0x65 0x6f 0x75 0x74 0x65 0x72
269
+ // {"inner": 1} = 0xa1 0x65 0x69 0x6e 0x6e 0x65 0x72 0x01
270
+ const result = parseMap('a1656f75746572a1 65696e6e657201')
271
+ expect(result.value).toEqual(new Map([['outer', new Map([['inner', 1]])]]))
272
+ })
273
+
274
+ it('should parse map with array value {"numbers": [1, 2, 3]}', () => {
275
+ const { parseMap } = useCborCollection()
276
+
277
+ // {"numbers": [1, 2, 3]}
278
+ // "numbers" = 0x67 0x6e 0x75 0x6d 0x62 0x65 0x72 0x73
279
+ // [1, 2, 3] = 0x83 0x01 0x02 0x03
280
+ const result = parseMap('a1676e756d62657273 83010203')
281
+ expect(result.value).toEqual(new Map([['numbers', [1, 2, 3]]]))
282
+ })
283
+ })
284
+
285
+ describe('Indefinite-Length Maps', () => {
286
+ it('should parse indefinite-length map {_ "a": 1, "b": 2}', () => {
287
+ const { parseMap } = useCborCollection()
288
+
289
+ // {_ "a": 1, "b": 2} = 0xbf 0x61 "a" 0x01 0x61 "b" 0x02 0xff
290
+ const result = parseMap('bf61610161620 2ff')
291
+ expect(result.value).toEqual(new Map([['a', 1], ['b', 2]]))
292
+ expect(result.bytesRead).toBe(8)
293
+ })
294
+
295
+ it('should parse indefinite-length empty map {_}', () => {
296
+ const { parseMap } = useCborCollection()
297
+
298
+ // {_} = 0xbf 0xff
299
+ const result = parseMap('bfff')
300
+ expect(result.value).toEqual(new Map())
301
+ expect(result.bytesRead).toBe(2)
302
+ })
303
+ })
304
+
305
+ describe('Real Cardano Examples', () => {
306
+ it('should parse Cardano balance object {"lovelace": 1000000}', () => {
307
+ const { parseMap } = useCborCollection()
308
+
309
+ // {"lovelace": 1000000}
310
+ // "lovelace" = 0x68 0x6c 0x6f 0x76 0x65 0x6c 0x61 0x63 0x65
311
+ // 1000000 = 0x1a 0x000f4240
312
+ const result = parseMap('a1686c6f76656c6163 651a000f4240')
313
+ expect(result.value).toEqual(new Map([['lovelace', 1000000]]))
314
+ })
315
+
316
+ it('should parse Cardano metadata map {"msg": "Hello"}', () => {
317
+ const { parseMap } = useCborCollection()
318
+
319
+ // {"msg": "Hello"}
320
+ // "msg" = 0x63 0x6d 0x73 0x67
321
+ // "Hello" = 0x65 0x48 0x65 0x6c 0x6c 0x6f
322
+ const result = parseMap('a1636d73676548656c 6c6f')
323
+ expect(result.value).toEqual(new Map([['msg', 'Hello']]))
324
+ })
325
+
326
+ it('should parse Cardano UTXO map structure', () => {
327
+ const { parseMap } = useCborCollection()
328
+
329
+ // Simplified: {"amount": 5000000, "address": "addr1..."}
330
+ // "amount" = 0x66 0x61 0x6d 0x6f 0x75 0x6e 0x74
331
+ // 5000000 = 0x1a 0x004c4b40
332
+ // "address" = 0x67 0x61 0x64 0x64 0x72 0x65 0x73 0x73
333
+ // "addr1" = 0x65 0x61 0x64 0x64 0x72 0x31
334
+ const result = parseMap('a266616d6f756e741a 004c4b4067616464726573736561646472 31')
335
+ expect(result.value).toEqual(new Map([['amount', 5000000], ['address', 'addr1']]))
336
+ })
337
+ })
338
+ })
339
+
340
+ describe('Error Handling', () => {
341
+ it('should throw error for invalid major type in parseArray', () => {
342
+ const { parseArray } = useCborCollection()
343
+
344
+ // 0x00 = integer 0, not an array
345
+ expect(() => parseArray('00')).toThrow('Expected major type 4 (array)')
346
+ })
347
+
348
+ it('should throw error for invalid major type in parseMap', () => {
349
+ const { parseMap } = useCborCollection()
350
+
351
+ // 0x80 = empty array, not a map
352
+ expect(() => parseMap('80')).toThrow('Expected major type 5 (map)')
353
+ })
354
+
355
+ it('should throw error for truncated array data', () => {
356
+ const { parseArray } = useCborCollection()
357
+
358
+ // 0x83 = array(3), but only 2 elements provided
359
+ expect(() => parseArray('830102')).toThrow()
360
+ })
361
+
362
+ it('should throw error for truncated map data', () => {
363
+ const { parseMap } = useCborCollection()
364
+
365
+ // 0xa2 = map(2 pairs), but only 1 pair provided
366
+ expect(() => parseMap('a2616101')).toThrow()
367
+ })
368
+ })
369
+ })