UNPKG

@zondax/cbor

Version:

Encode and parse data in the Concise Binary Object Representation (CBOR) data format (RFC8949).

464 lines (463 loc) 16.8 kB
/// <reference types="node" /> export = Encoder; /** * @typedef EncodingOptions * @property {any[]|object} [genTypes=[]] Array of pairs of * `type`, `function(Encoder)` for semantic types to be encoded. Not * 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|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, 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"] - * how should dates be encoded? "number" means float or int, if no * fractional seconds. * @property {any} [encodeUndefined=undefined] How should an * "undefined" in the input be encoded. By default, just encode a CBOR * undefined. If this is a buffer, use those bytes without re-encoding * them. If this is a function, the function will be called (which is a * good time to throw an exception, if that's what you want), and the * return value will be used according to these rules. Anything else will * be encoded as CBOR. * @property {boolean} [disallowUndefinedKeys=false] Should * "undefined" be disallowed as a key in a Map that is serialized? If * this is true, encode(new Map([[undefined, 1]])) will throw an * exception. Note that it is impossible to get a key of undefined in a * normal JS object. * @property {boolean} [collapseBigIntegers=false] Should integers * that come in as ECMAscript bigint's be encoded * as normal CBOR integers if they fit, discarding type information? * @property {number} [chunkSize=4096] Number of characters or bytes * for each chunk, if obj is a string or Buffer, when indefinite encoding. * @property {boolean} [omitUndefinedProperties=false] When encoding * objects or Maps, do not include a key if its corresponding value is * `undefined`. */ /** * Transform JavaScript values into CBOR bytes. The `Writable` side of * the stream is in object mode. * * @extends stream.Transform */ declare class Encoder extends stream.Transform { /** * 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: 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. * @throws {Error} Map key that is undefined. * @ignore */ static _pushMap(gen: Encoder, obj: Map<any, any>, opts: any): boolean; /** * @param {Encoder} gen Encoder. * @param {NodeJS.TypedArray} obj Array to encode. * @returns {boolean} True on success. * @ignore */ static _pushTypedArray(gen: Encoder, obj: NodeJS.TypedArray): 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 * some (IMO) broken implementations of poorly-specified protocols that * REQUIRE indefinite-encoding. See the example for how to add this as an * `encodeCBOR` function to an object or class to get indefinite encoding. * * @param {Encoder} gen The encoder to use. * @param {string|Buffer|Array|Map|object} [obj] The object to encode. If * null, use "this" instead. * @param {EncodingOptions} [options={}] Options for encoding. * @returns {boolean} True on success. * @throws {Error} No object to encode or invalid indefinite encoding. * @example <caption>Force indefinite encoding:</caption> * const o = { * a: true, * encodeCBOR: cbor.Encoder.encodeIndefinite, * } * const m = [] * m.encodeCBOR = cbor.Encoder.encodeIndefinite * cbor.encodeOne([o, m]) */ static encodeIndefinite(gen: Encoder, obj?: string | Buffer | any[] | Map<any, any> | object, options?: EncodingOptions): boolean; /** * Encode one or more JavaScript objects, and return a Buffer containing the * CBOR bytes. * * @param {...any} objs The objects to encode. * @returns {Buffer} The encoded objects. */ static encode(...objs: any[]): Buffer; /** * Encode one or more JavaScript objects canonically (slower!), and return * a Buffer containing the CBOR bytes. * * @param {...any} objs The objects to encode. * @returns {Buffer} The encoded objects. */ static encodeCanonical(...objs: any[]): Buffer; /** * Encode one JavaScript object using the given options. * * @static * @param {any} obj The object to encode. * @param {EncodingOptions} [options={}] Passed to the Encoder constructor. * @returns {Buffer} The encoded objects. */ static encodeOne(obj: any, options?: EncodingOptions): Buffer; /** * Encode one JavaScript object using the given options in a way that * is more resilient to objects being larger than the highWaterMark * number of bytes. As with the other static encode functions, this * will still use a large amount of memory. Use a stream-based approach * directly if you need to process large and complicated inputs. * * @param {any} obj The object to encode. * @param {EncodingOptions} [options={}] Passed to the Encoder constructor. * @returns {Promise<Buffer>} A promise for the encoded buffer. */ static encodeAsync(obj: any, options?: EncodingOptions): Promise<Buffer>; 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. * * @param {EncodingOptions} [options={}] Options for the encoder. */ constructor(options?: EncodingOptions); canonical: boolean; encodeUndefined: any; disallowUndefinedKeys: boolean; dateType: "string" | "number" | "float" | "int"; collapseBigIntegers: boolean; /** @type {WeakSet?} */ detectLoops: WeakSet<any> | null; omitUndefinedProperties: boolean; semanticTypes: { [x: string]: EncodeFunction; }; /** * @param {number} val Number(0-255) to encode. * @returns {boolean} True on success. * @ignore */ _pushUInt8(val: number): boolean; /** * @param {number} val Number(0-65535) to encode. * @returns {boolean} True on success. * @ignore */ _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; /** * @param {number} obj Positive or negative infinity. * @returns {boolean} True on success. * @ignore */ _pushInfinity(obj: number): boolean; /** * 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: number): boolean; /** * 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: 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. * @throws {Error} Loop detected. * @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. * @throws {TypeError} Invalid function. */ addSemanticType(type: string | Function, fun: EncodeFunction): EncodeFunction | null; /** * Push any supported type onto the encoded stream. * * @param {any} obj The thing to encode. * @returns {boolean} True on success. * @throws {TypeError} Unknown type for obj. */ pushAny(obj: any): boolean; /** * Remove the loop detector WeakSet for this Encoder. * * @returns {boolean} True when the Encoder was reset, else false. */ removeLoopDetectors(): boolean; } declare namespace Encoder { 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 = { /** * Array of pairs of * `type`, `function(Encoder)` for semantic types to be encoded. Not * needed for Array, Date, Buffer, Map, RegExp, Set, or URL. * If an object, the keys are the constructor names for the types. */ genTypes?: any[] | object; /** * Should the output be * canonicalized. */ canonical?: boolean; /** * 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, which will clear the WeakSet. * You may pass in your own WeakSet to be used; this is useful in some * recursive scenarios. */ detectLoops?: boolean | WeakSet<any>; /** * - * how should dates be encoded? "number" means float or int, if no * fractional seconds. */ dateType?: ("number" | "float" | "int" | "string"); /** * How should an * "undefined" in the input be encoded. By default, just encode a CBOR * undefined. If this is a buffer, use those bytes without re-encoding * them. If this is a function, the function will be called (which is a * good time to throw an exception, if that's what you want), and the * return value will be used according to these rules. Anything else will * be encoded as CBOR. */ encodeUndefined?: any; /** * Should * "undefined" be disallowed as a key in a Map that is serialized? If * this is true, encode(new Map([[undefined, 1]])) will throw an * exception. Note that it is impossible to get a key of undefined in a * normal JS object. */ disallowUndefinedKeys?: boolean; /** * Should integers * that come in as ECMAscript bigint's be encoded * as normal CBOR integers if they fit, discarding type information? */ collapseBigIntegers?: boolean; /** * Number of characters or bytes * for each chunk, if obj is a string or Buffer, when indefinite encoding. */ chunkSize?: number; /** * 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; };