@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,345 @@
1
+ /**
2
+ * CBOR String Encoder Test Suite
3
+ * Tests for Major Type 2 (Byte Strings) and Major Type 3 (Text Strings)
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest'
7
+ import { useCborStringEncoder } from '../composables/useCborStringEncoder'
8
+
9
+ describe('CBOR String Encoder', () => {
10
+ describe('Byte Strings (Major Type 2)', () => {
11
+ describe('Definite-length encoding', () => {
12
+ it('should encode empty byte string', () => {
13
+ const { encodeByteString } = useCborStringEncoder()
14
+ const result = encodeByteString(new Uint8Array([]))
15
+
16
+ expect(result.bytes).toEqual(new Uint8Array([0x40]))
17
+ expect(result.hex).toBe('40')
18
+ })
19
+
20
+ it('should encode single byte', () => {
21
+ const { encodeByteString } = useCborStringEncoder()
22
+ const result = encodeByteString(new Uint8Array([0xff]))
23
+
24
+ expect(result.bytes).toEqual(new Uint8Array([0x41, 0xff]))
25
+ expect(result.hex).toBe('41ff')
26
+ })
27
+
28
+ it('should encode short byte string (< 24 bytes)', () => {
29
+ const { encodeByteString } = useCborStringEncoder()
30
+ const data = new Uint8Array([0x01, 0x02, 0x03, 0x04])
31
+ const result = encodeByteString(data)
32
+
33
+ expect(result.bytes).toEqual(new Uint8Array([0x44, 0x01, 0x02, 0x03, 0x04]))
34
+ expect(result.hex).toBe('4401020304')
35
+ })
36
+
37
+ it('should encode 23-byte string (direct length)', () => {
38
+ const { encodeByteString } = useCborStringEncoder()
39
+ const data = new Uint8Array(23).fill(0xaa)
40
+ const result = encodeByteString(data)
41
+
42
+ expect(result.bytes[0]).toBe(0x57) // 0x40 + 23
43
+ expect(result.bytes.length).toBe(24) // 1 byte header + 23 bytes data
44
+ expect(result.bytes.slice(1)).toEqual(data)
45
+ })
46
+
47
+ it('should encode 24-byte string (1-byte length)', () => {
48
+ const { encodeByteString } = useCborStringEncoder()
49
+ const data = new Uint8Array(24).fill(0xbb)
50
+ const result = encodeByteString(data)
51
+
52
+ expect(result.bytes[0]).toBe(0x58) // Major type 2, AI=24
53
+ expect(result.bytes[1]).toBe(24) // Length
54
+ expect(result.bytes.length).toBe(26) // 2 byte header + 24 bytes data
55
+ expect(result.bytes.slice(2)).toEqual(data)
56
+ })
57
+
58
+ it('should encode 256-byte string (2-byte length)', () => {
59
+ const { encodeByteString } = useCborStringEncoder()
60
+ const data = new Uint8Array(256).fill(0xcc)
61
+ const result = encodeByteString(data)
62
+
63
+ expect(result.bytes[0]).toBe(0x59) // Major type 2, AI=25
64
+ expect(result.bytes[1]).toBe(0x01) // Length high byte
65
+ expect(result.bytes[2]).toBe(0x00) // Length low byte
66
+ expect(result.bytes.length).toBe(259) // 3 byte header + 256 bytes data
67
+ })
68
+
69
+ it('should encode real Cardano transaction hash', () => {
70
+ const { encodeByteString } = useCborStringEncoder()
71
+ // 32-byte transaction hash (typical Cardano txHash)
72
+ const txHash = new Uint8Array([
73
+ 0x48, 0xbd, 0x01, 0xd5, 0x1e, 0x58, 0x0c, 0xde,
74
+ 0x15, 0xaf, 0xa6, 0xd2, 0x8f, 0x63, 0xd8, 0x9c,
75
+ 0x91, 0x37, 0xb9, 0x3a, 0x91, 0x0e, 0x59, 0x41,
76
+ 0x19, 0x2e, 0x26, 0xb1, 0x29, 0x06, 0x10, 0x67
77
+ ])
78
+ const result = encodeByteString(txHash)
79
+
80
+ // Should use 1-byte length encoding (32 < 256)
81
+ expect(result.bytes[0]).toBe(0x58)
82
+ expect(result.bytes[1]).toBe(32)
83
+ expect(result.bytes.slice(2)).toEqual(txHash)
84
+ expect(result.hex).toBe('582048bd01d51e580cde15afa6d28f63d89c9137b93a910e5941192e26b129061067')
85
+ })
86
+ })
87
+
88
+ describe('Indefinite-length encoding', () => {
89
+ it('should encode empty indefinite byte string', () => {
90
+ const { encodeByteStringIndefinite } = useCborStringEncoder()
91
+ const result = encodeByteStringIndefinite([])
92
+
93
+ // 0x5f (start) + 0xff (break)
94
+ expect(result.bytes).toEqual(new Uint8Array([0x5f, 0xff]))
95
+ expect(result.hex).toBe('5fff')
96
+ })
97
+
98
+ it('should encode single chunk', () => {
99
+ const { encodeByteStringIndefinite } = useCborStringEncoder()
100
+ const chunks = [new Uint8Array([0x01, 0x02, 0x03])]
101
+ const result = encodeByteStringIndefinite(chunks)
102
+
103
+ // 0x5f (start) + 0x43 (length 3) + data + 0xff (break)
104
+ expect(result.bytes).toEqual(new Uint8Array([0x5f, 0x43, 0x01, 0x02, 0x03, 0xff]))
105
+ expect(result.hex).toBe('5f43010203ff')
106
+ })
107
+
108
+ it('should encode multiple chunks', () => {
109
+ const { encodeByteStringIndefinite } = useCborStringEncoder()
110
+ const chunks = [
111
+ new Uint8Array([0xaa, 0xbb]),
112
+ new Uint8Array([0xcc]),
113
+ new Uint8Array([0xdd, 0xee, 0xff])
114
+ ]
115
+ const result = encodeByteStringIndefinite(chunks)
116
+
117
+ // 0x5f + (0x42 + data) + (0x41 + data) + (0x43 + data) + 0xff
118
+ expect(result.bytes).toEqual(new Uint8Array([
119
+ 0x5f,
120
+ 0x42, 0xaa, 0xbb,
121
+ 0x41, 0xcc,
122
+ 0x43, 0xdd, 0xee, 0xff,
123
+ 0xff
124
+ ]))
125
+ })
126
+ })
127
+
128
+ describe('Options handling', () => {
129
+ it('should reject indefinite encoding in canonical mode', () => {
130
+ const { encodeByteString } = useCborStringEncoder({ canonical: true })
131
+ const chunks = [new Uint8Array([0x01])]
132
+
133
+ expect(() => encodeByteString(chunks, { indefinite: true }))
134
+ .toThrow('Indefinite-length encoding not allowed in canonical mode')
135
+ })
136
+ })
137
+ })
138
+
139
+ describe('Text Strings (Major Type 3)', () => {
140
+ describe('Definite-length encoding', () => {
141
+ it('should encode empty string', () => {
142
+ const { encodeTextString } = useCborStringEncoder()
143
+ const result = encodeTextString('')
144
+
145
+ expect(result.bytes).toEqual(new Uint8Array([0x60]))
146
+ expect(result.hex).toBe('60')
147
+ })
148
+
149
+ it('should encode single ASCII character', () => {
150
+ const { encodeTextString } = useCborStringEncoder()
151
+ const result = encodeTextString('a')
152
+
153
+ expect(result.bytes).toEqual(new Uint8Array([0x61, 0x61]))
154
+ expect(result.hex).toBe('6161')
155
+ })
156
+
157
+ it('should encode short ASCII string', () => {
158
+ const { encodeTextString } = useCborStringEncoder()
159
+ const result = encodeTextString('IETF')
160
+
161
+ expect(result.bytes).toEqual(new Uint8Array([0x64, 0x49, 0x45, 0x54, 0x46]))
162
+ expect(result.hex).toBe('6449455446')
163
+ })
164
+
165
+ it('should encode string with quote character', () => {
166
+ const { encodeTextString } = useCborStringEncoder()
167
+ const result = encodeTextString('"\\')
168
+
169
+ expect(result.bytes).toEqual(new Uint8Array([0x62, 0x22, 0x5c]))
170
+ expect(result.hex).toBe('62225c')
171
+ })
172
+
173
+ it('should encode Unicode string (UTF-8)', () => {
174
+ const { encodeTextString } = useCborStringEncoder()
175
+ const result = encodeTextString('\u00fc') // ü
176
+
177
+ // ü in UTF-8 is 0xc3 0xbc (2 bytes)
178
+ expect(result.bytes).toEqual(new Uint8Array([0x62, 0xc3, 0xbc]))
179
+ expect(result.hex).toBe('62c3bc')
180
+ })
181
+
182
+ it('should encode Chinese characters (UTF-8)', () => {
183
+ const { encodeTextString } = useCborStringEncoder()
184
+ const result = encodeTextString('\u6c34') // 水 (water)
185
+
186
+ // 水 in UTF-8 is 0xe6 0xb0 0xb4 (3 bytes)
187
+ expect(result.bytes).toEqual(new Uint8Array([0x63, 0xe6, 0xb0, 0xb4]))
188
+ expect(result.hex).toBe('63e6b0b4')
189
+ })
190
+
191
+ it('should encode emoji (UTF-8)', () => {
192
+ const { encodeTextString } = useCborStringEncoder()
193
+ const result = encodeTextString('🔥')
194
+
195
+ // 🔥 in UTF-8 is 0xf0 0x9f 0x94 0xa5 (4 bytes)
196
+ expect(result.bytes).toEqual(new Uint8Array([0x64, 0xf0, 0x9f, 0x94, 0xa5]))
197
+ expect(result.hex).toBe('64f09f94a5')
198
+ })
199
+
200
+ it('should encode Cardano asset name', () => {
201
+ const { encodeTextString } = useCborStringEncoder()
202
+ const result = encodeTextString('amount')
203
+
204
+ // Real-world Cardano map key
205
+ expect(result.bytes).toEqual(new Uint8Array([0x66, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74]))
206
+ expect(result.hex).toBe('66616d6f756e74')
207
+ })
208
+
209
+ it('should encode 24-character string (1-byte length)', () => {
210
+ const { encodeTextString } = useCborStringEncoder()
211
+ const str = 'a'.repeat(24)
212
+ const result = encodeTextString(str)
213
+
214
+ expect(result.bytes[0]).toBe(0x78) // Major type 3, AI=24
215
+ expect(result.bytes[1]).toBe(24) // Length
216
+ expect(result.bytes.length).toBe(26)
217
+ })
218
+
219
+ it('should encode 256-character string (2-byte length)', () => {
220
+ const { encodeTextString } = useCborStringEncoder()
221
+ const str = 'x'.repeat(256)
222
+ const result = encodeTextString(str)
223
+
224
+ expect(result.bytes[0]).toBe(0x79) // Major type 3, AI=25
225
+ expect(result.bytes[1]).toBe(0x01) // Length high byte
226
+ expect(result.bytes[2]).toBe(0x00) // Length low byte
227
+ expect(result.bytes.length).toBe(259)
228
+ })
229
+ })
230
+
231
+ describe('Indefinite-length encoding', () => {
232
+ it('should encode empty indefinite text string', () => {
233
+ const { encodeTextStringIndefinite } = useCborStringEncoder()
234
+ const result = encodeTextStringIndefinite([])
235
+
236
+ expect(result.bytes).toEqual(new Uint8Array([0x7f, 0xff]))
237
+ expect(result.hex).toBe('7fff')
238
+ })
239
+
240
+ it('should encode single chunk', () => {
241
+ const { encodeTextStringIndefinite } = useCborStringEncoder()
242
+ const result = encodeTextStringIndefinite(['streaming'])
243
+
244
+ // 0x7f + 0x69 (length 9) + "streaming" + 0xff
245
+ expect(result.hex).toBe('7f6973747265616d696e67ff')
246
+ })
247
+
248
+ it('should encode streaming text', () => {
249
+ const { encodeTextStringIndefinite } = useCborStringEncoder()
250
+ const chunks = ['stream', 'ing']
251
+ const result = encodeTextStringIndefinite(chunks)
252
+
253
+ // 0x7f + (0x66 + "stream") + (0x63 + "ing") + 0xff
254
+ expect(result.hex).toBe('7f6673747265616d63696e67ff')
255
+ })
256
+ })
257
+
258
+ describe('Edge cases', () => {
259
+ it('should handle null character in string', () => {
260
+ const { encodeTextString } = useCborStringEncoder()
261
+ const result = encodeTextString('a\u0000b')
262
+
263
+ expect(result.bytes).toEqual(new Uint8Array([0x63, 0x61, 0x00, 0x62]))
264
+ })
265
+
266
+ it('should handle newline characters', () => {
267
+ const { encodeTextString } = useCborStringEncoder()
268
+ const result = encodeTextString('a\nb')
269
+
270
+ expect(result.bytes).toEqual(new Uint8Array([0x63, 0x61, 0x0a, 0x62]))
271
+ })
272
+ })
273
+ })
274
+
275
+ describe('String length limits', () => {
276
+ it('should respect maxOutputSize option', () => {
277
+ const { encodeTextString } = useCborStringEncoder({ maxOutputSize: 10 })
278
+ const largeString = 'x'.repeat(1000)
279
+
280
+ expect(() => encodeTextString(largeString))
281
+ .toThrow('Encoded output exceeds maximum size')
282
+ })
283
+
284
+ it('should respect maxOutputSize option for byte strings', () => {
285
+ const { encodeByteString } = useCborStringEncoder({ maxOutputSize: 10 })
286
+ const largeBytes = new Uint8Array(1000)
287
+
288
+ expect(() => encodeByteString(largeBytes))
289
+ .toThrow('Encoded output exceeds maximum size')
290
+ })
291
+ })
292
+
293
+ describe('Indefinite encoding via options', () => {
294
+ it('should encode text string as indefinite when option is set', () => {
295
+ const { encodeTextString } = useCborStringEncoder()
296
+ const result = encodeTextString('hello', { indefinite: true })
297
+
298
+ // Should start with 0x7f (indefinite text start) and end with 0xff (break)
299
+ expect(result.bytes[0]).toBe(0x7f)
300
+ expect(result.bytes[result.bytes.length - 1]).toBe(0xff)
301
+ })
302
+
303
+ it('should encode byte string as indefinite when option is set', () => {
304
+ const { encodeByteString } = useCborStringEncoder()
305
+ const result = encodeByteString(new Uint8Array([1, 2, 3]), { indefinite: true })
306
+
307
+ // Should start with 0x5f (indefinite bytes start) and end with 0xff (break)
308
+ expect(result.bytes[0]).toBe(0x5f)
309
+ expect(result.bytes[result.bytes.length - 1]).toBe(0xff)
310
+ })
311
+
312
+ it('should reject indefinite text encoding in canonical mode', () => {
313
+ const { encodeTextString } = useCborStringEncoder({ canonical: true })
314
+
315
+ expect(() => encodeTextString('hello', { indefinite: true }))
316
+ .toThrow('Indefinite-length encoding not allowed in canonical mode')
317
+ })
318
+
319
+ it('should reject indefinite text chunks in canonical mode', () => {
320
+ const { encodeTextStringIndefinite } = useCborStringEncoder({ canonical: true })
321
+
322
+ expect(() => encodeTextStringIndefinite(['a', 'b']))
323
+ .toThrow('Indefinite-length encoding not allowed in canonical mode')
324
+ })
325
+
326
+ it('should reject indefinite byte chunks in canonical mode', () => {
327
+ const { encodeByteStringIndefinite } = useCborStringEncoder({ canonical: true })
328
+
329
+ expect(() => encodeByteStringIndefinite([new Uint8Array([1])]))
330
+ .toThrow('Indefinite-length encoding not allowed in canonical mode')
331
+ })
332
+ })
333
+
334
+ describe('Byte string array handling', () => {
335
+ it('should encode array of byte arrays as indefinite', () => {
336
+ const { encodeByteString } = useCborStringEncoder()
337
+ const chunks = [new Uint8Array([1, 2]), new Uint8Array([3, 4])]
338
+ const result = encodeByteString(chunks)
339
+
340
+ // Should start with 0x5f and end with 0xff
341
+ expect(result.bytes[0]).toBe(0x5f)
342
+ expect(result.bytes[result.bytes.length - 1]).toBe(0xff)
343
+ })
344
+ })
345
+ })