@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,266 @@
1
+ /**
2
+ * CBOR String Encoder Composable
3
+ * Handles Major Type 2 (Byte Strings) and Major Type 3 (Text Strings)
4
+ * Following RFC 8949 specification
5
+ */
6
+
7
+ import type { EncodeResult, EncodeOptions, CborByteString, CborTextString } from '../types'
8
+ import { DEFAULT_ENCODE_OPTIONS, INDEFINITE_SYMBOL } from '../types'
9
+ import { bytesToHex, concatenateUint8Arrays, writeUint, writeBigUint } from '../utils'
10
+ import { useCborByteString, useCborTextString } from '../../parser/composables/useCborStringTypes'
11
+
12
+ interface StringEncodeOptions {
13
+ indefinite?: boolean
14
+ }
15
+
16
+ /**
17
+ * CBOR String Encoder Composable
18
+ *
19
+ * Provides functions to encode byte strings and text strings:
20
+ * - Major Type 2: Byte strings (Uint8Array)
21
+ * - Major Type 3: Text strings (UTF-8 encoded)
22
+ *
23
+ * Supports both definite-length and indefinite-length encoding.
24
+ *
25
+ * @param options - Global encoder options
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const { encodeByteString, encodeTextString } = useCborStringEncoder()
30
+ *
31
+ * // Encode byte string
32
+ * const bytes = new Uint8Array([0x01, 0x02, 0x03])
33
+ * const result1 = encodeByteString(bytes)
34
+ * // result1: { bytes: Uint8Array([0x43, 0x01, 0x02, 0x03]), hex: '43010203' }
35
+ *
36
+ * // Encode text string
37
+ * const result2 = encodeTextString('Hello')
38
+ * // result2: { bytes: Uint8Array([0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6f]), hex: '6548656c6c6f' }
39
+ *
40
+ * // Indefinite-length encoding
41
+ * const chunks = [new Uint8Array([0xaa]), new Uint8Array([0xbb])]
42
+ * const result3 = encodeByteStringIndefinite(chunks)
43
+ * // result3: { bytes: Uint8Array([0x5f, 0x41, 0xaa, 0x41, 0xbb, 0xff]), hex: '5f41aa41bbff' }
44
+ * ```
45
+ */
46
+ export function useCborStringEncoder(globalOptions?: Partial<EncodeOptions>) {
47
+ const options = { ...DEFAULT_ENCODE_OPTIONS, ...globalOptions }
48
+ const { isCborByteString } = useCborByteString()
49
+ const { isCborTextString } = useCborTextString()
50
+
51
+ /**
52
+ * Encode the length header for a string
53
+ *
54
+ * @param majorType - Major type (2 for bytes, 3 for text)
55
+ * @param length - Length of the string in bytes
56
+ * @returns Encoded length header
57
+ */
58
+ const encodeLengthHeader = (majorType: number, length: number): Uint8Array => {
59
+ const baseValue = majorType << 5
60
+
61
+ // Direct encoding (0-23)
62
+ if (length <= 23) {
63
+ return new Uint8Array([baseValue | length])
64
+ }
65
+ // 1-byte length (24-255)
66
+ else if (length <= 255) {
67
+ return new Uint8Array([baseValue | 24, length])
68
+ }
69
+ // 2-byte length (256-65535)
70
+ else if (length <= 65535) {
71
+ const lengthBytes = writeUint(length, 2)
72
+ return new Uint8Array([baseValue | 25, ...lengthBytes])
73
+ }
74
+ // 4-byte length (65536-4294967295)
75
+ else if (length <= 4294967295) {
76
+ const lengthBytes = writeUint(length, 4)
77
+ return new Uint8Array([baseValue | 26, ...lengthBytes])
78
+ }
79
+ // 8-byte length (> 4294967295)
80
+ else {
81
+ const lengthBytes = length > Number.MAX_SAFE_INTEGER
82
+ ? writeBigUint(BigInt(length), 8)
83
+ : writeUint(length, 8)
84
+ return new Uint8Array([baseValue | 27, ...lengthBytes])
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Encode byte string (Major Type 2)
90
+ *
91
+ * Can encode either:
92
+ * - Definite-length: Single Uint8Array
93
+ * - Indefinite-length: Array of Uint8Array chunks (if indefinite option is set)
94
+ *
95
+ * @param data - Byte data or array of chunks
96
+ * @param encodeOptions - Encoding options
97
+ * @returns Encoded CBOR bytes and hex string
98
+ * @throws Error if indefinite encoding is used in canonical mode
99
+ */
100
+ const encodeByteString = (
101
+ data: Uint8Array | Uint8Array[] | CborByteString,
102
+ encodeOptions?: StringEncodeOptions
103
+ ): EncodeResult => {
104
+ // Check if it's a CborByteString with indefinite marker
105
+ const isIndefinite = isCborByteString(data) && (data as any)[INDEFINITE_SYMBOL] === true
106
+
107
+ // Handle indefinite-length encoding
108
+ if (encodeOptions?.indefinite || Array.isArray(data) || isIndefinite) {
109
+ if (options.canonical) {
110
+ throw new Error('Indefinite-length encoding not allowed in canonical mode')
111
+ }
112
+
113
+ // If it's a CborByteString with chunks, use the original chunks
114
+ if (isCborByteString(data) && data.chunks) {
115
+ return encodeByteStringIndefinite(data.chunks)
116
+ }
117
+
118
+ // Otherwise, get the actual bytes and encode as single chunk
119
+ const bytes = isCborByteString(data) ? data.bytes : (Array.isArray(data) ? data : [data])
120
+ return encodeByteStringIndefinite(Array.isArray(bytes) ? bytes : [bytes])
121
+ }
122
+
123
+ // Definite-length encoding - extract bytes from CborByteString if needed
124
+ const bytes = isCborByteString(data) ? data.bytes : (data as Uint8Array)
125
+ const header = encodeLengthHeader(2, bytes.length)
126
+ const result = concatenateUint8Arrays([header, bytes])
127
+
128
+ // Check output size limit
129
+ if (result.length > options.maxOutputSize) {
130
+ throw new Error('Encoded output exceeds maximum size')
131
+ }
132
+
133
+ return {
134
+ bytes: result,
135
+ hex: bytesToHex(result)
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Encode byte string with indefinite length (Major Type 2)
141
+ *
142
+ * Format: 0x5f + chunk1 + chunk2 + ... + 0xff
143
+ * Each chunk is a definite-length byte string.
144
+ *
145
+ * @param chunks - Array of byte string chunks
146
+ * @returns Encoded CBOR bytes and hex string
147
+ */
148
+ const encodeByteStringIndefinite = (chunks: Uint8Array[]): EncodeResult => {
149
+ if (options.canonical) {
150
+ throw new Error('Indefinite-length encoding not allowed in canonical mode')
151
+ }
152
+
153
+ const parts: Uint8Array[] = [new Uint8Array([0x5f])] // Start marker
154
+
155
+ // Encode each chunk as definite-length byte string
156
+ for (const chunk of chunks) {
157
+ const header = encodeLengthHeader(2, chunk.length)
158
+ parts.push(header)
159
+ parts.push(chunk)
160
+ }
161
+
162
+ parts.push(new Uint8Array([0xff])) // Break marker
163
+
164
+ const result = concatenateUint8Arrays(parts)
165
+
166
+ return {
167
+ bytes: result,
168
+ hex: bytesToHex(result)
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Encode text string (Major Type 3)
174
+ *
175
+ * Text strings are encoded as UTF-8 bytes.
176
+ *
177
+ * @param text - Text string to encode
178
+ * @param _encodeOptions - Encoding options (reserved for future use)
179
+ * @returns Encoded CBOR bytes and hex string
180
+ */
181
+ const encodeTextString = (
182
+ text: string | CborTextString,
183
+ encodeOptions?: StringEncodeOptions
184
+ ): EncodeResult => {
185
+ // Check if it's a CborTextString with indefinite marker
186
+ const isIndefinite = isCborTextString(text) && (text as any)[INDEFINITE_SYMBOL] === true
187
+
188
+ // Handle indefinite-length encoding
189
+ if (encodeOptions?.indefinite || isIndefinite) {
190
+ if (options.canonical) {
191
+ throw new Error('Indefinite-length encoding not allowed in canonical mode')
192
+ }
193
+
194
+ // If it's a CborTextString with chunks, use the original chunks
195
+ if (isCborTextString(text) && text.chunks) {
196
+ return encodeTextStringIndefinite(text.chunks)
197
+ }
198
+
199
+ // Otherwise, get the actual text and encode as single chunk
200
+ const textStr = isCborTextString(text) ? text.text : text
201
+ return encodeTextStringIndefinite([textStr])
202
+ }
203
+
204
+ // Definite-length encoding - extract text from CborTextString if needed
205
+ const textStr = isCborTextString(text) ? text.text : text
206
+
207
+ // Convert string to UTF-8 bytes
208
+ const encoder = new TextEncoder()
209
+ const utf8Bytes = encoder.encode(textStr)
210
+
211
+ const header = encodeLengthHeader(3, utf8Bytes.length)
212
+ const result = concatenateUint8Arrays([header, utf8Bytes])
213
+
214
+ // Check output size limit
215
+ if (result.length > options.maxOutputSize) {
216
+ throw new Error('Encoded output exceeds maximum size')
217
+ }
218
+
219
+ return {
220
+ bytes: result,
221
+ hex: bytesToHex(result)
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Encode text string with indefinite length (Major Type 3)
227
+ *
228
+ * Format: 0x7f + chunk1 + chunk2 + ... + 0xff
229
+ * Each chunk is a definite-length text string.
230
+ *
231
+ * @param chunks - Array of text string chunks
232
+ * @returns Encoded CBOR bytes and hex string
233
+ */
234
+ const encodeTextStringIndefinite = (chunks: string[]): EncodeResult => {
235
+ if (options.canonical) {
236
+ throw new Error('Indefinite-length encoding not allowed in canonical mode')
237
+ }
238
+
239
+ const parts: Uint8Array[] = [new Uint8Array([0x7f])] // Start marker
240
+
241
+ // Encode each chunk as definite-length text string
242
+ const encoder = new TextEncoder()
243
+ for (const chunk of chunks) {
244
+ const utf8Bytes = encoder.encode(chunk)
245
+ const header = encodeLengthHeader(3, utf8Bytes.length)
246
+ parts.push(header)
247
+ parts.push(utf8Bytes)
248
+ }
249
+
250
+ parts.push(new Uint8Array([0xff])) // Break marker
251
+
252
+ const result = concatenateUint8Arrays(parts)
253
+
254
+ return {
255
+ bytes: result,
256
+ hex: bytesToHex(result)
257
+ }
258
+ }
259
+
260
+ return {
261
+ encodeByteString,
262
+ encodeByteStringIndefinite,
263
+ encodeTextString,
264
+ encodeTextStringIndefinite
265
+ }
266
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * CBOR Tag Encoder Composable
3
+ * Handles Major Type 6 (Semantic Tags)
4
+ * Following RFC 8949 specification
5
+ */
6
+
7
+ import type { EncodeResult, TaggedValue, EncodableValue } from '../types'
8
+ import { bytesToHex, writeUint, writeBigUint } from '../utils'
9
+
10
+ /**
11
+ * CBOR Tag Encoder Composable
12
+ *
13
+ * Provides functions to encode tagged values to CBOR format:
14
+ * - Major Type 6: Semantic tags (0 to 2^64-1)
15
+ *
16
+ * Tags provide semantic meaning to CBOR values:
17
+ * - Tag 0: Date/time string (RFC 3339)
18
+ * - Tag 1: Epoch timestamp
19
+ * - Tag 2: Positive bignum
20
+ * - Tag 3: Negative bignum
21
+ * - Tag 258: Cardano set (CIP-0005)
22
+ * - And many more...
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const { encodeTag } = useCborTagEncoder()
27
+ *
28
+ * // Encode date/time string (tag 0)
29
+ * const result1 = encodeTag(0, '2013-03-21T20:04:00Z', encode)
30
+ * // result1.hex: 'c074323031332d30332d32315432303a30343a30305a'
31
+ *
32
+ * // Encode positive bignum (tag 2)
33
+ * const result2 = encodeTag(2, new Uint8Array([0x01, 0xff]), encode)
34
+ * // result2.hex: 'c24201ff'
35
+ *
36
+ * // Encode Cardano set (tag 258)
37
+ * const result3 = encodeTag(258, [1, 2, 3], encode)
38
+ * // result3.hex: 'd9010283010203'
39
+ * ```
40
+ */
41
+ export function useCborTagEncoder() {
42
+ /**
43
+ * Encode tag number (Major Type 6 header)
44
+ *
45
+ * Tag numbers use the same encoding rules as unsigned integers:
46
+ * - 0-23: Direct encoding in initial byte (0xc0-0xd7)
47
+ * - 24-255: 0xd8 + 1 byte
48
+ * - 256-65535: 0xd9 + 2 bytes
49
+ * - 65536-4294967295: 0xda + 4 bytes
50
+ * - 4294967296-2^64-1: 0xdb + 8 bytes
51
+ *
52
+ * @param tagNumber - Tag number (0 to 2^64-1)
53
+ * @returns Encoded tag header bytes
54
+ * @throws Error if tag number is negative or >= 2^64
55
+ */
56
+ const encodeTagNumber = (tagNumber: number | bigint): Uint8Array => {
57
+ // Convert to BigInt for consistent handling
58
+ const bigTag = typeof tagNumber === 'bigint' ? tagNumber : BigInt(tagNumber)
59
+
60
+ // Validate tag is non-negative
61
+ if (bigTag < 0n) {
62
+ throw new Error('Tag number cannot be negative')
63
+ }
64
+
65
+ // Validate tag doesn't exceed 2^64-1
66
+ const MAX_UINT64 = 18446744073709551615n // 2^64 - 1
67
+ if (bigTag > MAX_UINT64) {
68
+ throw new Error('Tag number exceeds maximum (2^64-1)')
69
+ }
70
+
71
+ let bytes: Uint8Array
72
+
73
+ // Direct encoding (0-23) - Major type 6 (0xc0) + tag number
74
+ if (bigTag <= 23n) {
75
+ bytes = new Uint8Array([0xc0 + Number(bigTag)])
76
+ }
77
+ // 1-byte encoding (24-255) - 0xd8 + 1 byte
78
+ else if (bigTag <= 255n) {
79
+ bytes = new Uint8Array([0xd8, Number(bigTag)])
80
+ }
81
+ // 2-byte encoding (256-65535) - 0xd9 + 2 bytes
82
+ else if (bigTag <= 65535n) {
83
+ const valueBytes = writeUint(Number(bigTag), 2)
84
+ bytes = new Uint8Array([0xd9, ...valueBytes])
85
+ }
86
+ // 4-byte encoding (65536-4294967295) - 0xda + 4 bytes
87
+ else if (bigTag <= 4294967295n) {
88
+ const valueBytes = writeUint(Number(bigTag), 4)
89
+ bytes = new Uint8Array([0xda, ...valueBytes])
90
+ }
91
+ // 8-byte encoding (> 4294967295) - 0xdb + 8 bytes
92
+ else {
93
+ const valueBytes = writeBigUint(bigTag, 8)
94
+ bytes = new Uint8Array([0xdb, ...valueBytes])
95
+ }
96
+
97
+ return bytes
98
+ }
99
+
100
+ /**
101
+ * Encode tagged value (tag + content)
102
+ *
103
+ * A tagged value consists of:
104
+ * 1. Tag number (Major Type 6 header)
105
+ * 2. Tagged content (recursively encoded value)
106
+ *
107
+ * The encode function is passed as a parameter to avoid circular dependencies.
108
+ *
109
+ * @param tagNumber - Tag number
110
+ * @param value - Value to tag
111
+ * @param encode - Encoder function for the tagged value
112
+ * @returns Encoded CBOR bytes and hex string
113
+ */
114
+ const encodeTag = (
115
+ tagNumber: number | bigint,
116
+ value: EncodableValue,
117
+ encode: (value: EncodableValue) => EncodeResult
118
+ ): EncodeResult => {
119
+ // Encode tag number
120
+ const tagBytes = encodeTagNumber(tagNumber)
121
+
122
+ // Recursively encode the tagged value
123
+ const valueResult = encode(value)
124
+
125
+ // Concatenate tag header + value bytes
126
+ const totalLength = tagBytes.length + valueResult.bytes.length
127
+ const bytes = new Uint8Array(totalLength)
128
+ bytes.set(tagBytes, 0)
129
+ bytes.set(valueResult.bytes, tagBytes.length)
130
+
131
+ return {
132
+ bytes,
133
+ hex: bytesToHex(bytes)
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Encode TaggedValue object
139
+ *
140
+ * Convenience function for encoding { tag, value } objects.
141
+ *
142
+ * @param taggedValue - Object with tag and value properties
143
+ * @param encode - Encoder function for the tagged value
144
+ * @returns Encoded CBOR bytes and hex string
145
+ */
146
+ const encodeTaggedValue = (
147
+ taggedValue: TaggedValue,
148
+ encode: (value: EncodableValue) => EncodeResult
149
+ ): EncodeResult => {
150
+ return encodeTag(taggedValue.tag, taggedValue.value, encode)
151
+ }
152
+
153
+ return {
154
+ encodeTagNumber,
155
+ encodeTag,
156
+ encodeTaggedValue
157
+ }
158
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * NACHOS Encoder Module
3
+ *
4
+ * @module @marcuspuchalla/nachos/encoder
5
+ */
6
+
7
+ // Export encoder composables
8
+ export { useCborEncoder } from './composables/useCborEncoder'
9
+ export { useCborIntegerEncoder } from './composables/useCborIntegerEncoder'
10
+ export { useCborStringEncoder } from './composables/useCborStringEncoder'
11
+ export { useCborCollectionEncoder } from './composables/useCborCollectionEncoder'
12
+ export { useCborSimpleEncoder } from './composables/useCborSimpleEncoder'
13
+ export { useCborTagEncoder } from './composables/useCborTagEncoder'
14
+
15
+ // Export types
16
+ export type {
17
+ EncodeResult,
18
+ EncodeOptions,
19
+ EncodableValue,
20
+ EncodeContext
21
+ } from './types'
22
+
23
+ // Export constants
24
+ export {
25
+ DEFAULT_ENCODE_OPTIONS
26
+ } from './types'
27
+
28
+ // Export utility functions
29
+ export {
30
+ bytesToHex,
31
+ concatenateUint8Arrays,
32
+ compareBytes,
33
+ writeUint,
34
+ writeBigUint
35
+ } from './utils'
@@ -0,0 +1,88 @@
1
+ /**
2
+ * CBOR Encoder Type Definitions
3
+ * Following RFC 8949 specification
4
+ */
5
+
6
+ import type { PlutusConstr, CborByteString, CborTextString } from '../parser/types'
7
+ import { INDEFINITE_SYMBOL, ALL_ENTRIES_SYMBOL } from '../parser/types'
8
+
9
+ // Re-export symbols and types for use in encoder
10
+ export { INDEFINITE_SYMBOL, ALL_ENTRIES_SYMBOL }
11
+ export type { CborByteString, CborTextString }
12
+
13
+ /**
14
+ * Encoder options for controlling behavior
15
+ */
16
+ export interface EncodeOptions {
17
+ /** Enable canonical encoding (shortest form, sorted maps) */
18
+ canonical?: boolean
19
+ /** Allow indefinite-length encoding (false in canonical mode) */
20
+ allowIndefinite?: boolean
21
+ /** Reject duplicate map keys */
22
+ rejectDuplicateKeys?: boolean
23
+ /** Maximum nesting depth */
24
+ maxDepth?: number
25
+ /** Maximum output size in bytes */
26
+ maxOutputSize?: number
27
+ }
28
+
29
+ /**
30
+ * Default encode options
31
+ */
32
+ export const DEFAULT_ENCODE_OPTIONS: Required<EncodeOptions> = {
33
+ canonical: false,
34
+ allowIndefinite: true,
35
+ rejectDuplicateKeys: false,
36
+ maxDepth: 64,
37
+ maxOutputSize: 100 * 1024 * 1024 // 100 MB
38
+ }
39
+
40
+ /**
41
+ * Result of encoding operation
42
+ */
43
+ export interface EncodeResult {
44
+ /** Encoded CBOR bytes */
45
+ bytes: Uint8Array
46
+ /** Hex string representation */
47
+ hex: string
48
+ }
49
+
50
+ /**
51
+ * Values that can be encoded to CBOR
52
+ *
53
+ * Supports both plain objects (for convenience) and Maps (for type preservation).
54
+ * Map<any, any> is preferred for maps with non-string keys (integers, Uint8Arrays, etc.)
55
+ */
56
+ export type EncodableValue =
57
+ | number
58
+ | bigint
59
+ | string
60
+ | boolean
61
+ | null
62
+ | undefined
63
+ | Uint8Array
64
+ | EncodableValue[]
65
+ | { [key: string]: EncodableValue } // Plain object (legacy/convenience)
66
+ | Map<EncodableValue, EncodableValue> // Map (preserves key types)
67
+ | TaggedValue
68
+
69
+ /**
70
+ * Tagged CBOR value (Major Type 6)
71
+ */
72
+ export interface TaggedValue {
73
+ tag: number
74
+ value: EncodableValue
75
+ plutus?: PlutusConstr
76
+ }
77
+
78
+ /**
79
+ * Encoding context that tracks state during CBOR encoding
80
+ */
81
+ export interface EncodeContext {
82
+ /** Current nesting depth */
83
+ depth: number
84
+ /** Bytes written so far */
85
+ bytesWritten: number
86
+ /** Encoder options */
87
+ options: Required<EncodeOptions>
88
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * CBOR Encoder Utility Functions
3
+ */
4
+
5
+ /**
6
+ * Convert Uint8Array to hex string
7
+ */
8
+ export function bytesToHex(bytes: Uint8Array): string {
9
+ return Array.from(bytes)
10
+ .map(b => b.toString(16).padStart(2, '0'))
11
+ .join('')
12
+ }
13
+
14
+ /**
15
+ * Concatenate multiple Uint8Arrays
16
+ */
17
+ export function concatenateUint8Arrays(arrays: Uint8Array[]): Uint8Array {
18
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0)
19
+ const result = new Uint8Array(totalLength)
20
+
21
+ let offset = 0
22
+ for (const arr of arrays) {
23
+ result.set(arr, offset)
24
+ offset += arr.length
25
+ }
26
+
27
+ return result
28
+ }
29
+
30
+ /**
31
+ * Compare two Uint8Arrays bytewise (for canonical map sorting)
32
+ */
33
+ export function compareBytes(a: Uint8Array, b: Uint8Array): number {
34
+ // First, compare lengths
35
+ if (a.length !== b.length) {
36
+ return a.length - b.length
37
+ }
38
+
39
+ // Then, compare bytewise
40
+ for (let i = 0; i < a.length; i++) {
41
+ const byteA = a[i]
42
+ const byteB = b[i]
43
+ if (byteA === undefined || byteB === undefined) {
44
+ throw new Error(`Unexpected undefined byte at index ${i}`)
45
+ }
46
+ if (byteA !== byteB) {
47
+ return byteA - byteB
48
+ }
49
+ }
50
+
51
+ return 0
52
+ }
53
+
54
+ /**
55
+ * Write unsigned integer to bytes (big-endian)
56
+ */
57
+ export function writeUint(value: number, bytes: number): Uint8Array {
58
+ const result = new Uint8Array(bytes)
59
+
60
+ for (let i = bytes - 1; i >= 0; i--) {
61
+ result[i] = value & 0xff
62
+ value = value >>> 8
63
+ }
64
+
65
+ return result
66
+ }
67
+
68
+ /**
69
+ * Write BigInt to bytes (big-endian)
70
+ */
71
+ export function writeBigUint(value: bigint, bytes: number): Uint8Array {
72
+ const result = new Uint8Array(bytes)
73
+
74
+ for (let i = bytes - 1; i >= 0; i--) {
75
+ result[i] = Number(value & 0xffn)
76
+ value = value >> 8n
77
+ }
78
+
79
+ return result
80
+ }