cborg 1.6.1 → 1.8.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.
- package/README.md +108 -11
- package/cjs/browser-test/node-test-bin.js +232 -105
- package/cjs/lib/3string.js +12 -8
- package/cjs/lib/bin.js +39 -23
- package/cjs/lib/diagnostic.js +57 -18
- package/cjs/lib/token.js +1 -0
- package/cjs/node-test/node-test-bin.js +232 -105
- package/esm/browser-test/node-test-bin.js +232 -105
- package/esm/lib/3string.js +16 -9
- package/esm/lib/bin.js +43 -24
- package/esm/lib/diagnostic.js +62 -20
- package/esm/lib/token.js +1 -0
- package/esm/node-test/node-test-bin.js +232 -105
- package/interface.ts +1 -0
- package/lib/3string.js +15 -10
- package/lib/bin.js +52 -27
- package/lib/diagnostic.js +74 -23
- package/lib/token.js +2 -0
- package/package.json +1 -1
- package/test/node-test-bin.js +271 -120
- package/types/interface.d.ts +1 -0
- package/types/interface.d.ts.map +1 -1
- package/types/lib/3string.d.ts +2 -2
- package/types/lib/3string.d.ts.map +1 -1
- package/types/lib/diagnostic.d.ts +6 -0
- package/types/lib/diagnostic.d.ts.map +1 -1
- package/types/lib/token.d.ts +2 -0
- package/types/lib/token.d.ts.map +1 -1
package/lib/bin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import process from 'process'
|
|
4
4
|
import { decode, encode } from '../cborg.js'
|
|
5
|
-
import { tokensToDiagnostic } from './diagnostic.js'
|
|
5
|
+
import { tokensToDiagnostic, fromDiag } from './diagnostic.js'
|
|
6
6
|
import { fromHex as _fromHex, toHex } from './byte-utils.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -11,15 +11,18 @@ import { fromHex as _fromHex, toHex } from './byte-utils.js'
|
|
|
11
11
|
function usage (code) {
|
|
12
12
|
console.error('Usage: cborg <command> <args>')
|
|
13
13
|
console.error('Valid commands:')
|
|
14
|
-
console.error('\thex2diag [hex input]')
|
|
15
|
-
console.error('\thex2bin [hex input]')
|
|
16
|
-
console.error('\thex2json [--pretty] [hex input]')
|
|
17
|
-
console.error('\tbin2hex [binary input]')
|
|
18
14
|
console.error('\tbin2diag [binary input]')
|
|
15
|
+
console.error('\tbin2hex [binary input]')
|
|
19
16
|
console.error('\tbin2json [--pretty] [binary input]')
|
|
20
|
-
console.error('\
|
|
21
|
-
console.error('\
|
|
17
|
+
console.error('\tdiag2bin [diagnostic input]')
|
|
18
|
+
console.error('\tdiag2hex [diagnostic input]')
|
|
19
|
+
console.error('\tdiag2json [--pretty] [diagnostic input]')
|
|
20
|
+
console.error('\thex2bin [hex input]')
|
|
21
|
+
console.error('\thex2diag [hex input]')
|
|
22
|
+
console.error('\thex2json [--pretty] [hex input]')
|
|
22
23
|
console.error('\tjson2bin \'[json input]\'')
|
|
24
|
+
console.error('\tjson2diag \'[json input]\'')
|
|
25
|
+
console.error('\tjson2hex \'[json input]\'')
|
|
23
26
|
console.error('Input may either be supplied as an argument or piped via stdin')
|
|
24
27
|
process.exit(code || 0)
|
|
25
28
|
}
|
|
@@ -59,26 +62,15 @@ async function run () {
|
|
|
59
62
|
return usage(0)
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
case '
|
|
63
|
-
|
|
64
|
-
const bin =
|
|
65
|
-
return console.log(JSON.stringify(decode(bin), undefined, pretty ? 2 : undefined))
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
case 'hex2diag': {
|
|
69
|
-
const bin = fromHex(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
65
|
+
case 'bin2diag': {
|
|
66
|
+
/* c8 ignore next 1 */
|
|
67
|
+
const bin = process.argv.length < 4 ? (await fromStdin()) : new TextEncoder().encode(process.argv[3])
|
|
70
68
|
for (const line of tokensToDiagnostic(bin)) {
|
|
71
69
|
console.log(line)
|
|
72
70
|
}
|
|
73
71
|
return
|
|
74
72
|
}
|
|
75
73
|
|
|
76
|
-
case 'hex2bin': {
|
|
77
|
-
// this is really nothing to do with cbor.. just handy
|
|
78
|
-
const bin = fromHex(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
79
|
-
return process.stdout.write(bin)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
74
|
case 'bin2hex': {
|
|
83
75
|
// this is really nothing to do with cbor.. just handy
|
|
84
76
|
/* c8 ignore next 1 */
|
|
@@ -93,19 +85,52 @@ async function run () {
|
|
|
93
85
|
return console.log(JSON.stringify(decode(bin), undefined, pretty ? 2 : undefined))
|
|
94
86
|
}
|
|
95
87
|
|
|
96
|
-
case '
|
|
88
|
+
case 'diag2bin': {
|
|
89
|
+
// no coverage on windows for non-stdin input
|
|
97
90
|
/* c8 ignore next 1 */
|
|
98
|
-
const bin = process.argv.length < 4 ? (await fromStdin()) :
|
|
91
|
+
const bin = fromDiag(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
92
|
+
return process.stdout.write(bin)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case 'diag2hex': {
|
|
96
|
+
// no coverage on windows for non-stdin input
|
|
97
|
+
/* c8 ignore next 1 */
|
|
98
|
+
const bin = fromDiag(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
99
|
+
return console.log(toHex(bin))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case 'diag2json': {
|
|
103
|
+
const { argv, pretty } = argvPretty()
|
|
104
|
+
// no coverage on windows for non-stdin input
|
|
105
|
+
/* c8 ignore next 1 */
|
|
106
|
+
const bin = fromDiag(argv.length < 4 ? (await fromStdin()).toString() : argv[3])
|
|
107
|
+
return console.log(JSON.stringify(decode(bin), undefined, pretty ? 2 : undefined))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
case 'hex2bin': {
|
|
111
|
+
// this is really nothing to do with cbor.. just handy
|
|
112
|
+
const bin = fromHex(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
113
|
+
return process.stdout.write(bin)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
case 'hex2diag': {
|
|
117
|
+
const bin = fromHex(process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3])
|
|
99
118
|
for (const line of tokensToDiagnostic(bin)) {
|
|
100
119
|
console.log(line)
|
|
101
120
|
}
|
|
102
121
|
return
|
|
103
122
|
}
|
|
104
123
|
|
|
105
|
-
case '
|
|
124
|
+
case 'hex2json': {
|
|
125
|
+
const { argv, pretty } = argvPretty()
|
|
126
|
+
const bin = fromHex(argv.length < 4 ? (await fromStdin()).toString() : argv[3])
|
|
127
|
+
return console.log(JSON.stringify(decode(bin), undefined, pretty ? 2 : undefined))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
case 'json2bin': {
|
|
106
131
|
const inp = process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3]
|
|
107
132
|
const obj = JSON.parse(inp)
|
|
108
|
-
return
|
|
133
|
+
return process.stdout.write(encode(obj))
|
|
109
134
|
}
|
|
110
135
|
|
|
111
136
|
case 'json2diag': {
|
|
@@ -117,10 +142,10 @@ async function run () {
|
|
|
117
142
|
return
|
|
118
143
|
}
|
|
119
144
|
|
|
120
|
-
case '
|
|
145
|
+
case 'json2hex': {
|
|
121
146
|
const inp = process.argv.length < 4 ? (await fromStdin()).toString() : process.argv[3]
|
|
122
147
|
const obj = JSON.parse(inp)
|
|
123
|
-
return
|
|
148
|
+
return console.log(toHex(encode(obj)))
|
|
124
149
|
}
|
|
125
150
|
|
|
126
151
|
default: { // no, or unknown cmd
|
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
|
|
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
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
|
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)}`
|
|
@@ -67,17 +105,16 @@ function * tokensToDiagnostic (inp, width = 100) {
|
|
|
67
105
|
}
|
|
68
106
|
}
|
|
69
107
|
|
|
108
|
+
if (indent.length) {
|
|
109
|
+
indent[indent.length - 1]--
|
|
110
|
+
}
|
|
70
111
|
if (!token.type.terminal) {
|
|
71
112
|
switch (token.type.name) {
|
|
72
113
|
case 'map':
|
|
73
|
-
|
|
74
|
-
indent.push(token.value * 2)
|
|
75
|
-
}
|
|
114
|
+
indent.push(token.value * 2)
|
|
76
115
|
break
|
|
77
116
|
case 'array':
|
|
78
|
-
|
|
79
|
-
indent.push(token.value)
|
|
80
|
-
}
|
|
117
|
+
indent.push(token.value)
|
|
81
118
|
break
|
|
82
119
|
// TODO: test tags .. somehow
|
|
83
120
|
/* c8 ignore next 5 */
|
|
@@ -87,17 +124,31 @@ function * tokensToDiagnostic (inp, width = 100) {
|
|
|
87
124
|
default:
|
|
88
125
|
throw new Error(`Unknown token type '${token.type.name}'`)
|
|
89
126
|
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (indent[indent.length - 1] === 0) {
|
|
94
|
-
indent.pop()
|
|
95
|
-
}
|
|
96
|
-
}
|
|
127
|
+
}
|
|
128
|
+
while (indent.length && indent[indent.length - 1] <= 0) {
|
|
129
|
+
indent.pop()
|
|
97
130
|
}
|
|
98
131
|
// @ts-ignore it should be set on a decode operation
|
|
99
132
|
pos += token.encodedLength
|
|
100
133
|
}
|
|
101
134
|
}
|
|
102
135
|
|
|
103
|
-
|
|
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