Comparing version 7.0.6 to 8.0.0
'use strict' | ||
exports.BigNumber = require('./constants').BigNumber | ||
exports.Commented = require('./commented') | ||
@@ -16,2 +15,3 @@ exports.Diagnose = require('./diagnose') | ||
exports.comment = exports.Commented.comment | ||
/** | ||
@@ -21,2 +21,3 @@ * Convenience name for {@linkcode Decoder.decodeAll} | ||
exports.decodeAll = exports.Decoder.decodeAll | ||
/** | ||
@@ -26,2 +27,3 @@ * Convenience name for {@linkcode Decoder.decodeFirst} | ||
exports.decodeFirst = exports.Decoder.decodeFirst | ||
/** | ||
@@ -31,2 +33,3 @@ * Convenience name for {@linkcode Decoder.decodeAllSync} | ||
exports.decodeAllSync = exports.Decoder.decodeAllSync | ||
/** | ||
@@ -36,2 +39,3 @@ * Convenience name for {@linkcode Decoder.decodeFirstSync} | ||
exports.decodeFirstSync = exports.Decoder.decodeFirstSync | ||
/** | ||
@@ -41,2 +45,3 @@ * Convenience name for {@linkcode Diagnose.diagnose} | ||
exports.diagnose = exports.Diagnose.diagnose | ||
/** | ||
@@ -46,2 +51,3 @@ * Convenience name for {@linkcode Encoder.encode} | ||
exports.encode = exports.Encoder.encode | ||
/** | ||
@@ -51,2 +57,3 @@ * Convenience name for {@linkcode Encoder.encodeCanonical} | ||
exports.encodeCanonical = exports.Encoder.encodeCanonical | ||
/** | ||
@@ -56,2 +63,3 @@ * Convenience name for {@linkcode Encoder.encodeOne} | ||
exports.encodeOne = exports.Encoder.encodeOne | ||
/** | ||
@@ -61,2 +69,3 @@ * Convenience name for {@linkcode Encoder.encodeAsync} | ||
exports.encodeAsync = exports.Encoder.encodeAsync | ||
/** | ||
@@ -90,11 +99,13 @@ * Convenience name for {@linkcode Decoder.decodeFirstSync} | ||
buffer: true, | ||
name: 'cbor' | ||
name: 'cbor', | ||
} | ||
/** | ||
* Does this library and runtime support BigInts? Only exported for backward | ||
* compatibility. | ||
* | ||
* @deprecated since version 6.0 | ||
* Reset everything that we can predict a plugin might have altered in good | ||
* faith. For now that includes the default set of tags that decoding and | ||
* encoding will use. | ||
*/ | ||
exports.hasBigInt = true | ||
exports.reset = function reset() { | ||
exports.Encoder.reset() | ||
exports.Tagged.reset() | ||
} |
@@ -30,4 +30,2 @@ 'use strict' | ||
* function returns the correctly-created value for that tag. | ||
* @property {boolean} [bigint=true] generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
* @property {boolean} [preferWeb=false] if true, prefer Uint8Arrays to | ||
@@ -43,2 +41,3 @@ * be generated instead of node Buffers. This might turn on some more | ||
* @param {string} [commented] - the comment string | ||
* @returns {void} | ||
*/ | ||
@@ -85,8 +84,7 @@ /** | ||
no_summary = false, | ||
// decoder options | ||
// Decoder options | ||
tags = {}, | ||
bigint, | ||
preferWeb, | ||
encoding, | ||
// stream.Transform options | ||
// Stream.Transform options | ||
...superOpts | ||
@@ -98,3 +96,3 @@ } = options | ||
readableObjectMode: false, | ||
writableObjectMode: false | ||
writableObjectMode: false, | ||
}) | ||
@@ -112,5 +110,4 @@ | ||
max_depth, | ||
bigint, | ||
preferWeb, | ||
encoding | ||
encoding, | ||
}) | ||
@@ -250,3 +247,3 @@ this.parser.on('value', this._on_value.bind(this)) | ||
} | ||
return this.push(desc + ' next ' + len + ' byte' + (plural(len)) + '\n') | ||
return this.push(`${desc} next ${len} byte${plural(len)}\n`) | ||
} | ||
@@ -263,9 +260,9 @@ | ||
case MT.BYTE_STRING: | ||
desc = 'Bytes, length: ' + tag | ||
desc = `Bytes, length: ${tag}` | ||
break | ||
case MT.UTF8_STRING: | ||
desc = 'String, length: ' + (tag.toString()) | ||
desc = `String, length: ${tag.toString()}` | ||
break | ||
} | ||
return this.push(desc + '\n') | ||
return this.push(`${desc}\n`) | ||
} | ||
@@ -272,0 +269,0 @@ |
'use strict' | ||
// Let's get consistent first, then we can think about feature testing | ||
// for BigNumber support | ||
let bn = null | ||
try { | ||
bn = require('bignumber.js').BigNumber | ||
} catch (ignored) { | ||
// bignumber.js isn't available | ||
} | ||
/** @type {typeof import('bignumber.js').BigNumber?} */ | ||
exports.BigNumber = bn | ||
/** | ||
@@ -25,3 +14,3 @@ * @enum {number} | ||
TAG: 6, | ||
SIMPLE_FLOAT: 7 | ||
SIMPLE_FLOAT: 7, | ||
} | ||
@@ -49,3 +38,3 @@ | ||
// https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md | ||
SET: 258 | ||
SET: 258, | ||
} | ||
@@ -62,3 +51,3 @@ | ||
EIGHT: 27, | ||
INDEFINITE: 31 | ||
INDEFINITE: 31, | ||
} | ||
@@ -73,3 +62,3 @@ | ||
NULL: 22, | ||
UNDEFINED: 23 | ||
UNDEFINED: 23, | ||
} | ||
@@ -82,3 +71,3 @@ | ||
BREAK: Symbol.for('github.com/hildjj/node-cbor/break'), | ||
STREAM: Symbol.for('github.com/hildjj/node-cbor/stream') | ||
STREAM: Symbol.for('github.com/hildjj/node-cbor/stream'), | ||
} | ||
@@ -93,18 +82,4 @@ | ||
MAXINT64: BigInt('0xffffffffffffffff'), | ||
SHIFT32: BigInt(exports.SHIFT32) | ||
SHIFT32: BigInt(exports.SHIFT32), | ||
} | ||
if (exports.BigNumber) { | ||
const MINUS_ONE = new exports.BigNumber(-1) | ||
exports.BN = { | ||
MINUS_ONE, | ||
NEG_MAX: MINUS_ONE.minus( | ||
new exports.BigNumber(Number.MAX_SAFE_INTEGER.toString(16), 16) | ||
), | ||
TWO: new exports.BigNumber(2), | ||
MAXINT: new exports.BigNumber('0x20000000000000'), | ||
MAXINT32: new exports.BigNumber(0xffffffff), | ||
MAXINT64: new exports.BigNumber('0xffffffffffffffff'), | ||
SHIFT32: new exports.BigNumber(exports.SHIFT32) | ||
} | ||
} |
@@ -35,19 +35,2 @@ 'use strict' | ||
/** | ||
* @param {Buffer} v | ||
* @private | ||
*/ | ||
function _tag_2(v) { | ||
return utils.bufferToBigInt(v) | ||
} | ||
/** | ||
* @param {BigInt} v | ||
* @private | ||
*/ | ||
function _tag_3(v) { | ||
// avoid syntax error on old runtimes | ||
return BI.MINUS_ONE - utils.bufferToBigInt(v) | ||
} | ||
class UnexpectedDataError extends Error { | ||
@@ -80,7 +63,5 @@ constructor(byte, value) { | ||
* running out of memory. | ||
* @property {object} [tags] - mapping from tag number to function(v), | ||
* @property {Tagged.TagMap} [tags] - mapping from tag number to function(v), | ||
* where v is the decoded value that comes after the tag, and where the | ||
* function returns the correctly-created value for that tag. | ||
* @property {boolean} [bigint=true] generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
* @property {boolean} [preferWeb=false] if true, prefer Uint8Arrays to | ||
@@ -101,2 +82,3 @@ * be generated instead of node Buffers. This might turn on some more | ||
* @param {any} [value] - the decoded value | ||
* @returns {void} | ||
*/ | ||
@@ -141,3 +123,2 @@ /** | ||
max_depth = -1, | ||
bigint = true, | ||
preferWeb = false, | ||
@@ -157,3 +138,2 @@ required = false, | ||
this.extendedResults = extendedResults | ||
this.bigint = bigint | ||
this.required = required | ||
@@ -163,12 +143,4 @@ | ||
this.bs.on('read', this._onRead.bind(this)) | ||
this.valueBytes = new NoFilter() | ||
this.valueBytes = /** @type {NoFilter} */ (new NoFilter()) | ||
} | ||
if (bigint) { | ||
if (this.tags[2] == null) { | ||
this.tags[2] = _tag_2 | ||
} | ||
if (this.tags[3] == null) { | ||
this.tags[3] = _tag_3 | ||
} | ||
} | ||
} | ||
@@ -214,3 +186,3 @@ | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input - If a Readable stream, must have | ||
* |DataView|ReadableStream} input - If a Readable stream, must have | ||
* received the `readable` event already, or you will get an error | ||
@@ -230,3 +202,3 @@ * claiming "Insufficient data" | ||
// for/of doesn't work when you need to call next() with a value | ||
// For/of doesn't work when you need to call next() with a value | ||
// generator created by parser will be "done" after each CBOR entity | ||
@@ -250,3 +222,6 @@ // parser will yield numbers of bytes that it wants | ||
let val = null | ||
if (!c.extendedResults) { | ||
if (c.extendedResults) { | ||
val = state.value | ||
val.unused = s.read() | ||
} else { | ||
val = Decoder.nullcheck(state.value) | ||
@@ -259,5 +234,2 @@ if (s.length > 0) { | ||
} | ||
} else { | ||
val = state.value | ||
val.unused = s.read() | ||
} | ||
@@ -274,3 +246,3 @@ return val | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|string} [options={}] Options or encoding | ||
@@ -319,3 +291,3 @@ * for input | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|decodeCallback|string} [options={}] - options, the | ||
@@ -334,4 +306,3 @@ * callback, or input encoding | ||
const c = new Decoder(opts) | ||
/** @type {any} */ | ||
let v = NOT_FOUND | ||
let v = /** @type {any} */ (NOT_FOUND) | ||
const s = utils.guessEncoding(input, encoding) | ||
@@ -349,2 +320,4 @@ const p = new Promise((resolve, reject) => { | ||
if (v !== NOT_FOUND) { | ||
// Typescript work-around | ||
// eslint-disable-next-line dot-notation | ||
er['value'] = v | ||
@@ -393,3 +366,3 @@ } | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|decodeAllCallback|string} [options={}] - | ||
@@ -451,3 +424,3 @@ * Decoding options, the callback, or the input encoding. | ||
if ((this.max_depth >= 0) && (depth > this.max_depth)) { | ||
throw new Error('Maximum depth ' + this.max_depth + ' exceeded') | ||
throw new Error(`Maximum depth ${this.max_depth} exceeded`) | ||
} | ||
@@ -462,4 +435,4 @@ | ||
const ai = octet & 0x1f | ||
const parent_major = (parent != null) ? parent[MAJOR] : undefined | ||
const parent_length = (parent != null) ? parent.length : undefined | ||
const parent_major = (parent == null) ? undefined : parent[MAJOR] | ||
const parent_length = (parent == null) ? undefined : parent.length | ||
@@ -480,3 +453,3 @@ switch (ai) { | ||
buf : | ||
utils.parseCBORint(ai, buf, this.bigint) | ||
utils.parseCBORint(ai, buf) | ||
break | ||
@@ -488,3 +461,3 @@ } | ||
this.running = false | ||
throw new Error('Additional info not implemented: ' + ai) | ||
throw new Error(`Additional info not implemented: ${ai}`) | ||
case NUMBYTES.INDEFINITE: | ||
@@ -504,16 +477,7 @@ switch (mt) { | ||
case MT.POS_INT: | ||
// val already decoded | ||
// Val already decoded | ||
break | ||
case MT.NEG_INT: | ||
if (val === Number.MAX_SAFE_INTEGER) { | ||
if (this.bigint) { | ||
val = BI.NEG_MAX | ||
} else if (constants.BigNumber) { | ||
val = constants.BN.NEG_MAX | ||
} else { | ||
throw new Error('No bigint and no bignumber.js') | ||
} | ||
} else if (constants.BigNumber && | ||
(val instanceof constants.BigNumber)) { | ||
val = constants.BN.MINUS_ONE.minus(val) | ||
val = BI.NEG_MAX | ||
} else { | ||
@@ -626,3 +590,3 @@ val = (typeof val === 'bigint') ? BI.MINUS_ONE - val : -1 - val | ||
if ((parent.length % 2) !== 0) { | ||
throw new Error('Invalid map length: ' + parent.length) | ||
throw new Error(`Invalid map length: ${parent.length}`) | ||
} | ||
@@ -657,3 +621,3 @@ for (let i = 0, len = parent.length; i < len; i += 2) { | ||
} else /* istanbul ignore else */ if (parent instanceof NoFilter) { | ||
// only parent types are Array and NoFilter for (Array/Map) and | ||
// Only parent types are Array and NoFilter for (Array/Map) and | ||
// (bytes/string) respectively. | ||
@@ -664,3 +628,7 @@ switch (parent[MAJOR]) { | ||
if (this.preferWeb) { | ||
val = new Uint8Array(val.buffer, val.byteOffset, val.length) | ||
val = new Uint8Array( | ||
/** @type {Buffer} */ (val).buffer, | ||
/** @type {Buffer} */ (val).byteOffset, | ||
/** @type {Buffer} */ (val).length | ||
) | ||
} | ||
@@ -686,3 +654,3 @@ break | ||
bytes, | ||
length: bytes.length | ||
length: bytes.length, | ||
} | ||
@@ -689,0 +657,0 @@ |
@@ -25,4 +25,2 @@ 'use strict' | ||
* function returns the correctly-created value for that tag. | ||
* @property {boolean} [bigint=true] generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
* @property {boolean} [preferWeb=false] - if true, prefer Uint8Arrays to | ||
@@ -38,2 +36,3 @@ * be generated instead of node Buffers. This might turn on some more | ||
* @param {string} [value] - the diagnostic value | ||
* @returns {void} | ||
*/ | ||
@@ -75,9 +74,8 @@ /** | ||
stream_errors = false, | ||
// decoder options | ||
// Decoder options | ||
tags, | ||
max_depth, | ||
bigint, | ||
preferWeb, | ||
encoding, | ||
// stream.Transform options | ||
// Stream.Transform options | ||
...superOpts | ||
@@ -88,3 +86,3 @@ } = options | ||
readableObjectMode: false, | ||
writableObjectMode: false | ||
writableObjectMode: false, | ||
}) | ||
@@ -98,5 +96,4 @@ | ||
max_depth, | ||
bigint, | ||
preferWeb, | ||
encoding | ||
encoding, | ||
}) | ||
@@ -161,2 +158,3 @@ this.parser.on('more-bytes', this._on_more.bind(this)) | ||
/** @private */ | ||
_on_error(er) { | ||
@@ -169,2 +167,3 @@ if (this.stream_errors) { | ||
/** @private */ | ||
_on_more(mt, len, parent_mt, pos) { | ||
@@ -175,3 +174,3 @@ if (mt === MT.SIMPLE_FLOAT) { | ||
4: 2, | ||
8: 3 | ||
8: 3, | ||
}[len] | ||
@@ -181,2 +180,3 @@ } | ||
/** @private */ | ||
_fore(parent_mt, pos) { | ||
@@ -202,2 +202,3 @@ switch (parent_mt) { | ||
/** @private */ | ||
_on_value(val, parent_mt, pos) { | ||
@@ -213,2 +214,3 @@ if (val === SYMS.BREAK) { | ||
/** @private */ | ||
_on_start(mt, tag, parent_mt, pos) { | ||
@@ -236,2 +238,3 @@ this._fore(parent_mt, pos) | ||
/** @private */ | ||
_on_stop(mt) { | ||
@@ -255,2 +258,3 @@ switch (mt) { | ||
/** @private */ | ||
_on_data() { | ||
@@ -257,0 +261,0 @@ this.push(this.separator) |
@@ -8,3 +8,3 @@ 'use strict' | ||
const { | ||
MT, NUMBYTES, SHIFT32, SIMPLE, SYMS, TAG, BI | ||
MT, NUMBYTES, SHIFT32, SIMPLE, SYMS, TAG, BI, | ||
} = constants | ||
@@ -28,2 +28,30 @@ const { Buffer } = require('buffer') | ||
/** | ||
* Generate the CBOR for a value. If you are using this, you'll either need | ||
* to call {@link Encoder.write} with a Buffer, or look into the internals of | ||
* Encoder to reuse existing non-documented behavior. | ||
* | ||
* @callback EncodeFunction | ||
* @param {Encoder} enc - the encoder to use | ||
* @param {any} val - the value to encode | ||
* @return {boolean} - true on success | ||
*/ | ||
/** | ||
* A mapping from tag number to a tag decoding function | ||
* @typedef {Object.<string, EncodeFunction>} SemanticMap | ||
*/ | ||
/** | ||
* @type {SemanticMap} | ||
* @private | ||
*/ | ||
const SEMANTIC_TYPES = {} | ||
/** | ||
* @type {SemanticMap} | ||
* @private | ||
*/ | ||
let current_SEMANTIC_TYPES = {} | ||
/** | ||
* @param {string} str | ||
@@ -38,3 +66,2 @@ * @returns {"number"|"float"|"int"|"string"} | ||
switch (str.toLowerCase()) { | ||
// yes, return str would have made more sense, but tsc is pedantic | ||
case 'number': | ||
@@ -45,2 +72,3 @@ return 'number' | ||
case 'int': | ||
case 'integer': | ||
return 'int' | ||
@@ -57,3 +85,3 @@ case 'string': | ||
* `type`, `function(Encoder)` for semantic types to be encoded. Not | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, URL, or BigNumber. | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, or URL. | ||
* If an object, the keys are the constructor names for the types. | ||
@@ -85,3 +113,3 @@ * @property {boolean} [canonical=false] - should the output be | ||
* @property {boolean} [collapseBigIntegers=false] - Should integers | ||
* that come in as BigNumber integers and ECMAscript bigint's be encoded | ||
* that come in as ECMAscript bigint's be encoded | ||
* as normal CBOR integers if they fit, discarding type information? | ||
@@ -123,3 +151,3 @@ * @property {number} [chunkSize=4096] - Number of characters or bytes | ||
readableObjectMode: false, | ||
writableObjectMode: true | ||
writableObjectMode: true, | ||
}) | ||
@@ -132,3 +160,5 @@ | ||
this.collapseBigIntegers = this.canonical ? true : collapseBigIntegers | ||
this.detectLoops = detectLoops | ||
/** @type WeakSet<any>? */ | ||
this.detectLoops = undefined | ||
if (typeof detectLoops === 'boolean') { | ||
@@ -138,3 +168,5 @@ if (detectLoops) { | ||
} | ||
} else if (!(detectLoops instanceof WeakSet)) { | ||
} else if (detectLoops instanceof WeakSet) { | ||
this.detectLoops = detectLoops | ||
} else { | ||
throw new TypeError('detectLoops must be boolean or WeakSet') | ||
@@ -144,37 +176,3 @@ } | ||
this.semanticTypes = { | ||
Array: this._pushArray, | ||
Date: this._pushDate, | ||
Buffer: this._pushBuffer, | ||
[Buffer.name]: this._pushBuffer, // might be mangled | ||
Map: this._pushMap, | ||
NoFilter: this._pushNoFilter, | ||
[NoFilter.name]: this._pushNoFilter, // might be mangled | ||
RegExp: this._pushRegexp, | ||
Set: this._pushSet, | ||
ArrayBuffer: this._pushArrayBuffer, | ||
Uint8ClampedArray: this._pushTypedArray, | ||
Uint8Array: this._pushTypedArray, | ||
Uint16Array: this._pushTypedArray, | ||
Uint32Array: this._pushTypedArray, | ||
Int8Array: this._pushTypedArray, | ||
Int16Array: this._pushTypedArray, | ||
Int32Array: this._pushTypedArray, | ||
Float32Array: this._pushTypedArray, | ||
Float64Array: this._pushTypedArray, | ||
URL: this._pushURL, | ||
Boolean: this._pushBoxed, | ||
Number: this._pushBoxed, | ||
String: this._pushBoxed | ||
} | ||
if (constants.BigNumber) { | ||
this.semanticTypes[constants.BigNumber.name] = this._pushBigNumber | ||
} | ||
// Safari needs to get better. | ||
if (typeof BigUint64Array !== 'undefined') { | ||
this.semanticTypes[BigUint64Array.name] = this._pushTypedArray | ||
} | ||
if (typeof BigInt64Array !== 'undefined') { | ||
this.semanticTypes[BigInt64Array.name] = this._pushTypedArray | ||
} | ||
this.semanticTypes = {...Encoder.SEMANTIC_TYPES} | ||
@@ -198,3 +196,2 @@ if (Array.isArray(genTypes)) { | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
@@ -206,31 +203,6 @@ _flush(cb) { | ||
/** | ||
* @callback encodeFunction | ||
* @param {Encoder} encoder - the encoder to serialize into. Call "write" | ||
* on the encoder as needed. | ||
* @return {bool} - true on success, else false | ||
* @param {number} val - Number(0-255) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
/** | ||
* Add an encoding function to the list of supported semantic types. This is | ||
* useful for objects for which you can't add an encodeCBOR method | ||
* | ||
* @param {any} type | ||
* @param {any} fun | ||
* @returns {encodeFunction} | ||
*/ | ||
addSemanticType(type, fun) { | ||
const typeName = (typeof type === 'string') ? type : type.name | ||
const old = this.semanticTypes[typeName] | ||
if (fun) { | ||
if (typeof fun !== 'function') { | ||
throw new TypeError('fun must be of type function') | ||
} | ||
this.semanticTypes[typeName] = fun | ||
} else if (old) { | ||
delete this.semanticTypes[typeName] | ||
} | ||
return old | ||
} | ||
_pushUInt8(val) { | ||
@@ -242,2 +214,7 @@ const b = Buffer.allocUnsafe(1) | ||
/** | ||
* @param {number} val - Number(0-65535) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUInt16BE(val) { | ||
@@ -249,2 +226,7 @@ const b = Buffer.allocUnsafe(2) | ||
/** | ||
* @param {number} val - Number(0..2**32-1) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUInt32BE(val) { | ||
@@ -256,2 +238,7 @@ const b = Buffer.allocUnsafe(4) | ||
/** | ||
* @param {number} val - Number to encode as 4-byte float | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushFloatBE(val) { | ||
@@ -263,2 +250,7 @@ const b = Buffer.allocUnsafe(4) | ||
/** | ||
* @param {number} val - Number to encode as 8-byte double | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushDoubleBE(val) { | ||
@@ -270,2 +262,6 @@ const b = Buffer.allocUnsafe(8) | ||
/** | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNaN() { | ||
@@ -275,2 +271,7 @@ return this.push(BUF_NAN) | ||
/** | ||
* @param {number} obj - Positive or negative infinity | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushInfinity(obj) { | ||
@@ -281,2 +282,10 @@ const half = (obj < 0) ? BUF_INF_NEG : BUF_INF_POS | ||
/** | ||
* Choose the best float representation for a number and encode it. | ||
* | ||
* @param {number} obj - A number that is known to be not-integer, but not | ||
* how many bytes of precision it needs | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushFloat(obj) { | ||
@@ -310,2 +319,18 @@ if (this.canonical) { | ||
/** | ||
* Choose the best integer representation for a postive number and encode | ||
* it. If the number is over MAX_SAFE_INTEGER, fall back on float (but I | ||
* don't remember why). | ||
* | ||
* @param {number} obj - A positive number that is known to be an integer, | ||
* but not how many bytes of precision it needs | ||
* @param {number} mt - The Major Type number to combine with the integer. | ||
* Not yet shifted. | ||
* @param {number} [orig] - The number before it was transformed to positive. | ||
* If the mt is NEG_INT, and the positive number is over MAX_SAFE_INT, | ||
* then we'll encode this as a float rather than making the number | ||
* negative again and losing precision. | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushInt(obj, mt, orig) { | ||
@@ -334,2 +359,10 @@ const m = mt << 5 | ||
/** | ||
* Choose the best integer representation for a number and encode it. | ||
* | ||
* @param {number} obj - A number that is known to be an integer, | ||
* but not how many bytes of precision it needs | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushIntNum(obj) { | ||
@@ -346,2 +379,7 @@ if (Object.is(obj, -0)) { | ||
/** | ||
* @param {number} obj - plain JS number to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNumber(obj) { | ||
@@ -360,2 +398,7 @@ switch (false) { | ||
/** | ||
* @param {string} obj - string to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushString(obj) { | ||
@@ -366,2 +409,7 @@ const len = Buffer.byteLength(obj, 'utf8') | ||
/** | ||
* @param {boolean} obj - bool to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushBoolean(obj) { | ||
@@ -371,2 +419,7 @@ return this._pushUInt8(obj ? TRUE : FALSE) | ||
/** | ||
* @param {undefined} obj - ignored | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUndefined(obj) { | ||
@@ -377,3 +430,3 @@ switch (typeof this.encodeUndefined) { | ||
case 'function': | ||
return this.pushAny(this.encodeUndefined.call(this, obj)) | ||
return this.pushAny(this.encodeUndefined(obj)) | ||
case 'object': { | ||
@@ -389,2 +442,7 @@ const buf = utils.bufferishToBuffer(this.encodeUndefined) | ||
/** | ||
* @param {null} obj - ignored | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNull(obj) { | ||
@@ -394,9 +452,221 @@ return this._pushUInt8(NULL) | ||
// TODO: make this static, and not-private | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushArray(gen, obj, opts) { | ||
/** | ||
* @param {number} tag - Tag number to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushTag(tag) { | ||
return this._pushInt(tag, MT.TAG) | ||
} | ||
/** | ||
* @param {bigint} obj - BigInt to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushJSBigint(obj) { | ||
let m = MT.POS_INT | ||
let tag = TAG.POS_BIGINT | ||
// BigInt doesn't have -0 | ||
if (obj < 0) { | ||
obj = -obj + BI.MINUS_ONE | ||
m = MT.NEG_INT | ||
tag = TAG.NEG_BIGINT | ||
} | ||
if (this.collapseBigIntegers && | ||
(obj <= BI.MAXINT64)) { | ||
// Special handiling for 64bits | ||
if (obj <= 0xffffffff) { | ||
return this._pushInt(Number(obj), m) | ||
} | ||
return this._pushUInt8((m << 5) | NUMBYTES.EIGHT) && | ||
this._pushUInt32BE(Number(obj / BI.SHIFT32)) && | ||
this._pushUInt32BE(Number(obj % BI.SHIFT32)) | ||
} | ||
let str = obj.toString(16) | ||
if (str.length % 2) { | ||
str = `0${str}` | ||
} | ||
const buf = Buffer.from(str, 'hex') | ||
return this._pushTag(tag) && Encoder._pushBuffer(this, buf) | ||
} | ||
/** | ||
* @param {object} obj - object to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushObject(obj, opts) { | ||
if (!obj) { | ||
return this._pushNull(obj) | ||
} | ||
opts = { | ||
indefinite: false, | ||
...opts | ||
skipTypes: false, | ||
...opts, | ||
} | ||
if (!opts.indefinite) { | ||
// This will only happen the first time through for indefinite encoding | ||
if (this.detectLoops) { | ||
if (this.detectLoops.has(obj)) { | ||
throw new Error(`\ | ||
Loop detected while CBOR encoding. | ||
Call removeLoopDetectors before resuming.`) | ||
} else { | ||
this.detectLoops.add(obj) | ||
} | ||
} | ||
} | ||
if (!opts.skipTypes) { | ||
const f = obj.encodeCBOR | ||
if (typeof f === 'function') { | ||
return f.call(obj, this) | ||
} | ||
const converter = this.semanticTypes[obj.constructor.name] | ||
if (converter) { | ||
return converter.call(obj, this, obj) | ||
} | ||
} | ||
const keys = Object.keys(obj).filter(k => { | ||
const tv = typeof obj[k] | ||
return (tv !== 'function') && | ||
(!this.omitUndefinedProperties || (tv !== 'undefined')) | ||
}) | ||
const cbor_keys = {} | ||
if (this.canonical) { | ||
// Note: this can't be a normal sort, because 'b' needs to sort before | ||
// 'aa' | ||
keys.sort((a, b) => { | ||
// Always strings, so don't bother to pass options. | ||
// hold on to the cbor versions, since there's no need | ||
// to encode more than once | ||
const a_cbor = cbor_keys[a] || (cbor_keys[a] = Encoder.encode(a)) | ||
const b_cbor = cbor_keys[b] || (cbor_keys[b] = Encoder.encode(b)) | ||
return a_cbor.compare(b_cbor) | ||
}) | ||
} | ||
if (opts.indefinite) { | ||
if (!this._pushUInt8((MT.MAP << 5) | NUMBYTES.INDEFINITE)) { | ||
return false | ||
} | ||
} else if (!this._pushInt(keys.length, MT.MAP)) { | ||
return false | ||
} | ||
let ck = null | ||
for (let j = 0, len2 = keys.length; j < len2; j++) { | ||
const k = keys[j] | ||
if (this.canonical && ((ck = cbor_keys[k]))) { | ||
if (!this.push(ck)) { // Already a Buffer | ||
return false | ||
} | ||
} else if (!this._pushString(k)) { | ||
return false | ||
} | ||
if (!this.pushAny(obj[k])) { | ||
return false | ||
} | ||
} | ||
if (opts.indefinite) { | ||
if (!this.push(BREAK)) { | ||
return false | ||
} | ||
} else if (this.detectLoops) { | ||
this.detectLoops.delete(obj) | ||
} | ||
return true | ||
} | ||
/** | ||
* @param {any[]} objs - Array of supported things | ||
* @returns {Buffer} Concatenation of encodings for the supported things | ||
* @ignore | ||
*/ | ||
_encodeAll(objs) { | ||
const bs = new NoFilter({ highWaterMark: this.readableHighWaterMark }) | ||
this.pipe(bs) | ||
for (const o of objs) { | ||
this.pushAny(o) | ||
} | ||
this.end() | ||
return bs.read() | ||
} | ||
/** | ||
* Add an encoding function to the list of supported semantic types. This | ||
* is useful for objects for which you can't add an encodeCBOR method | ||
* | ||
* @param {string|function} type - The type to encode | ||
* @param {EncodeFunction} fun - The encoder to use | ||
* @returns {EncodeFunction?} The previous encoder or undefined if there | ||
* wasn't one. | ||
*/ | ||
addSemanticType(type, fun) { | ||
const typeName = (typeof type === 'string') ? type : type.name | ||
const old = this.semanticTypes[typeName] | ||
if (fun) { | ||
if (typeof fun !== 'function') { | ||
throw new TypeError('fun must be of type function') | ||
} | ||
this.semanticTypes[typeName] = fun | ||
} else if (old) { | ||
delete this.semanticTypes[typeName] | ||
} | ||
return old | ||
} | ||
/** | ||
* Push any supported type onto the encoded stream | ||
* | ||
* @param {any} obj | ||
* @returns {boolean} true on success | ||
*/ | ||
pushAny(obj) { | ||
switch (typeof obj) { | ||
case 'number': | ||
return this._pushNumber(obj) | ||
case 'bigint': | ||
return this._pushJSBigint(obj) | ||
case 'string': | ||
return this._pushString(obj) | ||
case 'boolean': | ||
return this._pushBoolean(obj) | ||
case 'undefined': | ||
return this._pushUndefined(obj) | ||
case 'object': | ||
return this._pushObject(obj) | ||
case 'symbol': | ||
switch (obj) { | ||
case SYMS.NULL: | ||
return this._pushNull(null) | ||
case SYMS.UNDEFINED: | ||
return this._pushUndefined(undefined) | ||
// TODO: Add pluggable support for other symbols | ||
default: | ||
throw new Error(`Unknown symbol: ${obj.toString()}`) | ||
} | ||
default: | ||
throw new Error( | ||
`Unknown type: ${typeof obj}, ${(typeof obj.toString === 'function') ? obj.toString() : ''}` | ||
) | ||
} | ||
} | ||
/** | ||
* Encode an array and all of its elements. | ||
* | ||
* @param {Encoder} gen - Encoder to use | ||
* @param {any[]} obj - Array to encode | ||
* @param {Object} [opts] - options | ||
* @param {boolean} [opts.indefinite=false] - Use indefinite encoding? | ||
* @returns {boolean} true on success | ||
*/ | ||
static pushArray(gen, obj, opts) { | ||
opts = { | ||
indefinite: false, | ||
...opts, | ||
} | ||
const len = obj.length | ||
@@ -423,9 +693,22 @@ if (opts.indefinite) { | ||
_pushTag(tag) { | ||
return this._pushInt(tag, MT.TAG) | ||
/** | ||
* Remove the loop detector WeakSet for this Encoder. | ||
* | ||
* @returns {boolean} - true when the Encoder was reset, else false | ||
*/ | ||
removeLoopDetectors() { | ||
if (!this.detectLoops) { | ||
return false | ||
} | ||
this.detectLoops = new WeakSet() | ||
return true | ||
} | ||
// TODO: make this static, and consider not-private | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushDate(gen, obj) { | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Date} obj - Date to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushDate(gen, obj) { | ||
switch (gen.dateType) { | ||
@@ -436,39 +719,54 @@ case 'string': | ||
case 'int': | ||
case 'integer': | ||
return gen._pushTag(TAG.DATE_EPOCH) && | ||
gen._pushIntNum(Math.round(obj / 1000)) | ||
gen._pushIntNum(Math.round(obj.getTime() / 1000)) | ||
case 'float': | ||
// force float | ||
// Force float | ||
return gen._pushTag(TAG.DATE_EPOCH) && | ||
gen._pushFloat(obj / 1000) | ||
gen._pushFloat(obj.getTime() / 1000) | ||
case 'number': | ||
default: | ||
// if we happen to have an integral number of seconds, | ||
// If we happen to have an integral number of seconds, | ||
// use integer. Otherwise, use float. | ||
return gen._pushTag(TAG.DATE_EPOCH) && | ||
gen.pushAny(obj / 1000) | ||
gen.pushAny(obj.getTime() / 1000) | ||
} | ||
} | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushBuffer(gen, obj) { | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Buffer} obj - Buffer to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushBuffer(gen, obj) { | ||
return gen._pushInt(obj.length, MT.BYTE_STRING) && gen.push(obj) | ||
} | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushNoFilter(gen, obj) { | ||
return gen._pushBuffer(gen, obj.slice()) | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {NoFilter} obj - Buffer to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushNoFilter(gen, obj) { | ||
return Encoder._pushBuffer(gen, /** @type {Buffer} */ (obj.slice())) | ||
} | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushRegexp(gen, obj) { | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {RegExp} obj - RegExp to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushRegexp(gen, obj) { | ||
return gen._pushTag(TAG.REGEXP) && gen.pushAny(obj.source) | ||
} | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushSet(gen, obj) { | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Set} obj - Set to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushSet(gen, obj) { | ||
if (!gen._pushTag(TAG.SET)) { | ||
@@ -488,117 +786,32 @@ return false | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushURL(gen, obj) { | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {URL} obj - URL to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushURL(gen, obj) { | ||
return gen._pushTag(TAG.URI) && gen.pushAny(obj.toString()) | ||
} | ||
// TODO: make static? | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushBoxed(gen, obj) { | ||
return gen._pushAny(obj.valueOf()) | ||
} | ||
/** | ||
* @param {constants.BigNumber} obj | ||
* @private | ||
* @param {Encoder} gen - Encoder | ||
* @param {object} obj - Boxed String, Number, or Boolean object to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
_pushBigint(obj) { | ||
let m = MT.POS_INT | ||
let tag = TAG.POS_BIGINT | ||
if (obj.isNegative()) { | ||
obj = obj.negated().minus(1) | ||
m = MT.NEG_INT | ||
tag = TAG.NEG_BIGINT | ||
} | ||
if (this.collapseBigIntegers && | ||
obj.lte(constants.BN.MAXINT64)) { | ||
// special handiling for 64bits | ||
if (obj.lte(constants.BN.MAXINT32)) { | ||
return this._pushInt(obj.toNumber(), m) | ||
} | ||
return this._pushUInt8((m << 5) | NUMBYTES.EIGHT) && | ||
this._pushUInt32BE( | ||
obj.dividedToIntegerBy(constants.BN.SHIFT32).toNumber() | ||
) && | ||
this._pushUInt32BE( | ||
obj.mod(constants.BN.SHIFT32).toNumber() | ||
) | ||
} | ||
let str = obj.toString(16) | ||
if (str.length % 2) { | ||
str = '0' + str | ||
} | ||
const buf = Buffer.from(str, 'hex') | ||
return this._pushTag(tag) && this._pushBuffer(this, buf) | ||
static _pushBoxed(gen, obj) { | ||
return gen.pushAny(obj.valueOf()) | ||
} | ||
/** | ||
* @param {bigint} obj | ||
* @private | ||
* @param {Encoder} gen - Encoder | ||
* @param {Map} obj - Map to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
_pushJSBigint(obj) { | ||
let m = MT.POS_INT | ||
let tag = TAG.POS_BIGINT | ||
// BigInt doesn't have -0 | ||
if (obj < 0) { | ||
obj = -obj + BI.MINUS_ONE | ||
m = MT.NEG_INT | ||
tag = TAG.NEG_BIGINT | ||
} | ||
if (this.collapseBigIntegers && | ||
(obj <= BI.MAXINT64)) { | ||
// special handiling for 64bits | ||
if (obj <= 0xffffffff) { | ||
return this._pushInt(Number(obj), m) | ||
} | ||
return this._pushUInt8((m << 5) | NUMBYTES.EIGHT) && | ||
this._pushUInt32BE(Number(obj / BI.SHIFT32)) && | ||
this._pushUInt32BE(Number(obj % BI.SHIFT32)) | ||
} | ||
let str = obj.toString(16) | ||
if (str.length % 2) { | ||
str = '0' + str | ||
} | ||
const buf = Buffer.from(str, 'hex') | ||
return this._pushTag(tag) && this._pushBuffer(this, buf) | ||
} | ||
// TODO: make static | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushBigNumber(gen, obj) { | ||
if (obj.isNaN()) { | ||
return gen._pushNaN() | ||
} | ||
if (!obj.isFinite()) { | ||
return gen._pushInfinity(obj.isNegative() ? -Infinity : Infinity) | ||
} | ||
if (obj.isInteger()) { | ||
return gen._pushBigint(obj) | ||
} | ||
if (!(gen._pushTag(TAG.DECIMAL_FRAC) && | ||
gen._pushInt(2, MT.ARRAY))) { | ||
return false | ||
} | ||
const dec = obj.decimalPlaces() | ||
const slide = obj.shiftedBy(dec) | ||
if (!gen._pushIntNum(-dec)) { | ||
return false | ||
} | ||
if (slide.abs().isLessThan(constants.BN.MAXINT)) { | ||
return gen._pushIntNum(slide.toNumber()) | ||
} | ||
return gen._pushBigint(slide) | ||
} | ||
// TODO: make static | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushMap(gen, obj, opts) { | ||
static _pushMap(gen, obj, opts) { | ||
opts = { | ||
indefinite: false, | ||
...opts | ||
...opts, | ||
} | ||
@@ -616,6 +829,6 @@ let entries = [...obj.entries()] | ||
} | ||
// memoizing the cbor only helps in certain cases, and hurts in most | ||
// Memoizing the cbor only helps in certain cases, and hurts in most | ||
// others. Just avoid it. | ||
if (gen.canonical) { | ||
// keep the key/value pairs together, so we don't have to do odd | ||
// Keep the key/value pairs together, so we don't have to do odd | ||
// gets with object keys later | ||
@@ -625,6 +838,6 @@ const enc = new Encoder({ | ||
canonical: gen.canonical, | ||
detectLoops: !!gen.detectLoops, // give enc its own loop detector | ||
detectLoops: Boolean(gen.detectLoops), // Give enc its own loop detector | ||
dateType: gen.dateType, | ||
disallowUndefinedKeys: gen.disallowUndefinedKeys, | ||
collapseBigIntegers: gen.collapseBigIntegers | ||
collapseBigIntegers: gen.collapseBigIntegers, | ||
}) | ||
@@ -634,3 +847,3 @@ const bs = new NoFilter({highWaterMark: gen.readableHighWaterMark}) | ||
entries.sort(([a], [b]) => { | ||
// a, b are the keys | ||
// Both a and b are the keys | ||
enc.pushAny(a) | ||
@@ -668,6 +881,13 @@ const a_cbor = bs.read() | ||
// TODO: make static | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushTypedArray(gen, obj) { | ||
// see https://tools.ietf.org/html/rfc8746 | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param { Uint8Array|Uint16Array|Uint32Array| | ||
* Int8Array|Int16Array|Int32Array| | ||
* Float32Array|Float64Array| | ||
* BigUint64Array|BigInt64Array } obj - Array to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushTypedArray(gen, obj) { | ||
// See https://tools.ietf.org/html/rfc8746 | ||
@@ -691,3 +911,3 @@ let typ = 0b01000000 | ||
4: 0b10, | ||
8: 0b11 | ||
8: 0b11, | ||
}[sz] | ||
@@ -697,3 +917,3 @@ if (!gen._pushTag(typ)) { | ||
} | ||
return gen._pushBuffer( | ||
return Encoder._pushBuffer( | ||
gen, | ||
@@ -704,157 +924,13 @@ Buffer.from(obj.buffer, obj.byteOffset, obj.byteLength) | ||
// TODO: make static | ||
// eslint-disable-next-line class-methods-use-this | ||
_pushArrayBuffer(gen, obj) { | ||
return gen._pushBuffer(gen, Buffer.from(obj)) | ||
} | ||
/** | ||
* Remove the loop detector WeakSet for this Encoder. | ||
* | ||
* @returns {boolean} - true when the Encoder was reset, else false | ||
* @param {Encoder} gen - Encoder | ||
* @param { ArrayBuffer } obj - Array to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
removeLoopDetectors() { | ||
if (!this.detectLoops) { | ||
return false | ||
} | ||
this.detectLoops = new WeakSet() | ||
return true | ||
static _pushArrayBuffer(gen, obj) { | ||
return Encoder._pushBuffer(gen, Buffer.from(obj)) | ||
} | ||
_pushObject(obj, opts) { | ||
if (!obj) { | ||
return this._pushNull(obj) | ||
} | ||
opts = { | ||
indefinite: false, | ||
skipTypes: false, | ||
...opts | ||
} | ||
if (!opts.indefinite) { | ||
// this will only happen the first time through for indefinite encoding | ||
if (this.detectLoops) { | ||
if (this.detectLoops.has(obj)) { | ||
throw new Error(`\ | ||
Loop detected while CBOR encoding. | ||
Call removeLoopDetectors before resuming.`) | ||
} else { | ||
this.detectLoops.add(obj) | ||
} | ||
} | ||
} | ||
if (!opts.skipTypes) { | ||
const f = obj.encodeCBOR | ||
if (typeof f === 'function') { | ||
return f.call(obj, this) | ||
} | ||
const converter = this.semanticTypes[obj.constructor.name] | ||
if (converter) { | ||
return converter.call(obj, this, obj) | ||
} | ||
} | ||
const keys = Object.keys(obj).filter(k => { | ||
const tv = typeof obj[k] | ||
return (tv !== 'function') && | ||
(!this.omitUndefinedProperties || (tv !== 'undefined')) | ||
}) | ||
const cbor_keys = {} | ||
if (this.canonical) { | ||
// note: this can't be a normal sort, because 'b' needs to sort before | ||
// 'aa' | ||
keys.sort((a, b) => { | ||
// Always strings, so don't bother to pass options. | ||
// hold on to the cbor versions, since there's no need | ||
// to encode more than once | ||
const a_cbor = cbor_keys[a] || (cbor_keys[a] = Encoder.encode(a)) | ||
const b_cbor = cbor_keys[b] || (cbor_keys[b] = Encoder.encode(b)) | ||
return a_cbor.compare(b_cbor) | ||
}) | ||
} | ||
if (opts.indefinite) { | ||
if (!this._pushUInt8((MT.MAP << 5) | NUMBYTES.INDEFINITE)) { | ||
return false | ||
} | ||
} else if (!this._pushInt(keys.length, MT.MAP)) { | ||
return false | ||
} | ||
let ck = null | ||
for (let j = 0, len2 = keys.length; j < len2; j++) { | ||
const k = keys[j] | ||
if (this.canonical && ((ck = cbor_keys[k]))) { | ||
if (!this.push(ck)) { // already a Buffer | ||
return false | ||
} | ||
} else if (!this._pushString(k)) { | ||
return false | ||
} | ||
if (!this.pushAny(obj[k])) { | ||
return false | ||
} | ||
} | ||
if (opts.indefinite) { | ||
if (!this.push(BREAK)) { | ||
return false | ||
} | ||
} else if (this.detectLoops) { | ||
this.detectLoops.delete(obj) | ||
} | ||
return true | ||
} | ||
/** | ||
* Push any supported type onto the encoded stream | ||
* | ||
* @param {any} obj | ||
* @returns {boolean} true on success | ||
*/ | ||
pushAny(obj) { | ||
switch (typeof obj) { | ||
case 'number': | ||
return this._pushNumber(obj) | ||
case 'bigint': | ||
return this._pushJSBigint(obj) | ||
case 'string': | ||
return this._pushString(obj) | ||
case 'boolean': | ||
return this._pushBoolean(obj) | ||
case 'undefined': | ||
return this._pushUndefined(obj) | ||
case 'object': | ||
return this._pushObject(obj) | ||
case 'symbol': | ||
switch (obj) { | ||
case SYMS.NULL: | ||
return this._pushNull(null) | ||
case SYMS.UNDEFINED: | ||
return this._pushUndefined(undefined) | ||
// TODO: Add pluggable support for other symbols | ||
default: | ||
throw new Error('Unknown symbol: ' + obj.toString()) | ||
} | ||
default: | ||
throw new Error( | ||
'Unknown type: ' + typeof obj + ', ' + | ||
(!!obj.toString ? obj.toString() : '') | ||
) | ||
} | ||
} | ||
/* backwards-compat wrapper */ | ||
_pushAny(obj) { | ||
// TODO: write deprecation warning | ||
return this.pushAny(obj) | ||
} | ||
_encodeAll(objs) { | ||
const bs = new NoFilter({ highWaterMark: this.readableHighWaterMark }) | ||
this.pipe(bs) | ||
for (const o of objs) { | ||
this.pushAny(o) | ||
} | ||
this.end() | ||
return bs.read() | ||
} | ||
/** | ||
* Encode the given object with indefinite length. There are apparently | ||
@@ -904,3 +980,3 @@ * some (IMO) broken implementations of poorly-specified protocols that | ||
ret = ret && gen.push(BREAK) | ||
} else if (buf = utils.bufferishToBuffer(obj)) { | ||
} else if ((buf = utils.bufferishToBuffer(obj))) { | ||
ret = ret && gen._pushUInt8((MT.BYTE_STRING << 5) | NUMBYTES.INDEFINITE) | ||
@@ -910,3 +986,3 @@ let offset = 0 | ||
const endIndex = offset + chunkSize | ||
ret = ret && gen._pushBuffer(gen, buf.slice(offset, endIndex)) | ||
ret = ret && Encoder._pushBuffer(gen, buf.slice(offset, endIndex)) | ||
offset = endIndex | ||
@@ -916,8 +992,8 @@ } | ||
} else if (Array.isArray(obj)) { | ||
ret = ret && gen._pushArray(gen, obj, { | ||
indefinite: true | ||
ret = ret && Encoder.pushArray(gen, obj, { | ||
indefinite: true, | ||
}) | ||
} else if (obj instanceof Map) { | ||
ret = ret && gen._pushMap(gen, obj, { | ||
indefinite: true | ||
ret = ret && Encoder._pushMap(gen, obj, { | ||
indefinite: true, | ||
}) | ||
@@ -930,3 +1006,3 @@ } else { | ||
indefinite: true, | ||
skipTypes: true | ||
skipTypes: true, | ||
}) | ||
@@ -957,3 +1033,3 @@ } | ||
return new Encoder({ | ||
canonical: true | ||
canonical: true, | ||
})._encodeAll(objs) | ||
@@ -995,4 +1071,59 @@ } | ||
} | ||
/** | ||
* The currently supported set of semantic types. May be modified by plugins. | ||
* @type {SemanticMap} | ||
*/ | ||
static get SEMANTIC_TYPES() { | ||
return current_SEMANTIC_TYPES | ||
} | ||
static set SEMANTIC_TYPES(val) { | ||
current_SEMANTIC_TYPES = val | ||
} | ||
/** | ||
* Reset the supported semantic types to the original set, before any | ||
* plugins modified the list. | ||
*/ | ||
static reset() { | ||
Encoder.SEMANTIC_TYPES = {...SEMANTIC_TYPES} | ||
} | ||
} | ||
Object.assign(SEMANTIC_TYPES, { | ||
Array: Encoder.pushArray, | ||
Date: Encoder._pushDate, | ||
Buffer: Encoder._pushBuffer, | ||
[Buffer.name]: Encoder._pushBuffer, // Might be mangled | ||
Map: Encoder._pushMap, | ||
NoFilter: Encoder._pushNoFilter, | ||
[NoFilter.name]: Encoder._pushNoFilter, // Mßight be mangled | ||
RegExp: Encoder._pushRegexp, | ||
Set: Encoder._pushSet, | ||
ArrayBuffer: Encoder._pushArrayBuffer, | ||
Uint8ClampedArray: Encoder._pushTypedArray, | ||
Uint8Array: Encoder._pushTypedArray, | ||
Uint16Array: Encoder._pushTypedArray, | ||
Uint32Array: Encoder._pushTypedArray, | ||
Int8Array: Encoder._pushTypedArray, | ||
Int16Array: Encoder._pushTypedArray, | ||
Int32Array: Encoder._pushTypedArray, | ||
Float32Array: Encoder._pushTypedArray, | ||
Float64Array: Encoder._pushTypedArray, | ||
URL: Encoder._pushURL, | ||
Boolean: Encoder._pushBoxed, | ||
Number: Encoder._pushBoxed, | ||
String: Encoder._pushBoxed, | ||
}) | ||
// Safari needs to get better. | ||
if (typeof BigUint64Array !== 'undefined') { | ||
SEMANTIC_TYPES[BigUint64Array.name] = Encoder._pushTypedArray | ||
} | ||
if (typeof BigInt64Array !== 'undefined') { | ||
SEMANTIC_TYPES[BigInt64Array.name] = Encoder._pushTypedArray | ||
} | ||
Encoder.reset() | ||
module.exports = Encoder |
@@ -138,3 +138,3 @@ 'use strict' | ||
forEach(fun, thisArg) { | ||
if (typeof(fun) !== 'function') { | ||
if (typeof fun !== 'function') { | ||
throw new TypeError('Must be function') | ||
@@ -141,0 +141,0 @@ } |
@@ -16,6 +16,6 @@ 'use strict' | ||
if (typeof value !== 'number') { | ||
throw new Error('Invalid Simple type: ' + (typeof value)) | ||
throw new Error(`Invalid Simple type: ${typeof value}`) | ||
} | ||
if ((value < 0) || (value > 255) || ((value | 0) !== value)) { | ||
throw new Error('value must be a small positive integer: ' + value) | ||
throw new Error(`value must be a small positive integer: ${value}`) | ||
} | ||
@@ -31,3 +31,3 @@ this.value = value | ||
toString() { | ||
return 'simple(' + this.value + ')' | ||
return `simple(${this.value})` | ||
} | ||
@@ -41,3 +41,3 @@ | ||
inspect(depth, opts) { | ||
return 'simple(' + this.value + ')' | ||
return `simple(${this.value})` | ||
} | ||
@@ -44,0 +44,0 @@ |
@@ -5,2 +5,3 @@ 'use strict' | ||
const utils = require('./utils') | ||
const INTERNAL_JSON = Symbol('INTERNAL_JSON') | ||
@@ -19,3 +20,6 @@ function setBuffersToJSON(obj, fn) { | ||
} else if (obj && (typeof obj === 'object')) { | ||
// ffs, complexity in the protocol. | ||
// FFS, complexity in the protocol. | ||
// There's some circular dependency in here. | ||
// eslint-disable-next-line no-use-before-define | ||
if (!(obj instanceof Tagged) || (obj.tag < 21) || (obj.tag > 23)) { | ||
@@ -29,2 +33,17 @@ for (const v of Object.values(obj)) { | ||
function b64this() { | ||
// eslint-disable-next-line no-invalid-this | ||
return utils.base64(this) | ||
} | ||
function b64urlThis() { | ||
// eslint-disable-next-line no-invalid-this | ||
return utils.base64url(this) | ||
} | ||
function hexThis() { | ||
// eslint-disable-next-line no-invalid-this | ||
return this.toString('hex') | ||
} | ||
function swapEndian(ab, size, byteOffset, byteLength) { | ||
@@ -35,3 +54,3 @@ const dv = new DataView(ab) | ||
4: [dv.getUint32, dv.setUint32], | ||
8: [dv.getBigUint64, dv.setBigUint64] | ||
8: [dv.getBigUint64, dv.setBigUint64], | ||
}[size] | ||
@@ -45,2 +64,133 @@ | ||
/** | ||
* Convert a tagged value to a more interesting JavaScript type. Errors | ||
* thrown in this function will be captured into the "err" property of the | ||
* original Tagged instance. | ||
* | ||
* @callback TagFunction | ||
* @param {any} value - the value inside the tag | ||
* @param {Tagged} tag - the enclosing Tagged instance; useful if you want to | ||
* modify it and return it. Also available as "this". | ||
* @return {any} the transformed value | ||
*/ | ||
/** | ||
* A mapping from tag number to a tag decoding function | ||
* @typedef {Object.<string, TagFunction>} TagMap | ||
*/ | ||
/** | ||
* @type {TagMap} | ||
* @private | ||
*/ | ||
const TAGS = { | ||
// Standard date/time string; see Section 3.4.1 | ||
0: v => new Date(v), | ||
// Epoch-based date/time; see Section 3.4.2 | ||
1: v => new Date(v * 1000), | ||
// Positive bignum; see Section 3.4.3 | ||
2: v => utils.bufferToBigInt(v), | ||
// Negative bignum; see Section 3.4.3 | ||
3: v => constants.BI.MINUS_ONE - utils.bufferToBigInt(v), | ||
// Expected conversion to base64url encoding; see Section 3.4.5.2 | ||
21: (v, tag) => { | ||
if (utils.isBufferish(v)) { | ||
tag[INTERNAL_JSON] = b64urlThis | ||
} else { | ||
setBuffersToJSON(v, b64urlThis) | ||
} | ||
return tag | ||
}, | ||
// Expected conversion to base64 encoding; see Section 3.4.5.2 | ||
22: (v, tag) => { | ||
if (utils.isBufferish(v)) { | ||
tag[INTERNAL_JSON] = b64this | ||
} else { | ||
setBuffersToJSON(v, b64this) | ||
} | ||
return tag | ||
}, | ||
// Expected conversion to base16 encoding; see Section Section 3.4.5.2 | ||
23: (v, tag) => { | ||
if (utils.isBufferish(v)) { | ||
tag[INTERNAL_JSON] = hexThis | ||
} else { | ||
setBuffersToJSON(v, hexThis) | ||
} | ||
return tag | ||
}, | ||
// URI; see Section 3.4.5.3 | ||
32: v => new URL(v), | ||
// Base64url; see Section 3.4.5.3 | ||
33: (v, tag) => { | ||
// If any of the following apply: | ||
// - the encoded text string contains non-alphabet characters or | ||
// only 1 alphabet character in the last block of 4 (where | ||
// alphabet is defined by Section 5 of [RFC4648] for tag number 33 | ||
// and Section 4 of [RFC4648] for tag number 34), or | ||
if (!v.match(/^[a-zA-Z0-9_-]+$/)) { | ||
throw new Error('Invalid base64url characters') | ||
} | ||
const last = v.length % 4 | ||
if (last === 1) { | ||
throw new Error('Invalid base64url length') | ||
} | ||
// - the padding bits in a 2- or 3-character block are not 0, or | ||
if (last === 2) { | ||
// The last 4 bits of the last character need to be zero. | ||
if ('AQgw'.indexOf(v[v.length - 1]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} else if (last === 3) { | ||
// The last 2 bits of the last character need to be zero. | ||
if ('AEIMQUYcgkosw048'.indexOf(v[v.length - 1]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} | ||
// Or | ||
// - the base64url encoding has padding characters, | ||
// (caught above) | ||
// the string is invalid. | ||
return tag | ||
}, | ||
// Base64; see Section 3.4.5.3 | ||
34: (v, tag) => { | ||
// If any of the following apply: | ||
// - the encoded text string contains non-alphabet characters or | ||
// only 1 alphabet character in the last block of 4 (where | ||
// alphabet is defined by Section 5 of [RFC4648] for tag number 33 | ||
// and Section 4 of [RFC4648] for tag number 34), or | ||
const m = v.match(/^[a-zA-Z0-9+/]+(?<padding>={0,2})$/) | ||
if (!m) { | ||
throw new Error('Invalid base64 characters') | ||
} | ||
if ((v.length % 4) !== 0) { | ||
throw new Error('Invalid base64 length') | ||
} | ||
// - the padding bits in a 2- or 3-character block are not 0, or | ||
if (m.groups.padding === '=') { | ||
// The last 4 bits of the last character need to be zero. | ||
if ('AQgw'.indexOf(v[v.length - 2]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} else if (m.groups.padding === '==') { | ||
// The last 2 bits of the last character need to be zero. | ||
if ('AEIMQUYcgkosw048'.indexOf(v[v.length - 3]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} | ||
// - the base64 encoding has the wrong number of padding characters, | ||
// (caught above) | ||
// the string is invalid. | ||
return tag | ||
}, | ||
// Regular expression; see Section 2.4.4.3 | ||
35: v => new RegExp(v), | ||
// https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md | ||
258: v => new Set(v), | ||
} | ||
const TYPED_ARRAY_TAGS = { | ||
@@ -69,3 +219,3 @@ 64: Uint8Array, | ||
85: Float32Array, | ||
86: Float64Array | ||
86: Float64Array, | ||
// 87: not implemented, float128 array | ||
@@ -84,4 +234,35 @@ } | ||
const INTERNAL_JSON = Symbol('INTERNAL_JSON') | ||
function _toTypedArray(val, tagged) { | ||
if (!utils.isBufferish(val)) { | ||
throw new TypeError('val not a buffer') | ||
} | ||
const {tag} = tagged | ||
// See https://tools.ietf.org/html/rfc8746 | ||
const TypedClass = TYPED_ARRAY_TAGS[tag] | ||
if (!TypedClass) { | ||
throw new Error(`Invalid typed array tag: ${tag}`) | ||
} | ||
const little = tag & 0b00000100 | ||
const float = (tag & 0b00010000) >> 4 | ||
const sz = 2 ** (float + (tag & 0b00000011)) | ||
if ((!little !== utils.isBigEndian()) && (sz > 1)) { | ||
swapEndian(val.buffer, sz, val.byteOffset, val.byteLength) | ||
} | ||
const ab = val.buffer.slice(val.byteOffset, val.byteOffset + val.byteLength) | ||
return new TypedClass(ab) | ||
} | ||
for (const n of Object.keys(TYPED_ARRAY_TAGS)) { | ||
TAGS[n] = _toTypedArray | ||
} | ||
/** | ||
* @type {TagMap} | ||
* @private | ||
*/ | ||
let current_TAGS = {} | ||
/** | ||
* A CBOR tagged item, where the tag does not have semantics specified at the | ||
@@ -104,6 +285,6 @@ * moment, or those semantics threw an error during parsing. Typically this will | ||
if (typeof this.tag !== 'number') { | ||
throw new Error('Invalid tag type (' + (typeof this.tag) + ')') | ||
throw new Error(`Invalid tag type (${typeof this.tag})`) | ||
} | ||
if ((this.tag < 0) || ((this.tag | 0) !== this.tag)) { | ||
throw new Error('Tag must be a positive integer: ' + this.tag) | ||
throw new Error(`Tag must be a positive integer: ${this.tag}`) | ||
} | ||
@@ -114,7 +295,7 @@ } | ||
if (this[INTERNAL_JSON]) { | ||
return this[INTERNAL_JSON]() | ||
return this[INTERNAL_JSON].call(this.value) | ||
} | ||
const ret = { | ||
tag: this.tag, | ||
value: this.value | ||
value: this.value, | ||
} | ||
@@ -158,16 +339,11 @@ if (this.err) { | ||
convert(converters) { | ||
let f = converters != null ? converters[this.tag] : undefined | ||
let f = (converters == null) ? undefined : converters[this.tag] | ||
if (typeof f !== 'function') { | ||
f = Tagged['_tag_' + this.tag] | ||
f = Tagged.TAGS[this.tag] | ||
if (typeof f !== 'function') { | ||
f = TYPED_ARRAY_TAGS[this.tag] | ||
if (typeof f === 'function') { | ||
f = this._toTypedArray | ||
} else { | ||
return this | ||
} | ||
return this | ||
} | ||
} | ||
try { | ||
return f.call(this, this.value) | ||
return f.call(this, this.value, this) | ||
} catch (error) { | ||
@@ -183,183 +359,26 @@ if (error && error.message && (error.message.length > 0)) { | ||
_toTypedArray(val) { | ||
const {tag} = this | ||
// see https://tools.ietf.org/html/rfc8746 | ||
const TypedClass = TYPED_ARRAY_TAGS[tag] | ||
if (!TypedClass) { | ||
throw new Error(`Invalid typed array tag: ${tag}`) | ||
} | ||
const little = tag & 0b00000100 | ||
const float = (tag & 0b00010000) >> 4 | ||
const sz = 2 ** (float + (tag & 0b00000011)) | ||
if ((!little !== utils.isBigEndian()) && (sz > 1)) { | ||
swapEndian(val.buffer, sz, val.byteOffset, val.byteLength) | ||
} | ||
const ab = val.buffer.slice(val.byteOffset, val.byteOffset + val.byteLength) | ||
return new TypedClass(ab) | ||
/** | ||
* The current set of supported tags. May be modified by plugins. | ||
* | ||
* @type {TagMap} | ||
* @static | ||
*/ | ||
static get TAGS() { | ||
return current_TAGS | ||
} | ||
// Standard date/time string; see Section 3.4.1 | ||
static _tag_0(v) { | ||
return new Date(v) | ||
static set TAGS(val) { | ||
current_TAGS = val | ||
} | ||
// Epoch-based date/time; see Section 3.4.2 | ||
static _tag_1(v) { | ||
return new Date(v * 1000) | ||
/** | ||
* Reset the supported tags to the original set, before any plugins modified | ||
* the list. | ||
*/ | ||
static reset() { | ||
Tagged.TAGS = { ...TAGS } | ||
} | ||
// Positive bignum; see Section 3.4.3 | ||
static _tag_2(v) { | ||
// (note: replaced by bigint version in decoder.js when bigint on) | ||
return utils.bufferToBignumber(v) // throws if no BigNumber | ||
} | ||
// Negative bignum; see Section 3.4.3 | ||
static _tag_3(v) { | ||
// (note: replaced by bigint version in decoder.js when bigint on) | ||
const pos = utils.bufferToBignumber(v) // throws if no BigNumber | ||
return constants.BN.MINUS_ONE.minus(pos) | ||
} | ||
// Decimal fraction; see Section 3.4.4 | ||
static _tag_4(v) { | ||
if (!constants.BigNumber) { | ||
throw new Error('No bignumber.js') | ||
} | ||
return new constants.BigNumber(v[1]).shiftedBy(v[0]) | ||
} | ||
// Bigfloat; see Section 3.4.4 | ||
static _tag_5(v) { | ||
if (!constants.BigNumber) { | ||
throw new Error('No bignumber.js') | ||
} | ||
return constants.BN.TWO.pow(v[0]).times(v[1]) | ||
} | ||
// Expected conversion to base64url encoding; see Section 3.4.5.2 | ||
static _tag_21(v) { | ||
if (utils.isBufferish(v)) { | ||
this[INTERNAL_JSON] = () => utils.base64url(v) | ||
} else { | ||
setBuffersToJSON(v, function b64urlThis() { // no =>, honor `this` | ||
// eslint-disable-next-line no-invalid-this | ||
return utils.base64url(this) | ||
}) | ||
} | ||
return this | ||
} | ||
// Expected conversion to base64 encoding; see Section 3.4.5.2 | ||
static _tag_22(v) { | ||
if (utils.isBufferish(v)) { | ||
this[INTERNAL_JSON] = () => utils.base64(v) | ||
} else { | ||
setBuffersToJSON(v, function b64this() { // no =>, honor `this` | ||
// eslint-disable-next-line no-invalid-this | ||
return utils.base64(this) | ||
}) | ||
} | ||
return this | ||
} | ||
// Expected conversion to base16 encoding; see Section Section 3.4.5.2 | ||
static _tag_23(v) { | ||
if (utils.isBufferish(v)) { | ||
this[INTERNAL_JSON] = () => v.toString('hex') | ||
} else { | ||
setBuffersToJSON(v, function hexThis() { // no =>, honor `this` | ||
// eslint-disable-next-line no-invalid-this | ||
return this.toString('hex') | ||
}) | ||
} | ||
return this | ||
} | ||
// URI; see Section 3.4.5.3 | ||
static _tag_32(v) { | ||
return new URL(v) | ||
} | ||
// base64url; see Section 3.4.5.3 | ||
static _tag_33(v) { | ||
// If any of the following apply: | ||
// - the encoded text string contains non-alphabet characters or | ||
// only 1 alphabet character in the last block of 4 (where | ||
// alphabet is defined by Section 5 of [RFC4648] for tag number 33 | ||
// and Section 4 of [RFC4648] for tag number 34), or | ||
if (!v.match(/^[a-zA-Z0-9_-]+$/)) { | ||
throw new Error('Invalid base64url characters') | ||
} | ||
const last = v.length % 4 | ||
if (last === 1) { | ||
throw new Error('Invalid base64url length') | ||
} | ||
// - the padding bits in a 2- or 3-character block are not 0, or | ||
if (last === 2) { | ||
// The last 4 bits of the last character need to be zero. | ||
if ('AQgw'.indexOf(v[v.length - 1]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} else if (last === 3) { | ||
// The last 2 bits of the last character need to be zero. | ||
if ('AEIMQUYcgkosw048'.indexOf(v[v.length - 1]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} | ||
// or | ||
// - the base64url encoding has padding characters, | ||
// (caught above) | ||
// the string is invalid. | ||
return this | ||
} | ||
// base64; see Section 3.4.5.3 | ||
static _tag_34(v) { | ||
// If any of the following apply: | ||
// - the encoded text string contains non-alphabet characters or | ||
// only 1 alphabet character in the last block of 4 (where | ||
// alphabet is defined by Section 5 of [RFC4648] for tag number 33 | ||
// and Section 4 of [RFC4648] for tag number 34), or | ||
const m = v.match(/^[a-zA-Z0-9+/]+(={0,2})$/) | ||
if (!m) { | ||
throw new Error('Invalid base64url characters') | ||
} | ||
if ((v.length % 4) !== 0) { | ||
throw new Error('Invalid base64url length') | ||
} | ||
// - the padding bits in a 2- or 3-character block are not 0, or | ||
if (m[1] === '=') { | ||
// The last 4 bits of the last character need to be zero. | ||
if ('AQgw'.indexOf(v[v.length - 2]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} else if (m[1] === '==') { | ||
// The last 2 bits of the last character need to be zero. | ||
if ('AEIMQUYcgkosw048'.indexOf(v[v.length - 3]) === -1) { | ||
throw new Error('Invalid base64 padding') | ||
} | ||
} | ||
// - the base64 encoding has the wrong number of padding characters, | ||
// (caught above) | ||
// the string is invalid. | ||
return this | ||
} | ||
// Regular expression; see Section 2.4.4.3 | ||
static _tag_35(v) { | ||
return new RegExp(v) | ||
} | ||
// https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md | ||
static _tag_258(v) { | ||
return new Set(v) | ||
} | ||
} | ||
Tagged.INTERNAL_JSON = INTERNAL_JSON | ||
Tagged.reset() | ||
module.exports = Tagged |
115
lib/utils.js
@@ -6,25 +6,10 @@ 'use strict' | ||
const stream = require('stream') | ||
const TextDecoder = require('@cto.af/textdecoder') | ||
const constants = require('./constants') | ||
const { NUMBYTES, SHIFT32, BI, SYMS } = constants | ||
const MAX_SAFE_HIGH = 0x1fffff | ||
let util = null | ||
try { | ||
util = require('util') | ||
} catch (ignored) { | ||
// polyfill node-inspect-extracted in, if you're on the web | ||
// I don't think getting here is possible in non-webpack node. The normal | ||
// methods of causing require('util') to fail don't work with | ||
// internal packages. | ||
/* istanbul ignore next */ | ||
util = require('node-inspect-extracted') | ||
} | ||
exports.inspect = util.inspect | ||
/** | ||
* Convert a UTF8-encoded Buffer to a JS string. If possible, throw an error | ||
* on invalid UTF8. Byte Order Marks are not looked at or stripped. | ||
* @private | ||
*/ | ||
@@ -36,3 +21,3 @@ const td = new TextDecoder('utf8', {fatal: true, ignoreBOM: true}) | ||
function isReadable(s) { | ||
// is this a readable stream? In the webpack version, instanceof isn't | ||
// Is this a readable stream? In the webpack version, instanceof isn't | ||
// working correctly. | ||
@@ -66,3 +51,3 @@ if (s instanceof stream.Readable) { | ||
exports.parseCBORint = function parseCBORint(ai, buf, bigInt = true) { | ||
exports.parseCBORint = function parseCBORint(ai, buf) { | ||
switch (ai) { | ||
@@ -79,11 +64,3 @@ case NUMBYTES.ONE: | ||
if (f > MAX_SAFE_HIGH) { | ||
if (bigInt) { | ||
return (BigInt(f) * BI.SHIFT32) + BigInt(g) | ||
} | ||
if (!constants.BigNumber) { | ||
throw new Error('No bigint and no bignumber.js') | ||
} | ||
return new constants.BigNumber(f) | ||
.times(SHIFT32) | ||
.plus(g) | ||
return (BigInt(f) * BI.SHIFT32) + BigInt(g) | ||
} | ||
@@ -93,3 +70,3 @@ return (f * SHIFT32) + g | ||
default: | ||
throw new Error('Invalid additional info for int: ' + ai) | ||
throw new Error(`Invalid additional info for int: ${ai}`) | ||
} | ||
@@ -99,3 +76,3 @@ } | ||
exports.writeHalf = function writeHalf(buf, half) { | ||
// assume 0, -0, NaN, Infinity, and -Infinity have already been caught | ||
// Assume 0, -0, NaN, Infinity, and -Infinity have already been caught | ||
@@ -117,3 +94,3 @@ // HACK: everyone settle in. This isn't going to be pretty. | ||
// if ((u32.u & 0x1FFF) == 0) { /* worth trying half */ | ||
// If ((u32.u & 0x1FFF) == 0) { /* worth trying half */ | ||
@@ -127,2 +104,3 @@ // hildjj: If the lower 13 bits aren't 0, | ||
// Sign, exponent, mantissa | ||
// int s16 = (u32.u >> 16) & 0x8000; | ||
@@ -132,11 +110,10 @@ // int exp = (u32.u >> 23) & 0xff; | ||
let s16 = (u >> 16) & 0x8000 // top bit is sign | ||
const exp = (u >> 23) & 0xff // then 5 bits of exponent | ||
let s16 = (u >> 16) & 0x8000 // Top bit is sign | ||
const exp = (u >> 23) & 0xff // Then 5 bits of exponent | ||
const mant = u & 0x7fffff | ||
// Hildjj: zeros already handled. Assert if you don't believe me. | ||
// if (exp == 0 && mant == 0) | ||
// ; /* 0.0, -0.0 */ | ||
// hildjj: zeros already handled. Assert if you don't believe me. | ||
// else if (exp >= 113 && exp <= 142) /* normalized */ | ||
@@ -148,2 +125,3 @@ // s16 += ((exp - 112) << 10) + (mant >> 13); | ||
} else if ((exp >= 103) && (exp < 113)) { | ||
// Denormalized numbers | ||
// else if (exp >= 103 && exp < 113) { /* denorm, exp16 = 0 */ | ||
@@ -170,2 +148,3 @@ // if (mant & ((1 << (126 - exp)) - 1)) | ||
// Done | ||
// ensure_writable(3); | ||
@@ -185,5 +164,5 @@ // u16 = s16; | ||
} else if (exp === 0x1f) { | ||
return sign * (mant ? 0 / 0 : 2e308) | ||
return sign * (mant ? NaN : Infinity) | ||
} | ||
return sign * Math.pow(2, exp - 25) * (1024 + mant) | ||
return sign * (2 ** (exp - 25)) * (1024 + mant) | ||
} | ||
@@ -200,3 +179,3 @@ | ||
default: | ||
throw new Error('Invalid float size: ' + buf.length) | ||
throw new Error(`Invalid float size: ${buf.length}`) | ||
} | ||
@@ -232,11 +211,4 @@ } | ||
exports.bufferToBignumber = function bufferToBignumber(buf) { | ||
if (!constants.BigNumber) { | ||
throw new Error('No bigint and no bignumber.js') | ||
} | ||
return new constants.BigNumber(buf.toString('hex'), 16) | ||
} | ||
exports.bufferToBigInt = function bufferToBigInt(buf) { | ||
return BigInt('0x' + buf.toString('hex')) | ||
return BigInt(`0x${buf.toString('hex')}`) | ||
} | ||
@@ -255,3 +227,3 @@ | ||
} | ||
// impossible in node 10 | ||
// Impossible in node 10 | ||
/* istanbul ignore if */ | ||
@@ -261,11 +233,11 @@ if (val.description) { | ||
} | ||
// on node10, Symbol doesn't have description. Parse it out of the | ||
// On node10, Symbol doesn't have description. Parse it out of the | ||
// toString value, which looks like `Symbol(foo)`. | ||
const s = val.toString() | ||
const m = s.match(/^Symbol\((.*)\)/) | ||
const m = s.match(/^Symbol\((?<name>.*)\)/) | ||
/* istanbul ignore if */ | ||
if (m && m[1]) { | ||
// impossible in node 12+ | ||
if (m && m.groups.name) { | ||
// Impossible in node 12+ | ||
/* istanbul ignore next */ | ||
return m[1] | ||
return m.groups.name | ||
} | ||
@@ -278,20 +250,25 @@ return 'Symbol' | ||
return val.toString() | ||
case 'number': | ||
if (float_bytes > 0) { | ||
return (util.inspect(val)) + '_' + float_bytes | ||
case 'number': { | ||
const s = Object.is(val, -0) ? '-0' : String(val) | ||
return (float_bytes > 0) ? `${s}_${float_bytes}` : s | ||
} | ||
case 'object': { | ||
// A null should be caught above | ||
const buf = exports.bufferishToBuffer(val) | ||
if (buf) { | ||
const hex = buf.toString('hex') | ||
return (float_bytes === -Infinity) ? hex : `h'${hex}'` | ||
} | ||
return util.inspect(val) | ||
if (val && (typeof val.inspect === 'function')) { | ||
return val.inspect() | ||
} | ||
// Shouldn't get non-empty arrays here | ||
if (Array.isArray(val)) { | ||
return '[]' | ||
} | ||
// This should be all that is left | ||
return '{}' | ||
} | ||
} | ||
const buf = exports.bufferishToBuffer(val) | ||
if (buf) { | ||
const hex = buf.toString('hex') | ||
return (float_bytes === -Infinity) ? hex : `h'${hex}'` | ||
} | ||
if (constants.BigNumber && constants.BigNumber.isBigNumber(val)) { | ||
return val.toString() | ||
} | ||
if (val && (typeof val.inspect === 'function')) { | ||
return val.inspect() | ||
} | ||
return util.inspect(val) | ||
return String(val) | ||
} | ||
@@ -301,3 +278,3 @@ | ||
if (typeof input === 'string') { | ||
return new NoFilter(input, (encoding != null) ? encoding : 'hex') | ||
return new NoFilter(input, (encoding == null) ? 'hex' : encoding) | ||
} | ||
@@ -317,3 +294,3 @@ const buf = exports.bufferishToBuffer(input) | ||
'+': '-', | ||
'/': '_' | ||
'/': '_', | ||
} | ||
@@ -320,0 +297,0 @@ |
{ | ||
"name": "cbor", | ||
"version": "7.0.6", | ||
"version": "8.0.0", | ||
"description": "Encode and parse data in the Concise Binary Object Representation (CBOR) data format (RFC7049).", | ||
@@ -19,3 +19,3 @@ "main": "./lib/cbor.js", | ||
"scripts": { | ||
"clean": "rm -rf coverage .nyc_output/ docs", | ||
"clean": "rimraf coverage .nyc_output/ docs", | ||
"lint": "eslint lib/*.js test/*.js", | ||
@@ -47,17 +47,10 @@ "coverage": "nyc -r lcov npm test", | ||
"dependencies": { | ||
"@cto.af/textdecoder": "^0.0.0", | ||
"nofilter": "^2.0.3" | ||
"nofilter": "^3.0.2" | ||
}, | ||
"peerDependencies": { | ||
"bignumber.js": "^9.0.1" | ||
}, | ||
"peerDependenciesMeta": { | ||
"bignumber.js": { | ||
"optional": true | ||
} | ||
}, | ||
"devDependencies": { | ||
"@types/node": "*", | ||
"bignumber.js": "^9.0.1", | ||
"garbage": "~0.0.0" | ||
"garbage": "~0.0.0", | ||
"p-event": "^4.2.0", | ||
"rimraf": "^3.0.2" | ||
}, | ||
@@ -67,5 +60,5 @@ "license": "MIT", | ||
"engines": { | ||
"node": ">=10.18.0" | ||
"node": ">=12.19" | ||
}, | ||
"gitHead": "e3b17d1980dd4656505c575c9bc9d65148d40af1" | ||
"gitHead": "93d11477589995ec91c02df99b1dba9f01d583a7" | ||
} |
104
README.md
@@ -20,4 +20,2 @@ # cbor | ||
$ npm install --save cbor | ||
# optional, if you need big floats or big decimals: | ||
$ npm install --save bignumber.js | ||
``` | ||
@@ -28,2 +26,5 @@ | ||
If you need support for encoding and decoding BigDecimal fractions (tag 4) or | ||
BigFloats (tag 5), please see [cbor-bigdecimal](../cbor-bigdecimal). | ||
## Documentation: | ||
@@ -36,17 +37,17 @@ | ||
Example: | ||
```javascript | ||
var cbor = require('cbor'); | ||
var assert = require('assert'); | ||
```js | ||
const cbor = require('cbor') | ||
const assert = require('assert') | ||
var encoded = cbor.encode(true); // returns <Buffer f5> | ||
cbor.decodeFirst(encoded, function(error, obj) { | ||
// error != null if there was an error | ||
let encoded = cbor.encode(true) // Returns <Buffer f5> | ||
cbor.decodeFirst(encoded, (error, obj) => { | ||
// If there was an error, error != null | ||
// obj is the unpacked object | ||
assert.ok(obj === true); | ||
}); | ||
assert.ok(obj === true) | ||
}) | ||
// Use integers as keys? | ||
var m = new Map(); | ||
m.set(1, 2); | ||
encoded = cbor.encode(m); // <Buffer a1 01 02> | ||
const m = new Map() | ||
m.set(1, 2) | ||
encoded = cbor.encode(m) // <Buffer a1 01 02> | ||
``` | ||
@@ -56,18 +57,18 @@ | ||
```javascript | ||
var cbor = require('cbor'); | ||
var fs = require('fs'); | ||
```js | ||
const cbor = require('cbor') | ||
const fs = require('fs') | ||
var d = new cbor.Decoder(); | ||
d.on('data', function(obj){ | ||
console.log(obj); | ||
}); | ||
const d = new cbor.Decoder() | ||
d.on('data', obj => { | ||
console.log(obj) | ||
}) | ||
var s = fs.createReadStream('foo'); | ||
s.pipe(d); | ||
const s = fs.createReadStream('foo') | ||
s.pipe(d) | ||
var d2 = new cbor.Decoder({input: '00', encoding: 'hex'}); | ||
d.on('data', function(obj){ | ||
console.log(obj); | ||
}); | ||
const d2 = new cbor.Decoder({input: '00', encoding: 'hex'}) | ||
d.on('data', obj => { | ||
console.log(obj) | ||
}) | ||
``` | ||
@@ -77,8 +78,8 @@ | ||
```javascript | ||
```js | ||
try { | ||
console.log(cbor.decodeFirstSync('02')); // 2 | ||
console.log(cbor.decodeAllSync('0202')); // [2, 2] | ||
console.log(cbor.decodeFirstSync('02')) // 2 | ||
console.log(cbor.decodeAllSync('0202')) // [2, 2] | ||
} catch (e) { | ||
// throws on invalid input | ||
// Throws on invalid input | ||
} | ||
@@ -99,3 +100,3 @@ ``` | ||
```javascript | ||
``js | ||
cbor.encodeOne(Buffer.alloc(40000), {highWaterMark: 65535}) | ||
@@ -106,3 +107,3 @@ ``` | ||
```javascript | ||
```js | ||
const enc = new cbor.Encoder() | ||
@@ -135,3 +136,2 @@ enc.on('data', buf => /* send the data somewhere */) | ||
* BigInt | ||
* [bignumber](https://github.com/MikeMcl/bignumber.js) (If you install it. It is needed for big float and big decimal types) | ||
@@ -146,4 +146,2 @@ Decoding supports the above types, including the following CBOR tag numbers: | ||
| 3 | BigInt | | ||
| 4 | bignumber | | ||
| 5 | bignumber | | ||
| 21 | Tagged, with toJSON | | ||
@@ -190,9 +188,10 @@ | 22 | Tagged, with toJSON | | ||
```javascript | ||
```js | ||
class Foo { | ||
constructor () { | ||
constructor() { | ||
this.one = 1 | ||
this.two = 2 | ||
} | ||
encodeCBOR (encoder) { | ||
encodeCBOR(encoder) { | ||
const tagged = new Tagged(64000, [this.one, this.two]) | ||
@@ -214,5 +213,5 @@ return encoder.pushAny(tagged) | ||
```javascript | ||
```js | ||
class Bar { | ||
constructor () { | ||
constructor() { | ||
this.three = 3 | ||
@@ -237,10 +236,13 @@ } | ||
```javascript | ||
const d = new Decoder({tags: { 64000: (val) => { | ||
// check val to make sure it's an Array as expected, etc. | ||
const foo = new Foo() | ||
foo.one = val[0] | ||
foo.two = val[1] | ||
return foo | ||
}}}) | ||
```js | ||
const d = new Decoder({ | ||
tags: { | ||
64000: val => { | ||
// Check val to make sure it's an Array as expected, etc. | ||
const foo = new Foo() | ||
;[foo.one, foo.two] = val | ||
return foo | ||
}, | ||
}, | ||
}) | ||
``` | ||
@@ -251,3 +253,3 @@ | ||
```javascript | ||
```js | ||
cbor.decodeFirstSync(input, { | ||
@@ -258,4 +260,4 @@ tags: { | ||
// Temporal built-in, which supports nanosecond time: | ||
0: x => Temporal.Instant.from(x) | ||
} | ||
0: x => Temporal.Instant.from(x), | ||
}, | ||
}) | ||
@@ -262,0 +264,0 @@ ``` |
@@ -1,2 +0,1 @@ | ||
export var BigNumber: typeof import("bignumber.js").default; | ||
export var Commented: typeof import("./commented"); | ||
@@ -15,4 +14,3 @@ export var Diagnose: typeof import("./diagnose"); | ||
} | ||
export var hasBigInt: boolean; | ||
export function reset(): void; | ||
export var comment: typeof import("./commented").comment; | ||
@@ -19,0 +17,0 @@ export var decodeAll: typeof import("./decoder").decodeAll; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
export = Commented; | ||
@@ -29,3 +30,3 @@ /** | ||
max_depth: number; | ||
all: any; | ||
all: NoFilter; | ||
parser: Decoder; | ||
@@ -73,3 +74,5 @@ /** | ||
import stream = require("stream"); | ||
import NoFilter = require("nofilter"); | ||
import Decoder = require("./decoder"); | ||
import { Buffer } from "buffer"; | ||
type CommentOptions = { | ||
@@ -97,7 +100,2 @@ /** | ||
/** | ||
* generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
*/ | ||
bigint?: boolean; | ||
/** | ||
* if true, prefer Uint8Arrays to | ||
@@ -114,2 +112,2 @@ * be generated instead of node Buffers. This might turn on some more | ||
}; | ||
type commentCallback = (error?: Error, commented?: string) => any; | ||
type commentCallback = (error?: Error, commented?: string) => void; |
@@ -1,2 +0,1 @@ | ||
export { BigNumber }; | ||
export namespace MT { | ||
@@ -29,2 +28,3 @@ const POS_INT: number; | ||
const MIME: number; | ||
const SET: number; | ||
} | ||
@@ -65,17 +65,1 @@ export type TAG = number; | ||
} | ||
export namespace BN { | ||
export { MINUS_ONE_1 as MINUS_ONE }; | ||
const NEG_MAX_1: BigNumber; | ||
export { NEG_MAX_1 as NEG_MAX }; | ||
const TWO_1: BigNumber; | ||
export { TWO_1 as TWO }; | ||
export const MAXINT: BigNumber; | ||
const MAXINT32_1: BigNumber; | ||
export { MAXINT32_1 as MAXINT32 }; | ||
const MAXINT64_1: BigNumber; | ||
export { MAXINT64_1 as MAXINT64 }; | ||
const SHIFT32_1: BigNumber; | ||
export { SHIFT32_1 as SHIFT32 }; | ||
} | ||
import { BigNumber } from "bignumber.js"; | ||
declare const MINUS_ONE_1: BigNumber; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
export = Decoder; | ||
@@ -33,3 +34,3 @@ /** | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input - If a Readable stream, must have | ||
* |DataView|ReadableStream} input - If a Readable stream, must have | ||
* received the `readable` event already, or you will get an error | ||
@@ -40,3 +41,3 @@ * claiming "Insufficient data" | ||
*/ | ||
static decodeFirstSync(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | stream.Readable, options?: DecoderOptions | string): any; | ||
static decodeFirstSync(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | ReadableStream, options?: DecoderOptions | string): any; | ||
/** | ||
@@ -49,3 +50,3 @@ * Decode all of the CBOR items in the input into an array. This will throw | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|string} [options={}] Options or encoding | ||
@@ -55,3 +56,3 @@ * for input | ||
*/ | ||
static decodeAllSync(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | stream.Readable, options?: DecoderOptions | string): any[]; | ||
static decodeAllSync(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | ReadableStream, options?: DecoderOptions | string): any[]; | ||
/** | ||
@@ -66,3 +67,3 @@ * Decode the first CBOR item in the input. This will error if there are | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|decodeCallback|string} [options={}] - options, the | ||
@@ -73,3 +74,3 @@ * callback, or input encoding | ||
*/ | ||
static decodeFirst(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | stream.Readable, options?: DecoderOptions | decodeCallback | string, cb?: decodeCallback): Promise<any>; | ||
static decodeFirst(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | ReadableStream, options?: DecoderOptions | decodeCallback | string, cb?: decodeCallback): Promise<any>; | ||
/** | ||
@@ -86,3 +87,3 @@ * @callback decodeAllCallback | ||
* @param {string|Buffer|ArrayBuffer|Uint8Array|Uint8ClampedArray | ||
* |DataView|stream.Readable} input | ||
* |DataView|ReadableStream} input | ||
* @param {DecoderOptions|decodeAllCallback|string} [options={}] - | ||
@@ -93,3 +94,3 @@ * Decoding options, the callback, or the input encoding. | ||
*/ | ||
static decodeAll(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | stream.Readable, options?: string | DecoderOptions | ((error: Error, value: any[]) => any), cb?: (error: Error, value: any[]) => any): Promise<any[]>; | ||
static decodeAll(input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | ReadableStream, options?: string | DecoderOptions | ((error: Error, value: any[]) => any), cb?: (error: Error, value: any[]) => any): Promise<any[]>; | ||
/** | ||
@@ -103,7 +104,9 @@ * Create a parsing stream. | ||
max_depth: number; | ||
tags: any; | ||
tags: { | ||
[x: string]: Tagged.TagFunction; | ||
}; | ||
preferWeb: boolean; | ||
extendedResults: boolean; | ||
bigint: boolean; | ||
valueBytes: any; | ||
required: boolean; | ||
valueBytes: NoFilter; | ||
/** | ||
@@ -123,3 +126,5 @@ * Stop processing | ||
import BinaryParseStream = require("../vendor/binary-parse-stream"); | ||
import stream = require("stream"); | ||
import Tagged = require("./tagged"); | ||
import NoFilter = require("nofilter"); | ||
import { Buffer } from "buffer"; | ||
type DecoderOptions = { | ||
@@ -139,9 +144,4 @@ /** | ||
*/ | ||
tags?: object; | ||
tags?: Tagged.TagMap; | ||
/** | ||
* generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
*/ | ||
bigint?: boolean; | ||
/** | ||
* if true, prefer Uint8Arrays to | ||
@@ -164,3 +164,3 @@ * be generated instead of node Buffers. This might turn on some more | ||
* - if true, emit extended | ||
* results, which will be an object with shape {@link ExtendedResults}. | ||
* results, which will be an object with shape {@link ExtendedResults }. | ||
* The value will already have been null-checked. | ||
@@ -170,8 +170,4 @@ */ | ||
}; | ||
type decodeCallback = (error?: Error, value?: any) => any; | ||
type decodeCallback = (error?: Error, value?: any) => void; | ||
declare const NOT_FOUND: unique symbol; | ||
/** | ||
* {@linkcode Decoder.decodeFirst} or | ||
* {@linkcode Decoder.decodeFirstSync} was called. | ||
*/ | ||
type ExtendedResults = { | ||
@@ -194,5 +190,6 @@ /** | ||
* - the bytes that were left over from the original | ||
* input. This property only exists if { | ||
* input. This property only exists if {@linkcode Decoder.decodeFirst} or | ||
* {@linkcode Decoder.decodeFirstSync} was called. | ||
*/ | ||
unused?: Buffer; | ||
}; |
@@ -29,9 +29,16 @@ export = Diagnose; | ||
parser: Decoder; | ||
_on_error(er: any): boolean; | ||
_on_more(mt: any, len: any, parent_mt: any, pos: any): any; | ||
_fore(parent_mt: any, pos: any): boolean; | ||
_on_value(val: any, parent_mt: any, pos: any): boolean; | ||
_on_start(mt: any, tag: any, parent_mt: any, pos: any): boolean; | ||
_on_stop(mt: any): boolean; | ||
_on_data(): boolean; | ||
/** @private */ | ||
private _on_error; | ||
/** @private */ | ||
private _on_more; | ||
/** @private */ | ||
private _fore; | ||
/** @private */ | ||
private _on_value; | ||
/** @private */ | ||
private _on_start; | ||
/** @private */ | ||
private _on_stop; | ||
/** @private */ | ||
private _on_data; | ||
} | ||
@@ -68,7 +75,2 @@ declare namespace Diagnose { | ||
/** | ||
* generate JavaScript BigInt's | ||
* instead of BigNumbers, when possible. | ||
*/ | ||
bigint?: boolean; | ||
/** | ||
* - if true, prefer Uint8Arrays to | ||
@@ -85,2 +87,2 @@ * be generated instead of node Buffers. This might turn on some more | ||
}; | ||
type diagnoseCallback = (error?: Error, value?: string) => any; | ||
type diagnoseCallback = (error?: Error, value?: string) => void; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
export = Encoder; | ||
@@ -6,12 +7,13 @@ /** | ||
* `type`, `function(Encoder)` for semantic types to be encoded. Not | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, Url, or BigNumber. | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, or URL. | ||
* If an object, the keys are the constructor names for the types. | ||
* @property {boolean} [canonical=false] - should the output be | ||
* canonicalized | ||
* @property {boolean|Symbol} [detectLoops=false] - should object loops | ||
* be detected? This will currently modify the encoded object graph by | ||
* adding a Symbol property to each object. If this bothers you, call | ||
* `removeLoopDetectors` on the encoded object when done. Do not encode | ||
* @property {boolean|WeakSet} [detectLoops=false] - should object loops | ||
* be detected? This will currently add memory to track every part of the | ||
* object being encoded in a WeakSet. Do not encode | ||
* the same object twice on the same encoder, without calling | ||
* `removeLoopDetectors` in between. | ||
* `removeLoopDetectors` in between, which will clear the WeakSet. | ||
* You may pass in your own WeakSet to be used; this is useful in some | ||
* recursive scenarios. | ||
* @property {("number"|"float"|"int"|"string")} [dateType="number"] - | ||
@@ -33,3 +35,3 @@ * how should dates be encoded? "number" means float or int, if no | ||
* @property {boolean} [collapseBigIntegers=false] - Should integers | ||
* that come in as BigNumber integers and ECMAscript bigint's be encoded | ||
* that come in as ECMAscript bigint's be encoded | ||
* as normal CBOR integers if they fit, discarding type information? | ||
@@ -50,14 +52,87 @@ * @property {number} [chunkSize=4096] - Number of characters or bytes | ||
/** | ||
* Remove all of the loop detector additions to the given object. | ||
* The static version is easier to call when you don't have a full | ||
* encoder instance available; it uses a good heuristic to figure | ||
* out the loop detector symbol. | ||
* Encode an array and all of its elements. | ||
* | ||
* @param {Object} obj - object to clean | ||
* @param {Symbol} [detector=null] - the symbol to clean, or null | ||
* to use the first detected symbol | ||
* @returns {boolean} - true when the object was cleaned, else false | ||
* @param {Encoder} gen - Encoder to use | ||
* @param {any[]} obj - Array to encode | ||
* @param {Object} [opts] - options | ||
* @param {boolean} [opts.indefinite=false] - Use indefinite encoding? | ||
* @returns {boolean} true on success | ||
*/ | ||
static removeLoopDetectors(obj: any, detector?: Symbol): boolean; | ||
static pushArray(gen: Encoder, obj: any[], opts?: { | ||
indefinite?: boolean; | ||
}): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Date} obj - Date to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushDate(gen: Encoder, obj: Date): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Buffer} obj - Buffer to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushBuffer(gen: Encoder, obj: Buffer): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {NoFilter} obj - Buffer to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushNoFilter(gen: Encoder, obj: NoFilter): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {RegExp} obj - RegExp to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushRegexp(gen: Encoder, obj: RegExp): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Set} obj - Set to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushSet(gen: Encoder, obj: Set<any>): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {URL} obj - URL to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushURL(gen: Encoder, obj: URL): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {object} obj - Boxed String, Number, or Boolean object to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushBoxed(gen: Encoder, obj: object): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param {Map} obj - Map to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushMap(gen: Encoder, obj: Map<any, any>, opts: any): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param { Uint8Array|Uint16Array|Uint32Array| | ||
* Int8Array|Int16Array|Int32Array| | ||
* Float32Array|Float64Array| | ||
* BigUint64Array|BigInt64Array } obj - Array to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushTypedArray(gen: Encoder, obj: Uint8Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigUint64Array | BigInt64Array): boolean; | ||
/** | ||
* @param {Encoder} gen - Encoder | ||
* @param { ArrayBuffer } obj - Array to encode | ||
* @returns {boolean} True on success | ||
* @ignore | ||
*/ | ||
static _pushArrayBuffer(gen: Encoder, obj: ArrayBuffer): boolean; | ||
/** | ||
* Encode the given object with indefinite length. There are apparently | ||
@@ -119,3 +194,18 @@ * some (IMO) broken implementations of poorly-specified protocols that | ||
static encodeAsync(obj: any, options?: EncodingOptions): Promise<any>; | ||
static set SEMANTIC_TYPES(arg: { | ||
[x: string]: EncodeFunction; | ||
}); | ||
/** | ||
* The currently supported set of semantic types. May be modified by plugins. | ||
* @type {SemanticMap} | ||
*/ | ||
static get SEMANTIC_TYPES(): { | ||
[x: string]: EncodeFunction; | ||
}; | ||
/** | ||
* Reset the supported semantic types to the original set, before any | ||
* plugins modified the list. | ||
*/ | ||
static reset(): void; | ||
/** | ||
* Creates an instance of Encoder. | ||
@@ -131,88 +221,149 @@ * | ||
collapseBigIntegers: boolean; | ||
detectLoops: symbol; | ||
/** @type WeakSet<any>? */ | ||
detectLoops: WeakSet<any> | null; | ||
omitUndefinedProperties: boolean; | ||
semanticTypes: { | ||
Array: (gen: any, obj: any, opts: any) => boolean; | ||
Date: (gen: any, obj: any) => any; | ||
Buffer: (gen: any, obj: any) => any; | ||
Map: (gen: any, obj: any, opts: any) => boolean; | ||
NoFilter: (gen: any, obj: any) => any; | ||
RegExp: (gen: any, obj: any) => any; | ||
Set: (gen: any, obj: any) => boolean; | ||
BigNumber: (gen: any, obj: any) => any; | ||
ArrayBuffer: (gen: any, obj: any) => any; | ||
Uint8ClampedArray: (gen: any, obj: any) => any; | ||
Uint8Array: (gen: any, obj: any) => any; | ||
Uint16Array: (gen: any, obj: any, opts: any) => boolean; | ||
Uint32Array: (gen: any, obj: any, opts: any) => boolean; | ||
Int8Array: (gen: any, obj: any, opts: any) => boolean; | ||
Int16Array: (gen: any, obj: any, opts: any) => boolean; | ||
Int32Array: (gen: any, obj: any, opts: any) => boolean; | ||
Float32Array: (gen: any, obj: any) => boolean; | ||
Float64Array: (gen: any, obj: any) => boolean; | ||
Url: (gen: any, obj: any) => any; | ||
URL: (gen: any, obj: any) => any; | ||
[x: string]: EncodeFunction; | ||
}; | ||
/** | ||
* @callback encodeFunction | ||
* @param {Encoder} encoder - the encoder to serialize into. Call "write" | ||
* on the encoder as needed. | ||
* @return {bool} - true on success, else false | ||
* @param {number} val - Number(0-255) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUInt8(val: number): boolean; | ||
/** | ||
* Add an encoding function to the list of supported semantic types. This is | ||
* useful for objects for which you can't add an encodeCBOR method | ||
* | ||
* @param {any} type | ||
* @param {any} fun | ||
* @returns {encodeFunction} | ||
* @param {number} val - Number(0-65535) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
addSemanticType(type: any, fun: any): (encoder: Encoder) => any; | ||
_pushUInt8(val: any): boolean; | ||
_pushUInt16BE(val: any): boolean; | ||
_pushUInt32BE(val: any): boolean; | ||
_pushFloatBE(val: any): boolean; | ||
_pushDoubleBE(val: any): boolean; | ||
_pushUInt16BE(val: number): boolean; | ||
/** | ||
* @param {number} val - Number(0..2**32-1) to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUInt32BE(val: number): boolean; | ||
/** | ||
* @param {number} val - Number to encode as 4-byte float | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushFloatBE(val: number): boolean; | ||
/** | ||
* @param {number} val - Number to encode as 8-byte double | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushDoubleBE(val: number): boolean; | ||
/** | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNaN(): boolean; | ||
_pushInfinity(obj: any): boolean; | ||
_pushFloat(obj: any): boolean; | ||
_pushInt(obj: any, mt: any, orig: any): boolean; | ||
_pushIntNum(obj: any): boolean; | ||
_pushNumber(obj: any): boolean; | ||
_pushString(obj: any): boolean; | ||
_pushBoolean(obj: any): boolean; | ||
_pushUndefined(obj: any): boolean; | ||
_pushNull(obj: any): boolean; | ||
_pushArray(gen: any, obj: any, opts: any): boolean; | ||
_pushTag(tag: any): boolean; | ||
_pushDate(gen: any, obj: any): any; | ||
_pushBuffer(gen: any, obj: any): any; | ||
_pushNoFilter(gen: any, obj: any): any; | ||
_pushRegexp(gen: any, obj: any): any; | ||
_pushSet(gen: any, obj: any): boolean; | ||
_pushUrl(gen: any, obj: any): any; | ||
_pushURL(gen: any, obj: any): any; | ||
/** | ||
* @param {BigNumber} obj | ||
* @private | ||
* @param {number} obj - Positive or negative infinity | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
private _pushBigint; | ||
_pushInfinity(obj: number): boolean; | ||
/** | ||
* @param {bigint} obj | ||
* @private | ||
* Choose the best float representation for a number and encode it. | ||
* | ||
* @param {number} obj - A number that is known to be not-integer, but not | ||
* how many bytes of precision it needs | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
private _pushJSBigint; | ||
_pushBigNumber(gen: any, obj: any): any; | ||
_pushMap(gen: any, obj: any, opts: any): boolean; | ||
_pushUint8Array(gen: any, obj: any): any; | ||
_pushFloat32Array(gen: any, obj: any): boolean; | ||
_pushFloat64Array(gen: any, obj: any): boolean; | ||
_pushFloat(obj: number): boolean; | ||
/** | ||
* Remove all of the loop detector additions to the given object. | ||
* Choose the best integer representation for a postive number and encode | ||
* it. If the number is over MAX_SAFE_INTEGER, fall back on float (but I | ||
* don't remember why). | ||
* | ||
* @param {Object} obj - object to clean | ||
* @returns {boolean} - true when the object was cleaned, else false | ||
* @param {number} obj - A positive number that is known to be an integer, | ||
* but not how many bytes of precision it needs | ||
* @param {number} mt - The Major Type number to combine with the integer. | ||
* Not yet shifted. | ||
* @param {number} [orig] - The number before it was transformed to positive. | ||
* If the mt is NEG_INT, and the positive number is over MAX_SAFE_INT, | ||
* then we'll encode this as a float rather than making the number | ||
* negative again and losing precision. | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
removeLoopDetectors(obj: any): boolean; | ||
_pushObject(obj: any, opts: any): any; | ||
_pushInt(obj: number, mt: number, orig?: number): boolean; | ||
/** | ||
* Choose the best integer representation for a number and encode it. | ||
* | ||
* @param {number} obj - A number that is known to be an integer, | ||
* but not how many bytes of precision it needs | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushIntNum(obj: number): boolean; | ||
/** | ||
* @param {number} obj - plain JS number to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNumber(obj: number): boolean; | ||
/** | ||
* @param {string} obj - string to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushString(obj: string): boolean; | ||
/** | ||
* @param {boolean} obj - bool to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushBoolean(obj: boolean): boolean; | ||
/** | ||
* @param {undefined} obj - ignored | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushUndefined(obj: undefined): boolean; | ||
/** | ||
* @param {null} obj - ignored | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushNull(obj: null): boolean; | ||
/** | ||
* @param {number} tag - Tag number to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushTag(tag: number): boolean; | ||
/** | ||
* @param {bigint} obj - BigInt to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushJSBigint(obj: bigint): boolean; | ||
/** | ||
* @param {object} obj - object to encode | ||
* @returns {boolean} true on success | ||
* @ignore | ||
*/ | ||
_pushObject(obj: object, opts: any): boolean; | ||
/** | ||
* @param {any[]} objs - Array of supported things | ||
* @returns {Buffer} Concatenation of encodings for the supported things | ||
* @ignore | ||
*/ | ||
_encodeAll(objs: any[]): Buffer; | ||
/** | ||
* Add an encoding function to the list of supported semantic types. This | ||
* is useful for objects for which you can't add an encodeCBOR method | ||
* | ||
* @param {string|function} type - The type to encode | ||
* @param {EncodeFunction} fun - The encoder to use | ||
* @returns {EncodeFunction?} The previous encoder or undefined if there | ||
* wasn't one. | ||
*/ | ||
addSemanticType(type: string | Function, fun: EncodeFunction): EncodeFunction | null; | ||
/** | ||
* Push any supported type onto the encoded stream | ||
@@ -224,9 +375,21 @@ * | ||
pushAny(obj: any): boolean; | ||
_pushAny(obj: any): boolean; | ||
_encodeAll(objs: any): any; | ||
/** | ||
* Remove the loop detector WeakSet for this Encoder. | ||
* | ||
* @returns {boolean} - true when the Encoder was reset, else false | ||
*/ | ||
removeLoopDetectors(): boolean; | ||
} | ||
declare namespace Encoder { | ||
export { EncodingOptions }; | ||
export { EncodeFunction, SemanticMap, EncodingOptions }; | ||
} | ||
import stream = require("stream"); | ||
/** | ||
* Generate the CBOR for a value. If you are using this, you'll either need | ||
* to call {@link Encoder.write } with a Buffer, or look into the internals of | ||
* Encoder to reuse existing non-documented behavior. | ||
*/ | ||
type EncodeFunction = (enc: Encoder, val: any) => boolean; | ||
import { Buffer } from "buffer"; | ||
import NoFilter = require("nofilter"); | ||
type EncodingOptions = { | ||
@@ -236,3 +399,3 @@ /** | ||
* `type`, `function(Encoder)` for semantic types to be encoded. Not | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, Url, or BigNumber. | ||
* needed for Array, Date, Buffer, Map, RegExp, Set, or URL. | ||
* If an object, the keys are the constructor names for the types. | ||
@@ -248,9 +411,10 @@ */ | ||
* - should object loops | ||
* be detected? This will currently modify the encoded object graph by | ||
* adding a Symbol property to each object. If this bothers you, call | ||
* `removeLoopDetectors` on the encoded object when done. Do not encode | ||
* be detected? This will currently add memory to track every part of the | ||
* object being encoded in a WeakSet. Do not encode | ||
* the same object twice on the same encoder, without calling | ||
* `removeLoopDetectors` in between. | ||
* `removeLoopDetectors` in between, which will clear the WeakSet. | ||
* You may pass in your own WeakSet to be used; this is useful in some | ||
* recursive scenarios. | ||
*/ | ||
detectLoops?: boolean | Symbol; | ||
detectLoops?: boolean | WeakSet<any>; | ||
/** | ||
@@ -282,3 +446,3 @@ * - | ||
* - Should integers | ||
* that come in as BigNumber integers and ECMAscript bigint's be encoded | ||
* that come in as ECMAscript bigint's be encoded | ||
* as normal CBOR integers if they fit, discarding type information? | ||
@@ -293,6 +457,13 @@ */ | ||
/** | ||
* - When encoding objects or Maps, do not include a key if its | ||
* corresponding value is `undefined`. | ||
* - When encoding | ||
* objects or Maps, do not include a key if its corresponding value is | ||
* `undefined`. | ||
*/ | ||
omitUndefinedProperties?: boolean; | ||
}; | ||
/** | ||
* A mapping from tag number to a tag decoding function | ||
*/ | ||
type SemanticMap = { | ||
[x: string]: EncodeFunction; | ||
}; |
@@ -25,3 +25,3 @@ export = CborMap; | ||
* Creates an instance of CborMap. | ||
* @param {Iterable<[any, any]>} [iterable] An Array or other iterable | ||
* @param {Iterable<any>} [iterable] An Array or other iterable | ||
* object whose elements are key-value pairs (arrays with two elements, e.g. | ||
@@ -31,3 +31,3 @@ * <code>[[ 1, 'one' ],[ 2, 'two' ]]</code>). Each key-value pair is added | ||
*/ | ||
constructor(iterable?: Iterable<[any, any]>); | ||
constructor(iterable?: Iterable<any>); | ||
/** | ||
@@ -34,0 +34,0 @@ * Push the simple value onto the CBOR stream |
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
export = Simple; | ||
@@ -52,9 +51,2 @@ /** | ||
encodeCBOR(gen: any): any; | ||
/** | ||
* Debug string for simple value | ||
* | ||
* @returns {string} simple(value) | ||
*/ | ||
[util.inspect.custom](depth: any, opts: any): string; | ||
} | ||
import util = require("util"); |
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
export = Tagged; | ||
@@ -9,11 +8,20 @@ /** | ||
declare class Tagged { | ||
static _tag_0(v: any): Date; | ||
static _tag_1(v: any): Date; | ||
static _tag_2(v: any): BigNumber; | ||
static _tag_3(v: any): BigNumber; | ||
static _tag_4(v: any): BigNumber; | ||
static _tag_5(v: any): BigNumber; | ||
static _tag_32(v: any): url.UrlWithStringQuery; | ||
static _tag_35(v: any): RegExp; | ||
static set TAGS(arg: { | ||
[x: string]: TagFunction; | ||
}); | ||
/** | ||
* The current set of supported tags. May be modified by plugins. | ||
* | ||
* @type {TagMap} | ||
* @static | ||
*/ | ||
static get TAGS(): { | ||
[x: string]: TagFunction; | ||
}; | ||
/** | ||
* Reset the supported tags to the original set, before any plugins modified | ||
* the list. | ||
*/ | ||
static reset(): void; | ||
/** | ||
* Creates an instance of Tagged. | ||
@@ -29,2 +37,3 @@ * | ||
err: Error; | ||
toJSON(): any; | ||
/** | ||
@@ -55,3 +64,17 @@ * Convert to a String | ||
} | ||
import { BigNumber } from "./constants"; | ||
import url = require("url"); | ||
declare namespace Tagged { | ||
export { INTERNAL_JSON, TagFunction, TagMap }; | ||
} | ||
/** | ||
* Convert a tagged value to a more interesting JavaScript type. Errors | ||
* thrown in this function will be captured into the "err" property of the | ||
* original Tagged instance. | ||
*/ | ||
type TagFunction = (value: any, tag: Tagged) => any; | ||
declare const INTERNAL_JSON: unique symbol; | ||
/** | ||
* A mapping from tag number to a tag decoding function | ||
*/ | ||
type TagMap = { | ||
[x: string]: TagFunction; | ||
}; |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
export function utf8(buf: any): string; | ||
@@ -5,3 +6,5 @@ export namespace utf8 { | ||
} | ||
export function parseCBORint(ai: any, buf: any, bigInt?: boolean): any; | ||
export function isBufferish(b: any): boolean; | ||
export function bufferishToBuffer(b: any): Buffer; | ||
export function parseCBORint(ai: any, buf: any): any; | ||
export function writeHalf(buf: any, half: any): boolean; | ||
@@ -13,7 +16,8 @@ export function parseHalf(buf: any): number; | ||
export function arrayEqual(a: any, b: any): any; | ||
export function bufferEqual(a: any, b: any): boolean; | ||
export function bufferToBignumber(buf: any): BigNumber; | ||
export function bufferToBigInt(buf: any): bigint; | ||
export function cborValueToString(val: any, float_bytes?: number): string; | ||
export function cborValueToString(val: any, float_bytes?: number): any; | ||
export function guessEncoding(input: any, encoding: any): any; | ||
import { BigNumber } from "./constants"; | ||
export function base64url(buf: Buffer | Uint8Array | Uint8ClampedArray | ArrayBuffer | DataView): string; | ||
export function base64(buf: Buffer | Uint8Array | Uint8ClampedArray | ArrayBuffer | DataView): string; | ||
export function isBigEndian(): boolean; | ||
import { Buffer } from "buffer"; |
@@ -14,3 +14,3 @@ export = BinaryParseStream; | ||
constructor(options: any); | ||
bs: any; | ||
bs: NoFilter; | ||
__fresh: boolean; | ||
@@ -28,1 +28,2 @@ __needed: number; | ||
import Stream = require("stream"); | ||
import NoFilter = require("nofilter"); |
@@ -28,4 +28,7 @@ // Tweaked version of nathan7's binary-parse-stream | ||
super(options) | ||
// doesn't work to pass these in as opts, for some reason | ||
// Doesn't work to pass these in as opts, for some reason | ||
// also, work around typescript not knowing TransformStream internals | ||
// eslint-disable-next-line dot-notation | ||
this['_writableState'].objectMode = false | ||
// eslint-disable-next-line dot-notation | ||
this['_readableState'].objectMode = true | ||
@@ -56,7 +59,7 @@ | ||
if (!ret.done) { | ||
this.__needed = ret.value || Infinity | ||
} else { | ||
if (ret.done) { | ||
this.push(ret.value) | ||
this.__restart() | ||
} else { | ||
this.__needed = ret.value || Infinity | ||
} | ||
@@ -63,0 +66,0 @@ } |
@@ -15,5 +15,5 @@ # binary-parse-stream | ||
```javascript | ||
var BinaryParseStream = require('binary-parse-stream') | ||
, One = BinaryParseStream.One // -1 | ||
```js | ||
const BinaryParseStream = require('binary-parse-stream') | ||
const {One} = BinaryParseStream // -1 | ||
``` | ||
@@ -33,16 +33,16 @@ | ||
```js | ||
var BinaryParseStream = require('binary-parse-stream') | ||
, inherits = require('util').inherits | ||
class SillyProtocolParseStream extends BinaryParseStream { | ||
constructor(options) { | ||
super(options) | ||
this.count = 0 | ||
} | ||
module.exports = SillyProtocolParseStream | ||
inherits(SillyProtocolParseStream, BinaryParseStream) | ||
function SillyProtocolParseStream(options) { | ||
BinaryParseStream.call(this, options) | ||
*_parse() { | ||
const type = (yield 4).readUInt32BE(0, true) | ||
const length = yield -1 | ||
const buf = yield length | ||
this.count++ | ||
return { type, buf } | ||
} | ||
} | ||
SillyProtocolParseStream.prototype._parse = function*() { | ||
var type = (yield 4).readUInt32BE(0, true) | ||
, length = yield -1 | ||
, buf = yield length | ||
return { type: type, buf: buf } | ||
} | ||
``` | ||
@@ -49,0 +49,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
150044
1
4423
273
5
+ Addednofilter@3.1.0(transitive)
- Removed@cto.af/textdecoder@^0.0.0
- Removed@cto.af/textdecoder@0.0.0(transitive)
- Removedbignumber.js@9.1.2(transitive)
- Removednofilter@2.0.3(transitive)
Updatednofilter@^3.0.2