cborg 1.6.2 → 1.8.1

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.
package/lib/diagnostic.js CHANGED
@@ -1,12 +1,16 @@
1
1
  import { Tokeniser } from './decode.js'
2
- import { toHex } from './byte-utils.js'
2
+ import { toHex, fromHex } from './byte-utils.js'
3
+ import { uintBoundaries } from './0uint.js'
4
+
5
+ const utf8Encoder = new TextEncoder()
6
+ const utf8Decoder = new TextDecoder()
3
7
 
4
8
  /**
5
9
  * @param {Uint8Array} inp
6
10
  * @param {number} [width]
7
11
  */
8
12
  function * tokensToDiagnostic (inp, width = 100) {
9
- const tokeniser = new Tokeniser(inp)
13
+ const tokeniser = new Tokeniser(inp, { retainStringBytes: true })
10
14
  let pos = 0
11
15
  const indent = []
12
16
 
@@ -26,6 +30,7 @@ function * tokensToDiagnostic (inp, width = 100) {
26
30
  let vLength = token.encodedLength - 1
27
31
  /** @type {string|number} */
28
32
  let v = String(token.value)
33
+ let outp = `${margin}${slc(0, 1)}`
29
34
  const str = token.type.name === 'bytes' || token.type.name === 'string'
30
35
  if (token.type.name === 'string') {
31
36
  v = v.length
@@ -36,7 +41,33 @@ function * tokensToDiagnostic (inp, width = 100) {
36
41
  vLength -= v
37
42
  }
38
43
 
39
- let outp = `${margin}${slc(0, 1)} ${slc(1, vLength)}`
44
+ let multilen
45
+ switch (token.type.name) {
46
+ case 'string':
47
+ case 'bytes':
48
+ case 'map':
49
+ case 'array':
50
+ // for bytes and string, we want to print out the length part of the value prefix if it
51
+ // exists - it exists for short lengths (<24) but does for longer lengths
52
+ multilen = token.type.name === 'string' ? utf8Encoder.encode(token.value).length : token.value.length
53
+ if (multilen >= uintBoundaries[0]) {
54
+ if (multilen < uintBoundaries[1]) {
55
+ outp += ` ${slc(1, 1)}`
56
+ } else if (multilen < uintBoundaries[2]) {
57
+ outp += ` ${slc(1, 2)}`
58
+ /* c8 ignore next 5 */
59
+ } else if (multilen < uintBoundaries[3]) { // sus
60
+ outp += ` ${slc(1, 4)}`
61
+ } else if (multilen < uintBoundaries[4]) { // orly?
62
+ outp += ` ${slc(1, 8)}`
63
+ }
64
+ }
65
+ break
66
+ default:
67
+ // print the value if it's not compacted into the first byte
68
+ outp += ` ${slc(1, vLength)}`
69
+ break
70
+ }
40
71
 
41
72
  outp = outp.padEnd(width / 2, ' ')
42
73
  outp += `# ${margin}${token.type.name}`
@@ -46,19 +77,26 @@ function * tokensToDiagnostic (inp, width = 100) {
46
77
  yield outp
47
78
 
48
79
  if (str) {
80
+ let asString = token.type.name === 'string'
49
81
  margin += ' '
50
- const repr = token.type.name === 'bytes' ? token.value : new TextEncoder().encode(token.value)
82
+ let repr = asString ? utf8Encoder.encode(token.value) : token.value
83
+ if (asString && token.byteValue !== undefined) {
84
+ if (repr.length !== token.byteValue.length) {
85
+ // bail on printing this as a string, it's probably not utf8, so treat it as bytes
86
+ // (you can probably blame a Go programmer for this)
87
+ repr = token.byteValue
88
+ asString = false
89
+ }
90
+ }
51
91
  const wh = ((width / 2) - margin.length - 1) / 2
52
92
  let snip = 0
53
93
  while (repr.length - snip > 0) {
54
94
  const piece = repr.slice(snip, snip + wh)
55
95
  snip += piece.length
56
- // the assumption that we can utf8 a byte-sliced version is a stretch,
57
- // we could be slicing in the middle of a multi-byte character
58
- const st = token.type.name === 'string'
59
- ? new TextDecoder().decode(piece)
96
+ const st = asString
97
+ ? utf8Decoder.decode(piece)
60
98
  : piece.reduce((/** @type {string} */ p, /** @type {number} */ c) => {
61
- if (c < 0x20 || c === 0x7f) {
99
+ if (c < 0x20 || (c >= 0x7f && c < 0xa1) || c === 0xad) {
62
100
  return `${p}\\x${c.toString(16).padStart(2, '0')}`
63
101
  }
64
102
  return `${p}${String.fromCharCode(c)}`
@@ -95,4 +133,22 @@ function * tokensToDiagnostic (inp, width = 100) {
95
133
  }
96
134
  }
97
135
 
98
- export { tokensToDiagnostic }
136
+ /**
137
+ * Convert an input string formatted as CBOR diagnostic output into binary CBOR form.
138
+ * @param {string} input
139
+ * @returns {Uint8Array}
140
+ */
141
+ function fromDiag (input) {
142
+ /* c8 ignore next 3 */
143
+ if (typeof input !== 'string') {
144
+ throw new TypeError('Expected string input')
145
+ }
146
+ input = input.replace(/#.*?$/mg, '').replace(/[\s\r\n]+/mg, '')
147
+ /* c8 ignore next 3 */
148
+ if (/[^a-f0-9]/i.test(input)) {
149
+ throw new TypeError('Input string was not CBOR diagnostic format')
150
+ }
151
+ return fromHex(input)
152
+ }
153
+
154
+ export { tokensToDiagnostic, fromDiag }
package/lib/token.js CHANGED
@@ -54,6 +54,8 @@ class Token {
54
54
  this.encodedLength = encodedLength
55
55
  /** @type {Uint8Array|undefined} */
56
56
  this.encodedBytes = undefined
57
+ /** @type {Uint8Array|undefined} */
58
+ this.byteValue = undefined
57
59
  }
58
60
 
59
61
  /* c8 ignore next 3 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cborg",
3
- "version": "1.6.2",
3
+ "version": "1.8.1",
4
4
  "description": "Fast CBOR with a focus on strictness",
5
5
  "main": "./cjs/cborg.js",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  "mocha": "^9.1.3",
40
40
  "polendina": "~2.0.1",
41
41
  "standard": "^16.0.4",
42
- "typescript": "~4.5.3"
42
+ "typescript": "~4.6.2"
43
43
  },
44
44
  "exports": {
45
45
  ".": {
@@ -4,12 +4,63 @@ import chai from 'chai'
4
4
  import { exec } from 'child_process'
5
5
  import process from 'process'
6
6
  import path from 'path'
7
+ import { platform } from 'os'
7
8
  import { fileURLToPath } from 'url'
8
9
  // included here for ipjs compile tree
9
10
  import bin from '../lib/bin.js' // eslint-disable-line
10
11
 
11
12
  const { assert } = chai
12
13
 
14
+ const fixture1JsonString = '{"a":1,"b":[2,3],"smile":"😀"}'
15
+ const fixture1JsonPrettyString =
16
+ `{
17
+ "a": 1,
18
+ "b": [
19
+ 2,
20
+ 3
21
+ ],
22
+ "smile": "😀"
23
+ }
24
+ `
25
+ const fixture1HexString = 'a3616101616282020365736d696c6564f09f9880'
26
+ const fixture1Bin = fromHex(fixture1HexString)
27
+ const fixture1BinString = new TextDecoder().decode(fixture1Bin)
28
+ const fixture1DiagnosticString =
29
+ `a3 # map(3)
30
+ 61 # string(1)
31
+ 61 # "a"
32
+ 01 # uint(1)
33
+ 61 # string(1)
34
+ 62 # "b"
35
+ 82 # array(2)
36
+ 02 # uint(2)
37
+ 03 # uint(3)
38
+ 65 # string(5)
39
+ 736d696c65 # "smile"
40
+ 64 # string(2)
41
+ f09f9880 # "😀"
42
+ `
43
+ const fixture2HexString = 'a4616101616282020363627566440102036165736d696c6564f09f9880'
44
+ const fixture2DiagnosticString =
45
+ `a4 # map(4)
46
+ 61 # string(1)
47
+ 61 # "a"
48
+ 01 # uint(1)
49
+ 61 # string(1)
50
+ 62 # "b"
51
+ 82 # array(2)
52
+ 02 # uint(2)
53
+ 03 # uint(3)
54
+ 63 # string(3)
55
+ 627566 # "buf"
56
+ 44 # bytes(4)
57
+ 01020361 # "\\x01\\x02\\x03a"
58
+ 65 # string(5)
59
+ 736d696c65 # "smile"
60
+ 64 # string(2)
61
+ f09f9880 # "😀"
62
+ `
63
+
13
64
  const binPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '../lib/bin.js')
14
65
 
15
66
  function fromHex (hex) {
@@ -48,15 +99,18 @@ describe('Bin', () => {
48
99
  assert.strictEqual(e.stderr,
49
100
  `Usage: cborg <command> <args>
50
101
  Valid commands:
51
- \thex2diag [hex input]
52
- \thex2bin [hex input]
53
- \thex2json [--pretty] [hex input]
54
- \tbin2hex [binary input]
55
102
  \tbin2diag [binary input]
103
+ \tbin2hex [binary input]
56
104
  \tbin2json [--pretty] [binary input]
57
- \tjson2hex '[json input]'
58
- \tjson2diag '[json input]'
105
+ \tdiag2bin [diagnostic input]
106
+ \tdiag2hex [diagnostic input]
107
+ \tdiag2json [--pretty] [diagnostic input]
108
+ \thex2bin [hex input]
109
+ \thex2diag [hex input]
110
+ \thex2json [--pretty] [hex input]
59
111
  \tjson2bin '[json input]'
112
+ \tjson2diag '[json input]'
113
+ \tjson2hex '[json input]'
60
114
  Input may either be supplied as an argument or piped via stdin
61
115
  `)
62
116
  }
@@ -72,15 +126,18 @@ Input may either be supplied as an argument or piped via stdin
72
126
  `Unknown command: 'blip'
73
127
  Usage: cborg <command> <args>
74
128
  Valid commands:
75
- \thex2diag [hex input]
76
- \thex2bin [hex input]
77
- \thex2json [--pretty] [hex input]
78
- \tbin2hex [binary input]
79
129
  \tbin2diag [binary input]
130
+ \tbin2hex [binary input]
80
131
  \tbin2json [--pretty] [binary input]
81
- \tjson2hex '[json input]'
82
- \tjson2diag '[json input]'
132
+ \tdiag2bin [diagnostic input]
133
+ \tdiag2hex [diagnostic input]
134
+ \tdiag2json [--pretty] [diagnostic input]
135
+ \thex2bin [hex input]
136
+ \thex2diag [hex input]
137
+ \thex2json [--pretty] [hex input]
83
138
  \tjson2bin '[json input]'
139
+ \tjson2diag '[json input]'
140
+ \tjson2hex '[json input]'
84
141
  Input may either be supplied as an argument or piped via stdin
85
142
  `)
86
143
  }
@@ -92,164 +149,137 @@ Input may either be supplied as an argument or piped via stdin
92
149
  assert.strictEqual(stderr,
93
150
  `Usage: cborg <command> <args>
94
151
  Valid commands:
95
- \thex2diag [hex input]
96
- \thex2bin [hex input]
97
- \thex2json [--pretty] [hex input]
98
- \tbin2hex [binary input]
99
152
  \tbin2diag [binary input]
153
+ \tbin2hex [binary input]
100
154
  \tbin2json [--pretty] [binary input]
101
- \tjson2hex '[json input]'
102
- \tjson2diag '[json input]'
155
+ \tdiag2bin [diagnostic input]
156
+ \tdiag2hex [diagnostic input]
157
+ \tdiag2json [--pretty] [diagnostic input]
158
+ \thex2bin [hex input]
159
+ \thex2diag [hex input]
160
+ \thex2json [--pretty] [hex input]
103
161
  \tjson2bin '[json input]'
162
+ \tjson2diag '[json input]'
163
+ \tjson2hex '[json input]'
104
164
  Input may either be supplied as an argument or piped via stdin
105
165
  `)
106
166
  })
107
167
 
168
+ it('bin2diag (stdin)', async () => {
169
+ const { stdout, stderr } = await execBin('bin2diag', fixture1Bin)
170
+ assert.strictEqual(stderr, '')
171
+ assert.strictEqual(stdout, fixture1DiagnosticString)
172
+ })
173
+
174
+ it('bin2hex (stdin)', async () => {
175
+ const { stdout, stderr } = await execBin('bin2hex', fixture1Bin)
176
+ assert.strictEqual(stderr, '')
177
+ assert.strictEqual(stdout, `${fixture1HexString}\n`)
178
+ })
179
+
180
+ it('bin2json (stdin)', async () => {
181
+ const { stdout, stderr } = await execBin('bin2json', fixture1Bin)
182
+ assert.strictEqual(stderr, '')
183
+ assert.strictEqual(stdout, `${fixture1JsonString}\n`)
184
+ })
185
+
186
+ it('bin2json pretty (stdin)', async () => {
187
+ const { stdout, stderr } = await execBin('bin2json --pretty', fixture1Bin)
188
+ assert.strictEqual(stderr, '')
189
+ assert.strictEqual(stdout, fixture1JsonPrettyString)
190
+ })
191
+
108
192
  for (const stdin of [true, false]) {
109
- it(`hex2json${stdin ? ' (stdin)' : ''}`, async () => {
110
- const { stdout, stderr } = stdin
111
- ? await execBin('hex2json a3616101616282020365736d696c6564f09f9880')
112
- : await execBin('hex2json', 'a3616101616282020365736d696c6564f09f9880')
113
- assert.strictEqual(stderr, '')
114
- assert.strictEqual(stdout, '{"a":1,"b":[2,3],"smile":"😀"}\n')
115
- })
193
+ if (platform() !== 'win32' || stdin) { // multiline CLI input is hard (impossible?) on Windows
194
+ it(`diag2bin${stdin ? ' (stdin)' : ''}`, async () => {
195
+ const { stdout, stderr } = !stdin
196
+ ? await execBin(`diag2bin '${fixture1DiagnosticString}'`)
197
+ : await execBin('diag2bin', fixture1DiagnosticString)
198
+ assert.strictEqual(stderr, '')
199
+ assert.strictEqual(stdout, fixture1BinString)
200
+ })
116
201
 
117
- it(`hex2json pretty${stdin ? ' (stdin)' : ''}`, async () => {
118
- const { stdout, stderr } = stdin
119
- ? await execBin('hex2json --pretty a3616101616282020365736d696c6564f09f9880')
120
- : await execBin('hex2json --pretty', 'a3616101616282020365736d696c6564f09f9880')
202
+ it(`diag2hex${stdin ? ' (stdin)' : ''}`, async () => {
203
+ const { stdout, stderr } = !stdin
204
+ ? await execBin(`diag2hex '${fixture1DiagnosticString}'`)
205
+ : await execBin('diag2hex', fixture1DiagnosticString)
206
+ assert.strictEqual(stderr, '')
207
+ assert.strictEqual(stdout, `${fixture1HexString}\n`)
208
+ })
209
+
210
+ it(`diag2json${stdin ? ' (stdin)' : ''}`, async () => {
211
+ const { stdout, stderr } = !stdin
212
+ ? await execBin(`diag2json '${fixture1DiagnosticString}'`)
213
+ : await execBin('diag2json', fixture1DiagnosticString)
214
+ assert.strictEqual(stderr, '')
215
+ assert.strictEqual(stdout, `${fixture1JsonString}\n`)
216
+ })
217
+
218
+ it(`diag2json pretty${stdin ? ' (stdin)' : ''}`, async () => {
219
+ const { stdout, stderr } = !stdin
220
+ ? await execBin(`diag2json --pretty '${fixture1DiagnosticString}'`)
221
+ : await execBin('diag2json --pretty', fixture1DiagnosticString)
222
+ assert.strictEqual(stderr, '')
223
+ assert.strictEqual(stdout, fixture1JsonPrettyString)
224
+ })
225
+ }
226
+
227
+ it(`hex2bin${stdin ? ' (stdin)' : ''}`, async () => {
228
+ const { stdout, stderr } = !stdin
229
+ ? await execBin(`hex2bin ${fixture1HexString}`)
230
+ : await execBin('hex2bin', fixture1HexString)
121
231
  assert.strictEqual(stderr, '')
122
- assert.strictEqual(stdout,
123
- `{
124
- "a": 1,
125
- "b": [
126
- 2,
127
- 3
128
- ],
129
- "smile": "😀"
130
- }
131
- `)
232
+ assert.strictEqual(stdout, fixture1BinString)
132
233
  })
133
234
 
134
235
  it(`hex2diag${stdin ? ' (stdin)' : ''}`, async () => {
135
- const { stdout, stderr } = stdin
136
- ? await execBin('hex2diag a4616101616282020363627566440102036165736d696c6564f09f9880')
137
- : await execBin('hex2diag', 'a4616101616282020363627566440102036165736d696c6564f09f9880')
236
+ const { stdout, stderr } = !stdin
237
+ ? await execBin(`hex2diag ${fixture2HexString}`)
238
+ : await execBin('hex2diag', fixture2HexString)
138
239
  assert.strictEqual(stderr, '')
139
- assert.strictEqual(stdout,
140
- `a4 # map(4)
141
- 61 # string(1)
142
- 61 # "a"
143
- 01 # uint(1)
144
- 61 # string(1)
145
- 62 # "b"
146
- 82 # array(2)
147
- 02 # uint(2)
148
- 03 # uint(3)
149
- 63 # string(3)
150
- 627566 # "buf"
151
- 44 # bytes(4)
152
- 01020361 # "\\x01\\x02\\x03a"
153
- 65 # string(5)
154
- 736d696c65 # "smile"
155
- 64 f09f # string(2)
156
- f09f9880 # "😀"
157
- `)
240
+ assert.strictEqual(stdout, fixture2DiagnosticString)
158
241
  })
159
242
 
160
- it(`hex2bin${stdin ? ' (stdin)' : ''}`, async () => {
161
- const { stdout, stderr } = stdin
162
- ? await execBin('hex2bin a3616101616282020365736d696c6564f09f9880')
163
- : await execBin('hex2bin', 'a3616101616282020365736d696c6564f09f9880')
243
+ it(`hex2json${stdin ? ' (stdin)' : ''}`, async () => {
244
+ const { stdout, stderr } = !stdin
245
+ ? await execBin(`hex2json ${fixture1HexString}`)
246
+ : await execBin('hex2json', fixture1HexString)
164
247
  assert.strictEqual(stderr, '')
165
- assert.strictEqual(stdout, new TextDecoder().decode(fromHex('a3616101616282020365736d696c6564f09f9880')))
248
+ assert.strictEqual(stdout, `${fixture1JsonString}\n`)
166
249
  })
167
250
 
168
- it(`json2hex${stdin ? ' (stdin)' : ''}`, async () => {
169
- const { stdout, stderr } = stdin
170
- ? await execBin('json2hex "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"😀\\"}"')
171
- : await execBin('json2hex', '{"a":1,"b":[2,3],"smile":"😀"}')
251
+ it(`hex2json pretty${stdin ? ' (stdin)' : ''}`, async () => {
252
+ const { stdout, stderr } = !stdin
253
+ ? await execBin(`hex2json --pretty ${fixture1HexString}`)
254
+ : await execBin('hex2json --pretty', fixture1HexString)
172
255
  assert.strictEqual(stderr, '')
173
- assert.strictEqual(stdout, 'a3616101616282020365736d696c6564f09f9880\n')
256
+ assert.strictEqual(stdout, fixture1JsonPrettyString)
174
257
  })
175
258
 
176
259
  it(`json2bin${stdin ? ' (stdin)' : ''}`, async () => {
177
- const { stdout, stderr } = stdin
260
+ const { stdout, stderr } = !stdin
178
261
  ? await execBin('json2bin "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"😀\\"}"')
179
- : await execBin('json2bin', '{"a":1,"b":[2,3],"smile":"😀"}')
262
+ : await execBin('json2bin', fixture1JsonString)
180
263
  assert.strictEqual(stderr, '')
181
- assert.strictEqual(stdout, new TextDecoder().decode(fromHex('a3616101616282020365736d696c6564f09f9880')))
264
+ assert.strictEqual(stdout, fixture1BinString)
182
265
  })
183
266
 
184
267
  it(`json2diag${stdin ? ' (stdin)' : ''}`, async () => {
185
- const { stdout, stderr } = stdin
268
+ const { stdout, stderr } = !stdin
186
269
  ? await execBin('json2diag "{\\"a\\":1,\\"b\\":[2,3],\\"smile\\":\\"😀\\"}"')
187
- : await execBin('json2diag', '{"a":1,"b":[2,3],"smile":"😀"}')
270
+ : await execBin('json2diag', fixture1JsonString)
188
271
  assert.strictEqual(stderr, '')
189
- assert.strictEqual(stdout,
190
- `a3 # map(3)
191
- 61 # string(1)
192
- 61 # "a"
193
- 01 # uint(1)
194
- 61 # string(1)
195
- 62 # "b"
196
- 82 # array(2)
197
- 02 # uint(2)
198
- 03 # uint(3)
199
- 65 # string(5)
200
- 736d696c65 # "smile"
201
- 64 f09f # string(2)
202
- f09f9880 # "😀"
203
- `)
272
+ assert.strictEqual(stdout, fixture1DiagnosticString)
204
273
  })
205
- }
206
274
 
207
- it('bin2diag (stdin)', async () => {
208
- const { stdout, stderr } = await execBin('bin2diag', fromHex('a3616101616282020365736d696c6564f09f9880'))
209
- assert.strictEqual(stderr, '')
210
- assert.strictEqual(stdout,
211
- `a3 # map(3)
212
- 61 # string(1)
213
- 61 # "a"
214
- 01 # uint(1)
215
- 61 # string(1)
216
- 62 # "b"
217
- 82 # array(2)
218
- 02 # uint(2)
219
- 03 # uint(3)
220
- 65 # string(5)
221
- 736d696c65 # "smile"
222
- 64 f09f # string(2)
223
- f09f9880 # "😀"
224
- `)
225
- })
226
-
227
- it('bin2json (stdin)', async () => {
228
- const { stdout, stderr } = await execBin('bin2json', fromHex('a3616101616282020365736d696c6564f09f9880'))
229
- assert.strictEqual(stderr, '')
230
- assert.strictEqual(stdout, '{"a":1,"b":[2,3],"smile":"😀"}\n')
231
- })
232
-
233
- it('bin2json pretty (stdin)', async () => {
234
- const { stdout, stderr } = await execBin('bin2json --pretty', fromHex('a3616101616282020365736d696c6564f09f9880'))
235
- assert.strictEqual(stderr, '')
236
- assert.strictEqual(stdout,
237
- `{
238
- "a": 1,
239
- "b": [
240
- 2,
241
- 3
242
- ],
243
- "smile": "😀"
244
- }
245
- `)
246
- })
247
-
248
- it('bin2hex (stdin)', async () => {
249
- const { stdout, stderr } = await execBin('bin2hex', fromHex('a3616101616282020365736d696c6564f09f9880'))
250
- assert.strictEqual(stderr, '')
251
- assert.strictEqual(stdout, 'a3616101616282020365736d696c6564f09f9880\n')
252
- })
275
+ it(`json2hex${stdin ? ' (stdin)' : ''}`, async () => {
276
+ const { stdout, stderr } = !stdin
277
+ ? await execBin(`json2hex "${fixture1JsonString.replace(/"/g, '\\"')}"`)
278
+ : await execBin('json2hex', fixture1JsonString)
279
+ assert.strictEqual(stderr, '')
280
+ assert.strictEqual(stdout, `${fixture1HexString}\n`)
281
+ })
282
+ }
253
283
 
254
284
  // complicated nesting to test indenting algorithm
255
285
  it('diag indenting', async () => {
@@ -311,4 +341,64 @@ Input may either be supplied as an argument or piped via stdin
311
341
  01 # uint(1)
312
342
  `)
313
343
  })
344
+
345
+ describe('diag length bytes', () => {
346
+ it('compact', async () => {
347
+ const { stdout, stderr } = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaa"')
348
+ assert.strictEqual(stderr, '')
349
+ assert.strictEqual(stdout,
350
+ `77 # string(23)
351
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
352
+ `)
353
+ })
354
+
355
+ it('1-byte', async () => {
356
+ const { stdout, stderr } = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"')
357
+ assert.strictEqual(stderr, '')
358
+ assert.strictEqual(stdout,
359
+ `78 23 # string(35)
360
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
361
+ 616161616161616161616161 # "aaaaaaaaaaaa"
362
+ `)
363
+ })
364
+
365
+ it('2-byte', async () => {
366
+ const { stdout, stderr } = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"')
367
+ assert.strictEqual(stderr, '')
368
+ assert.strictEqual(stdout,
369
+ `79 0100 # string(256)
370
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
371
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
372
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
373
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
374
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
375
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
376
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
377
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
378
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
379
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
380
+ 6161616161616161616161616161616161616161616161 # "aaaaaaaaaaaaaaaaaaaaaaa"
381
+ 616161 # "aaa"
382
+ `)
383
+ })
384
+ })
385
+
386
+ it('diag non-utf8 and non-printable ascii', async () => {
387
+ const input = '7864f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c11e756338bd93865e645f1adec9b9c99ef407fbd4fc6859e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82f9f18c3d03418e35'
388
+ let { stdout, stderr } = await execBin(`hex2diag ${input}`)
389
+ assert.strictEqual(stderr, '')
390
+ assert.strictEqual(stdout,
391
+ `78 64 # string(86)
392
+ f55ff8f12508b63ef2bfeca7557ae90df6311a5ec1631b # "õ_øñ%\\x08¶>ò¿ì§Uzé\\x0dö1\\x1a^Ác\\x1b"
393
+ 4a1fa843310bd9c3a710eaace5a1bdd72ad0bfe049771c # "J\\x1f¨C1\\x0bÙç\\x10ê¬å¡½×*пàIw\\x1c"
394
+ 11e756338bd93865e645f1adec9b9c99ef407fbd4fc685 # "\\x11çV3\\x8bÙ8eæEñ\\xadì\\x9b\\x9c\\x99ï@\\x7f½OÆ\\x85"
395
+ 9e7904c5ad7dc9bd10a5cc16973d5b28ec1a6dd43d9f82 # "\\x9ey\\x04Å\\xad}ɽ\\x10¥Ì\\x16\\x97=[(ì\\x1amÔ=\\x9f\\x82"
396
+ f9f18c3d03418e35 # "ùñ\\x8c=\\x03A\\x8e5"
397
+ `)
398
+
399
+ // round-trip
400
+ ;({ stdout, stderr } = await execBin('diag2hex', stdout))
401
+ assert.strictEqual(stderr, '')
402
+ assert.strictEqual(stdout, `${input}\n`)
403
+ })
314
404
  })
@@ -29,6 +29,7 @@ export interface DecodeOptions {
29
29
  allowBigInt?: boolean;
30
30
  strict?: boolean;
31
31
  useMaps?: boolean;
32
+ retainStringBytes?: boolean;
32
33
  tags?: TagDecoder[];
33
34
  tokenizer?: DecodeTokenizer;
34
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAA;AAE7B,oBAAY,mBAAmB,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAA;AAEzE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,CAAA;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAA;CACvC;AAED,oBAAY,mBAAmB,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,mBAAmB,GAAG,IAAI,CAAA;AAEtI,oBAAY,iBAAiB,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,mBAAmB,CAAA;AAE7H,oBAAY,gBAAgB,GAAG;IAC7B,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACvD,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,CAAC;IAC5C,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CAC7D,CAAA;AAED,oBAAY,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,EAAE,KAAK,MAAM,CAAA;AAEpF,oBAAY,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,CAAA;AAEvE,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC;IAChB,IAAI,IAAI,KAAK,CAAA;CACd;AAED,oBAAY,UAAU,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;AAE5C,MAAM,WAAW,aAAa;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CAAA;KAAE,CAAA;CAC3D"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAA;AAE7B,oBAAY,mBAAmB,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAA;AAEzE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,CAAA;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAA;CACvC;AAED,oBAAY,mBAAmB,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,mBAAmB,GAAG,IAAI,CAAA;AAEtI,oBAAY,iBAAiB,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,mBAAmB,CAAA;AAE7H,oBAAY,gBAAgB,GAAG;IAC7B,CAAC,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACvD,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,MAAM,CAAC;IAC5C,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;CAC7D,CAAA;AAED,oBAAY,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,EAAE,CAAC,EAAE,KAAK,MAAM,CAAA;AAEpF,oBAAY,gBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,CAAA;AAEvE,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC;IAChB,IAAI,IAAI,KAAK,CAAA;CACd;AAED,oBAAY,UAAU,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;AAE5C,MAAM,WAAW,aAAa;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CAAA;KAAE,CAAA;CAC3D"}
@@ -2,10 +2,10 @@
2
2
  * @param {Uint8Array} data
3
3
  * @param {number} pos
4
4
  * @param {number} minor
5
- * @param {DecodeOptions} _options
5
+ * @param {DecodeOptions} options
6
6
  * @returns {Token}
7
7
  */
8
- export function decodeStringCompact(data: Uint8Array, pos: number, minor: number, _options: DecodeOptions): Token;
8
+ export function decodeStringCompact(data: Uint8Array, pos: number, minor: number, options: DecodeOptions): Token;
9
9
  /**
10
10
  * @param {Uint8Array} data
11
11
  * @param {number} pos
@@ -1 +1 @@
1
- {"version":3,"file":"3string.d.ts","sourceRoot":"","sources":["../../lib/3string.js"],"names":[],"mappings":"AAwBA;;;;;;GAMG;AACH,0CANW,UAAU,OACV,MAAM,SACN,MAAM,YACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAGD;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAQjB;AAED,8CAAuC;iBA7E1B,OAAO,SAAS,EAAE,EAAE;4BACpB,OAAO,cAAc,EAAE,aAAa"}
1
+ {"version":3,"file":"3string.d.ts","sourceRoot":"","sources":["../../lib/3string.js"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,0CANW,UAAU,OACV,MAAM,SACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAGD;;;;;;GAMG;AACH,qCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAQjB;AAED,8CAAuC;iBAlF1B,OAAO,SAAS,EAAE,EAAE;4BACpB,OAAO,cAAc,EAAE,aAAa"}
@@ -3,4 +3,10 @@
3
3
  * @param {number} [width]
4
4
  */
5
5
  export function tokensToDiagnostic(inp: Uint8Array, width?: number | undefined): Generator<string, void, unknown>;
6
+ /**
7
+ * Convert an input string formatted as CBOR diagnostic output into binary CBOR form.
8
+ * @param {string} input
9
+ * @returns {Uint8Array}
10
+ */
11
+ export function fromDiag(input: string): Uint8Array;
6
12
  //# sourceMappingURL=diagnostic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostic.d.ts","sourceRoot":"","sources":["../../lib/diagnostic.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wCAHW,UAAU,gEA2FpB"}
1
+ {"version":3,"file":"diagnostic.d.ts","sourceRoot":"","sources":["../../lib/diagnostic.js"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wCAHW,UAAU,gEA6HpB;AAED;;;;GAIG;AACH,gCAHW,MAAM,GACJ,UAAU,CAatB"}
@@ -47,6 +47,8 @@ export class Token {
47
47
  encodedLength: number | undefined;
48
48
  /** @type {Uint8Array|undefined} */
49
49
  encodedBytes: Uint8Array | undefined;
50
+ /** @type {Uint8Array|undefined} */
51
+ byteValue: Uint8Array | undefined;
50
52
  toString(): string;
51
53
  }
52
54
  //# sourceMappingURL=token.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../lib/token.js"],"names":[],"mappings":"AAAA;IACE;;;;OAIG;IACH,mBAJW,MAAM,QACN,MAAM,YACN,OAAO,EAOjB;IAJC,cAAkB;IAClB,qBAA8B;IAC9B,aAAgB;IAChB,kBAAwB;IAI1B,mBAEC;IAED;;;OAGG;IACH,aAHW,IAAI,GACF,MAAM,CAKlB;CACF;;;;;;;;;;;;;;;;;;;;AAkBD;IACE;;;;OAIG;IACH,kBAJW,IAAI,UACJ,GAAG,sCASb;IALC,WAAgB;IAChB,WAAkB;IAClB,kCAAkC;IAClC,mCAAmC;IACnC,cADW,UAAU,GAAC,SAAS,CACF;IAI/B,mBAEC;CACF"}
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../lib/token.js"],"names":[],"mappings":"AAAA;IACE;;;;OAIG;IACH,mBAJW,MAAM,QACN,MAAM,YACN,OAAO,EAOjB;IAJC,cAAkB;IAClB,qBAA8B;IAC9B,aAAgB;IAChB,kBAAwB;IAI1B,mBAEC;IAED;;;OAGG;IACH,aAHW,IAAI,GACF,MAAM,CAKlB;CACF;;;;;;;;;;;;;;;;;;;;AAkBD;IACE;;;;OAIG;IACH,kBAJW,IAAI,UACJ,GAAG,sCAWb;IAPC,WAAgB;IAChB,WAAkB;IAClB,kCAAkC;IAClC,mCAAmC;IACnC,cADW,UAAU,GAAC,SAAS,CACF;IAC7B,mCAAmC;IACnC,WADW,UAAU,GAAC,SAAS,CACL;IAI5B,mBAEC;CACF"}