cborg 1.5.4 → 1.7.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/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('\tjson2hex \'[json input]\'')
21
- console.error('\tjson2diag \'[json input]\'')
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 'hex2json': {
63
- const { argv, pretty } = argvPretty()
64
- const bin = fromHex(argv.length < 4 ? (await fromStdin()).toString() : argv[3])
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 'bin2diag': {
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()) : new TextEncoder().encode(process.argv[3])
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 'json2hex': {
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 console.log(toHex(encode(obj)))
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 'json2bin': {
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 process.stdout.write(encode(obj))
148
+ return console.log(toHex(encode(obj)))
124
149
  }
125
150
 
126
151
  default: { // no, or unknown cmd
package/lib/diagnostic.js CHANGED
@@ -1,5 +1,9 @@
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
@@ -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}`
@@ -47,7 +78,7 @@ function * tokensToDiagnostic (inp, width = 100) {
47
78
 
48
79
  if (str) {
49
80
  margin += ' '
50
- const repr = token.type.name === 'bytes' ? token.value : new TextEncoder().encode(token.value)
81
+ const repr = token.type.name === 'bytes' ? token.value : utf8Encoder.encode(token.value)
51
82
  const wh = ((width / 2) - margin.length - 1) / 2
52
83
  let snip = 0
53
84
  while (repr.length - snip > 0) {
@@ -56,7 +87,7 @@ function * tokensToDiagnostic (inp, width = 100) {
56
87
  // the assumption that we can utf8 a byte-sliced version is a stretch,
57
88
  // we could be slicing in the middle of a multi-byte character
58
89
  const st = token.type.name === 'string'
59
- ? new TextDecoder().decode(piece)
90
+ ? utf8Decoder.decode(piece)
60
91
  : piece.reduce((/** @type {string} */ p, /** @type {number} */ c) => {
61
92
  if (c < 0x20 || c === 0x7f) {
62
93
  return `${p}\\x${c.toString(16).padStart(2, '0')}`
@@ -67,6 +98,9 @@ function * tokensToDiagnostic (inp, width = 100) {
67
98
  }
68
99
  }
69
100
 
101
+ if (indent.length) {
102
+ indent[indent.length - 1]--
103
+ }
70
104
  if (!token.type.terminal) {
71
105
  switch (token.type.name) {
72
106
  case 'map':
@@ -83,17 +117,31 @@ function * tokensToDiagnostic (inp, width = 100) {
83
117
  default:
84
118
  throw new Error(`Unknown token type '${token.type.name}'`)
85
119
  }
86
- } else {
87
- if (indent.length) {
88
- indent[indent.length - 1]--
89
- if (indent[indent.length - 1] === 0) {
90
- indent.pop()
91
- }
92
- }
120
+ }
121
+ while (indent.length && indent[indent.length - 1] <= 0) {
122
+ indent.pop()
93
123
  }
94
124
  // @ts-ignore it should be set on a decode operation
95
125
  pos += token.encodedLength
96
126
  }
97
127
  }
98
128
 
99
- export { tokensToDiagnostic }
129
+ /**
130
+ * Convert an input string formatted as CBOR diagnostic output into binary CBOR form.
131
+ * @param {string} input
132
+ * @returns {Uint8Array}
133
+ */
134
+ function fromDiag (input) {
135
+ /* c8 ignore next 3 */
136
+ if (typeof input !== 'string') {
137
+ throw new TypeError('Expected string input')
138
+ }
139
+ input = input.replace(/#.*?$/mg, '').replace(/[\s\r\n]+/mg, '')
140
+ /* c8 ignore next 3 */
141
+ if (/[^a-f0-9]/i.test(input)) {
142
+ throw new TypeError('Input string was not CBOR diagnostic format')
143
+ }
144
+ return fromHex(input)
145
+ }
146
+
147
+ export { tokensToDiagnostic, fromDiag }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cborg",
3
- "version": "1.5.4",
3
+ "version": "1.7.0",
4
4
  "description": "Fast CBOR with a focus on strictness",
5
5
  "main": "./cjs/cborg.js",
6
6
  "bin": {
@@ -13,11 +13,13 @@
13
13
  "build:copy": "mkdir -p dist/test && cp test/*.js dist/test/ && cp -a tsconfig.json *.js *.ts lib dist/",
14
14
  "build:types": "npm run build:copy && cd dist && tsc --build",
15
15
  "test:cjs": "npm run build && mocha dist/cjs/node-test/test-*.js dist/cjs/node-test/node-test-*.js",
16
+ "test:esm": "npm run build && mocha dist/esm/node-test/test-*.js dist/esm/node-test/node-test-*.js",
16
17
  "test:node": "c8 --check-coverage --branches 100 --functions 100 --lines 100 mocha test/test-*.js test/node-test-*.js",
17
- "test:browser:cjs": "polendina --page --worker --serviceworker --cleanup dist/cjs/node-test/test-*.js",
18
- "test:browser:esm": "polendina --page --worker --serviceworker --cleanup dist/esm/node-test/test-*.js",
18
+ "test:browser:cjs": "polendina --page --worker --serviceworker --cleanup dist/cjs/browser-test/test-*.js",
19
+ "test:browser:esm": "polendina --page --worker --serviceworker --cleanup dist/esm/browser-test/test-*.js",
19
20
  "test:browser": "npm run test:browser:cjs && npm run test:browser:cjs",
20
- "test": "npm run lint && npm run test:node && npm run test:cjs && npm run test:browser",
21
+ "test": "npm run lint && npm run test:node && npm run test:esm && npm run test:browser:esm",
22
+ "test:ci": "npm run lint && npm run test:node && npm run test:cjs && npm run test:esm && npm run test:browser",
21
23
  "coverage": "c8 --reporter=html mocha test/test-*.js && npx st -d coverage -p 8080"
22
24
  },
23
25
  "repository": {
@@ -30,14 +32,14 @@
30
32
  "author": "Rod <rod@vagg.org> (http://r.va.gg/)",
31
33
  "license": "Apache-2.0",
32
34
  "devDependencies": {
33
- "c8": "^7.6.0",
34
- "chai": "^4.3.3",
35
- "ipjs": "^5.0.0",
36
- "ipld-garbage": "^4.0.1",
37
- "mocha": "^9.0.0",
38
- "polendina": "^2.0.0",
39
- "standard": "^16.0.3",
40
- "typescript": "^4.2.4"
35
+ "c8": "^7.10.0",
36
+ "chai": "^4.3.4",
37
+ "ipjs": "^5.2.0",
38
+ "ipld-garbage": "^4.0.10",
39
+ "mocha": "^9.1.3",
40
+ "polendina": "~2.0.1",
41
+ "standard": "^16.0.4",
42
+ "typescript": "~4.5.3"
41
43
  },
42
44
  "exports": {
43
45
  ".": {