'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var is = require('./is.js'); var token = require('./token.js'); var bl = require('./bl.js'); var common = require('./common.js'); var jump = require('./jump.js'); var byteUtils = require('./byte-utils.js'); var _0uint = require('./0uint.js'); var _1negint = require('./1negint.js'); var _2bytes = require('./2bytes.js'); var _3string = require('./3string.js'); var _4array = require('./4array.js'); var _5map = require('./5map.js'); var _6tag = require('./6tag.js'); var _7float = require('./7float.js'); const defaultEncodeOptions = { float64: false, mapSorter, quickEncodeToken: jump.quickEncodeToken }; function makeCborEncoders() { const encoders = []; encoders[token.Type.uint.major] = _0uint.encodeUint; encoders[token.Type.negint.major] = _1negint.encodeNegint; encoders[token.Type.bytes.major] = _2bytes.encodeBytes; encoders[token.Type.string.major] = _3string.encodeString; encoders[token.Type.array.major] = _4array.encodeArray; encoders[token.Type.map.major] = _5map.encodeMap; encoders[token.Type.tag.major] = _6tag.encodeTag; encoders[token.Type.float.major] = _7float.encodeFloat; return encoders; } const cborEncoders = makeCborEncoders(); const buf = new bl.Bl(); class Ref { constructor(obj, parent) { this.obj = obj; this.parent = parent; } includes(obj) { let p = this; do { if (p.obj === obj) { return true; } } while (p = p.parent); return false; } static createCheck(stack, obj) { if (stack && stack.includes(obj)) { throw new Error(`${ common.encodeErrPrefix } object contains circular references`); } return new Ref(obj, stack); } } const simpleTokens = { null: new token.Token(token.Type.null, null), undefined: new token.Token(token.Type.undefined, undefined), true: new token.Token(token.Type.true, true), false: new token.Token(token.Type.false, false), emptyArray: new token.Token(token.Type.array, 0), emptyMap: new token.Token(token.Type.map, 0) }; const typeEncoders = { number(obj, _typ, _options, _refStack) { if (!Number.isInteger(obj) || !Number.isSafeInteger(obj)) { return new token.Token(token.Type.float, obj); } else if (obj >= 0) { return new token.Token(token.Type.uint, obj); } else { return new token.Token(token.Type.negint, obj); } }, bigint(obj, _typ, _options, _refStack) { if (obj >= BigInt(0)) { return new token.Token(token.Type.uint, obj); } else { return new token.Token(token.Type.negint, obj); } }, Uint8Array(obj, _typ, _options, _refStack) { return new token.Token(token.Type.bytes, obj); }, string(obj, _typ, _options, _refStack) { return new token.Token(token.Type.string, obj); }, boolean(obj, _typ, _options, _refStack) { return obj ? simpleTokens.true : simpleTokens.false; }, null(_obj, _typ, _options, _refStack) { return simpleTokens.null; }, undefined(_obj, _typ, _options, _refStack) { return simpleTokens.undefined; }, ArrayBuffer(obj, _typ, _options, _refStack) { return new token.Token(token.Type.bytes, new Uint8Array(obj)); }, DataView(obj, _typ, _options, _refStack) { return new token.Token(token.Type.bytes, new Uint8Array(obj.buffer, obj.byteOffset, obj.byteLength)); }, Array(obj, _typ, options, refStack) { if (!obj.length) { if (options.addBreakTokens === true) { return [ simpleTokens.emptyArray, new token.Token(token.Type.break) ]; } return simpleTokens.emptyArray; } refStack = Ref.createCheck(refStack, obj); const entries = []; let i = 0; for (const e of obj) { entries[i++] = objectToTokens(e, options, refStack); } if (options.addBreakTokens) { return [ new token.Token(token.Type.array, obj.length), entries, new token.Token(token.Type.break) ]; } return [ new token.Token(token.Type.array, obj.length), entries ]; }, Object(obj, typ, options, refStack) { const isMap = typ !== 'Object'; const keys = isMap ? obj.keys() : Object.keys(obj); const length = isMap ? obj.size : keys.length; if (!length) { if (options.addBreakTokens === true) { return [ simpleTokens.emptyMap, new token.Token(token.Type.break) ]; } return simpleTokens.emptyMap; } refStack = Ref.createCheck(refStack, obj); const entries = []; let i = 0; for (const key of keys) { entries[i++] = [ objectToTokens(key, options, refStack), objectToTokens(isMap ? obj.get(key) : obj[key], options, refStack) ]; } sortMapEntries(entries, options); if (options.addBreakTokens) { return [ new token.Token(token.Type.map, length), entries, new token.Token(token.Type.break) ]; } return [ new token.Token(token.Type.map, length), entries ]; } }; typeEncoders.Map = typeEncoders.Object; typeEncoders.Buffer = typeEncoders.Uint8Array; for (const typ of 'Uint8Clamped Uint16 Uint32 Int8 Int16 Int32 BigUint64 BigInt64 Float32 Float64'.split(' ')) { typeEncoders[`${ typ }Array`] = typeEncoders.DataView; } function objectToTokens(obj, options = {}, refStack) { const typ = is.is(obj); const customTypeEncoder = options && options.typeEncoders && options.typeEncoders[typ] || typeEncoders[typ]; if (typeof customTypeEncoder === 'function') { const tokens = customTypeEncoder(obj, typ, options, refStack); if (tokens != null) { return tokens; } } const typeEncoder = typeEncoders[typ]; if (!typeEncoder) { throw new Error(`${ common.encodeErrPrefix } unsupported type: ${ typ }`); } return typeEncoder(obj, typ, options, refStack); } function sortMapEntries(entries, options) { if (options.mapSorter) { entries.sort(options.mapSorter); } } function mapSorter(e1, e2) { const keyToken1 = Array.isArray(e1[0]) ? e1[0][0] : e1[0]; const keyToken2 = Array.isArray(e2[0]) ? e2[0][0] : e2[0]; if (keyToken1.type !== keyToken2.type) { return keyToken1.type.compare(keyToken2.type); } const major = keyToken1.type.major; const tcmp = cborEncoders[major].compareTokens(keyToken1, keyToken2); if (tcmp === 0) { console.warn('WARNING: complex key types used, CBOR key sorting guarantees are gone'); } return tcmp; } function tokensToEncoded(buf, tokens, encoders, options) { if (Array.isArray(tokens)) { for (const token of tokens) { tokensToEncoded(buf, token, encoders, options); } } else { encoders[tokens.type.major](buf, tokens, options); } } function encodeCustom(data, encoders, options) { const tokens = objectToTokens(data, options); if (!Array.isArray(tokens) && options.quickEncodeToken) { const quickBytes = options.quickEncodeToken(tokens); if (quickBytes) { return quickBytes; } const encoder = encoders[tokens.type.major]; if (encoder.encodedSize) { const size = encoder.encodedSize(tokens, options); const buf = new bl.Bl(size); encoder(buf, tokens, options); if (buf.chunks.length !== 1) { throw new Error(`Unexpected error: pre-calculated length for ${ tokens } was wrong`); } return byteUtils.asU8A(buf.chunks[0]); } } buf.reset(); tokensToEncoded(buf, tokens, encoders, options); return buf.toBytes(true); } function encode(data, options) { options = Object.assign({}, defaultEncodeOptions, options); return encodeCustom(data, cborEncoders, options); } exports.Ref = Ref; exports.encode = encode; exports.encodeCustom = encodeCustom; exports.makeCborEncoders = makeCborEncoders; exports.objectToTokens = objectToTokens;