Dorian 0d073fa89e Add comprehensive installation and setup documentation
- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
2026-01-27 17:18:21 +00:00

312 lines
7.8 KiB
JavaScript

import { Type } from '../token.js'
import { encodeCustom } from '../encode.js'
import { encodeErrPrefix } from '../common.js'
import { asU8A, fromString } from '../byte-utils.js'
/**
* @typedef {import('../../interface').EncodeOptions} EncodeOptions
* @typedef {import('../token').Token} Token
* @typedef {import('../bl').Bl} Bl
*/
class JSONEncoder extends Array {
constructor () {
super()
/** @type {{type:Type,elements:number}[]} */
this.inRecursive = []
}
/**
* @param {Bl} buf
*/
prefix (buf) {
const recurs = this.inRecursive[this.inRecursive.length - 1]
if (recurs) {
if (recurs.type === Type.array) {
recurs.elements++
if (recurs.elements !== 1) { // >first
buf.push([44]) // ','
}
}
if (recurs.type === Type.map) {
recurs.elements++
if (recurs.elements !== 1) { // >first
if (recurs.elements % 2 === 1) { // key
buf.push([44]) // ','
} else {
buf.push([58]) // ':'
}
}
}
}
}
/**
* @param {Bl} buf
* @param {Token} token
*/
[Type.uint.major] (buf, token) {
this.prefix(buf)
const is = String(token.value)
const isa = []
for (let i = 0; i < is.length; i++) {
isa[i] = is.charCodeAt(i)
}
buf.push(isa)
}
/**
* @param {Bl} buf
* @param {Token} token
*/
[Type.negint.major] (buf, token) {
// @ts-ignore hack
this[Type.uint.major](buf, token)
}
/**
* @param {Bl} _buf
* @param {Token} _token
*/
[Type.bytes.major] (_buf, _token) {
throw new Error(`${encodeErrPrefix} unsupported type: Uint8Array`)
}
/**
* @param {Bl} buf
* @param {Token} token
*/
[Type.string.major] (buf, token) {
this.prefix(buf)
// buf.push(34) // '"'
// encodeUtf8(token.value, byts)
// buf.push(34) // '"'
const byts = fromString(JSON.stringify(token.value))
buf.push(byts.length > 32 ? asU8A(byts) : byts)
}
/**
* @param {Bl} buf
* @param {Token} _token
*/
[Type.array.major] (buf, _token) {
this.prefix(buf)
this.inRecursive.push({ type: Type.array, elements: 0 })
buf.push([91]) // '['
}
/**
* @param {Bl} buf
* @param {Token} _token
*/
[Type.map.major] (buf, _token) {
this.prefix(buf)
this.inRecursive.push({ type: Type.map, elements: 0 })
buf.push([123]) // '{'
}
/**
* @param {Bl} _buf
* @param {Token} _token
*/
[Type.tag.major] (_buf, _token) {}
/**
* @param {Bl} buf
* @param {Token} token
*/
[Type.float.major] (buf, token) {
if (token.type.name === 'break') {
const recurs = this.inRecursive.pop()
if (recurs) {
if (recurs.type === Type.array) {
buf.push([93]) // ']'
} else if (recurs.type === Type.map) {
buf.push([125]) // '}'
/* c8 ignore next 3 */
} else {
throw new Error('Unexpected recursive type; this should not happen!')
}
return
}
/* c8 ignore next 2 */
throw new Error('Unexpected break; this should not happen!')
}
if (token.value === undefined) {
throw new Error(`${encodeErrPrefix} unsupported type: undefined`)
}
this.prefix(buf)
if (token.type.name === 'true') {
buf.push([116, 114, 117, 101]) // 'true'
return
} else if (token.type.name === 'false') {
buf.push([102, 97, 108, 115, 101]) // 'false'
return
} else if (token.type.name === 'null') {
buf.push([110, 117, 108, 108]) // 'null'
return
}
// number
const is = String(token.value)
const isa = []
let dp = false
for (let i = 0; i < is.length; i++) {
isa[i] = is.charCodeAt(i)
if (!dp && (isa[i] === 46 || isa[i] === 101 || isa[i] === 69)) { // '[.eE]'
dp = true
}
}
if (!dp) { // need a decimal point for floats
isa.push(46) // '.'
isa.push(48) // '0'
}
buf.push(isa)
}
}
// The below code is mostly taken and modified from https://github.com/feross/buffer
// Licensed MIT. Copyright (c) Feross Aboukhadijeh
// function encodeUtf8 (string, byts) {
// let codePoint
// const length = string.length
// let leadSurrogate = null
// for (let i = 0; i < length; ++i) {
// codePoint = string.charCodeAt(i)
// // is surrogate component
// if (codePoint > 0xd7ff && codePoint < 0xe000) {
// // last char was a lead
// if (!leadSurrogate) {
// // no lead yet
// /* c8 ignore next 9 */
// if (codePoint > 0xdbff) {
// // unexpected trail
// byts.push(0xef, 0xbf, 0xbd)
// continue
// } else if (i + 1 === length) {
// // unpaired lead
// byts.push(0xef, 0xbf, 0xbd)
// continue
// }
// // valid lead
// leadSurrogate = codePoint
// continue
// }
// // 2 leads in a row
// /* c8 ignore next 5 */
// if (codePoint < 0xdc00) {
// byts.push(0xef, 0xbf, 0xbd)
// leadSurrogate = codePoint
// continue
// }
// // valid surrogate pair
// codePoint = (leadSurrogate - 0xd800 << 10 | codePoint - 0xdc00) + 0x10000
// /* c8 ignore next 4 */
// } else if (leadSurrogate) {
// // valid bmp char, but last char was a lead
// byts.push(0xef, 0xbf, 0xbd)
// }
// leadSurrogate = null
// // encode utf8
// if (codePoint < 0x80) {
// // special JSON escapes
// switch (codePoint) {
// case 8: // '\b'
// byts.push(92, 98) // '\\b'
// continue
// case 9: // '\t'
// byts.push(92, 116) // '\\t'
// continue
// case 10: // '\n'
// byts.push(92, 110) // '\\n'
// continue
// case 12: // '\f'
// byts.push(92, 102) // '\\f'
// continue
// case 13: // '\r'
// byts.push(92, 114) // '\\r'
// continue
// case 34: // '"'
// byts.push(92, 34) // '\\"'
// continue
// case 92: // '\\'
// byts.push(92, 92) // '\\\\'
// continue
// }
// byts.push(codePoint)
// } else if (codePoint < 0x800) {
// /* c8 ignore next 1 */
// byts.push(
// codePoint >> 0x6 | 0xc0,
// codePoint & 0x3f | 0x80
// )
// } else if (codePoint < 0x10000) {
// /* c8 ignore next 1 */
// byts.push(
// codePoint >> 0xc | 0xe0,
// codePoint >> 0x6 & 0x3f | 0x80,
// codePoint & 0x3f | 0x80
// )
// /* c8 ignore next 9 */
// } else if (codePoint < 0x110000) {
// byts.push(
// codePoint >> 0x12 | 0xf0,
// codePoint >> 0xc & 0x3f | 0x80,
// codePoint >> 0x6 & 0x3f | 0x80,
// codePoint & 0x3f | 0x80
// )
// } else {
// /* c8 ignore next 2 */
// throw new Error('Invalid code point')
// }
// }
// }
/**
* @param {(Token|Token[])[]} e1
* @param {(Token|Token[])[]} e2
* @returns {number}
*/
function mapSorter (e1, e2) {
if (Array.isArray(e1[0]) || Array.isArray(e2[0])) {
throw new Error(`${encodeErrPrefix} complex map keys are not supported`)
}
const keyToken1 = e1[0]
const keyToken2 = e2[0]
if (keyToken1.type !== Type.string || keyToken2.type !== Type.string) {
throw new Error(`${encodeErrPrefix} non-string map keys are not supported`)
}
if (keyToken1 < keyToken2) {
return -1
}
if (keyToken1 > keyToken2) {
return 1
}
/* c8 ignore next 1 */
throw new Error(`${encodeErrPrefix} unexpected duplicate map keys, this is not supported`)
}
const defaultEncodeOptions = { addBreakTokens: true, mapSorter }
/**
* @param {any} data
* @param {EncodeOptions} [options]
* @returns {Uint8Array}
*/
function encode (data, options) {
options = Object.assign({}, defaultEncodeOptions, options)
return encodeCustom(data, new JSONEncoder(), options)
}
export { encode }