| /** | ||
| * @typedef {import('../interface.js').TagDecodeControl} TagDecodeControl | ||
| * @typedef {(decode: TagDecodeControl) => Tagged} TaggedTagDecoder | ||
| */ | ||
| /** | ||
| * A wrapper class for representing a CBOR tag with an arbitrary nested value. | ||
| * | ||
| * `Tagged` is a symmetric primitive: it can be passed to `encode()` to emit | ||
| * a CBOR tag header followed by the encoded form of `value`, and it can be | ||
| * returned from a tag decoder (via `Tagged.decoder(tag)` or `Tagged.preserve()`) | ||
| * to round-trip a tag through decode without losing the tag number. | ||
| * | ||
| * Use `Tagged` for one-off tag handling where defining a dedicated | ||
| * `typeEncoders` entry and tag decoder pair would be heavyweight, e.g. when | ||
| * wrapping a structure in a single application-specific tag (COSE, dCBOR | ||
| * envelopes, etc.). | ||
| * | ||
| * For systematic mapping of a JS type to a tag (e.g. CID -> tag 42), prefer | ||
| * a dedicated `typeEncoders` entry instead. | ||
| */ | ||
| export class Tagged { | ||
| /** | ||
| * @param {number} tag - CBOR tag number, a non-negative integer | ||
| * @param {any} value - The value to be tagged; encoded recursively | ||
| */ | ||
| constructor (tag, value) { | ||
| if (typeof tag !== 'number' || !Number.isInteger(tag) || tag < 0) { | ||
| throw new TypeError('Tagged: tag must be a non-negative integer') | ||
| } | ||
| this.tag = tag | ||
| this.value = value | ||
| } | ||
| /** | ||
| * Build a tag decoder for use in `decode()`'s `tags` option that returns the | ||
| * decoded content wrapped in a `Tagged` instance, preserving the tag number | ||
| * for the caller to inspect. | ||
| * | ||
| * @param {number} tag - The CBOR tag number this decoder will be registered for | ||
| * @returns {TaggedTagDecoder} | ||
| * | ||
| * @example | ||
| * import { decode, Tagged } from 'cborg' | ||
| * const value = decode(bytes, { tags: { 16: Tagged.decoder(16) } }) | ||
| * // value instanceof Tagged; value.tag === 16 | ||
| */ | ||
| static decoder (tag) { | ||
| return (decode) => new Tagged(tag, decode()) | ||
| } | ||
| /** | ||
| * Build a `tags` option for `decode()` that wraps each listed tag number in | ||
| * a `Tagged` instance, preserving those tags through decode without | ||
| * registering a dedicated decoder per tag. | ||
| * | ||
| * @param {...number} tagNumbers - One or more CBOR tag numbers to preserve | ||
| * @returns {{[tagNumber: number]: TaggedTagDecoder}} | ||
| * | ||
| * @example | ||
| * import { decode, Tagged } from 'cborg' | ||
| * const value = decode(bytes, { tags: Tagged.preserve(16, 96) }) | ||
| */ | ||
| static preserve (...tagNumbers) { | ||
| /** @type {{[tagNumber: number]: TaggedTagDecoder}} */ | ||
| const tags = {} | ||
| for (const tag of tagNumbers) { | ||
| tags[tag] = Tagged.decoder(tag) | ||
| } | ||
| return tags | ||
| } | ||
| } | ||
| // Symbol.toStringTag so the internal `is()` type detection returns 'Tagged' | ||
| // for instances, allowing the default Tagged typeEncoder to match. | ||
| Object.defineProperty(Tagged.prototype, Symbol.toStringTag, { | ||
| value: 'Tagged' | ||
| }) |
| /* eslint-env mocha */ | ||
| import * as chai from 'chai' | ||
| import { decode, encode, encodeInto, rfc8949EncodeOptions, Tagged, Token, Type } from '../cborg.js' | ||
| import { encodedLength } from '../lib/length.js' | ||
| import { fromHex, toHex } from '../lib/byte-utils.js' | ||
| const { assert } = chai | ||
| describe('Tagged', () => { | ||
| describe('class', () => { | ||
| it('exposes tag and value', () => { | ||
| const t = new Tagged(16, 'hello') | ||
| assert.strictEqual(t.tag, 16) | ||
| assert.strictEqual(t.value, 'hello') | ||
| }) | ||
| it('rejects non-integer tag', () => { | ||
| assert.throws(() => new Tagged(1.5, null), TypeError) | ||
| assert.throws(() => new Tagged(-1, null), TypeError) | ||
| // @ts-expect-error - intentional bad input | ||
| assert.throws(() => new Tagged('16', null), TypeError) | ||
| // @ts-expect-error - intentional bad input | ||
| assert.throws(() => new Tagged(undefined, null), TypeError) | ||
| assert.throws(() => new Tagged(NaN, null), TypeError) | ||
| }) | ||
| it('Symbol.toStringTag is "Tagged"', () => { | ||
| assert.strictEqual(Object.prototype.toString.call(new Tagged(0, null)), '[object Tagged]') | ||
| }) | ||
| }) | ||
| describe('encode', () => { | ||
| it('encodes a small tag with primitive value', () => { | ||
| // RFC 8949 example: tag 1 wrapping 1363896240 | ||
| const bytes = encode(new Tagged(1, 1363896240)) | ||
| assert.strictEqual(toHex(bytes), 'c11a514b67b0') | ||
| }) | ||
| it('encodes a 1-byte tag header (>= 24)', () => { | ||
| const bytes = encode(new Tagged(32, 'http://example.com')) | ||
| assert.strictEqual(bytes[0], 0xd8) | ||
| assert.strictEqual(bytes[1], 32) | ||
| }) | ||
| it('encodes a 2-byte tag header (>= 256)', () => { | ||
| const bytes = encode(new Tagged(259, new Map())) | ||
| // d9 01 03 = tag(259), then a0 = map(0) | ||
| assert.strictEqual(toHex(bytes), 'd90103a0') | ||
| }) | ||
| it('encodes a 4-byte tag header (>= 65536)', () => { | ||
| const bytes = encode(new Tagged(0x10000, 0)) | ||
| // da 00 01 00 00 = tag(65536), then 00 = uint(0) | ||
| assert.strictEqual(toHex(bytes), 'da0001000000') | ||
| }) | ||
| it('recurses into nested object value', () => { | ||
| const bytes = encode(new Tagged(16, [new Uint8Array([1, 2, 3]), new Map(), null])) | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(16), useMaps: true }) | ||
| assert.instanceOf(decoded, Tagged) | ||
| assert.strictEqual(decoded.tag, 16) | ||
| assert.deepEqual(decoded.value[0], new Uint8Array([1, 2, 3])) | ||
| assert.instanceOf(decoded.value[1], Map) | ||
| assert.strictEqual(decoded.value[2], null) | ||
| }) | ||
| it('Tagged is overridable via typeEncoders (returning null falls through)', () => { | ||
| // Override that only special-cases tag 99 and falls through for everything else | ||
| let calls = 0 | ||
| const bytes = encode(new Tagged(99, 'ignored'), { | ||
| typeEncoders: { | ||
| Tagged: (obj) => { | ||
| calls++ | ||
| if (obj.tag !== 999) return null // fall through | ||
| return [new Token(Type.string, 'replaced')] | ||
| } | ||
| } | ||
| }) | ||
| assert.strictEqual(calls, 1) | ||
| // Falling through means default behaviour: tag(99) text("ignored") | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(99) }) | ||
| assert.strictEqual(decoded.tag, 99) | ||
| assert.strictEqual(decoded.value, 'ignored') | ||
| }) | ||
| it('Tagged is overridable via typeEncoders (full replacement)', () => { | ||
| const bytes = encode(new Tagged(99, 'foo'), { | ||
| typeEncoders: { | ||
| Tagged: () => [new Token(Type.string, 'replaced')] | ||
| } | ||
| }) | ||
| assert.strictEqual(decode(bytes), 'replaced') | ||
| }) | ||
| it('typeEncoders for inner types apply to wrapped value', () => { | ||
| // Custom Date encoder should fire when Date appears inside Tagged.value | ||
| let dateEncoderCalled = false | ||
| const bytes = encode(new Tagged(16, [new Date(0)]), { | ||
| typeEncoders: { | ||
| Date: (d) => { | ||
| dateEncoderCalled = true | ||
| return [new Token(Type.uint, d.getTime())] | ||
| } | ||
| } | ||
| }) | ||
| assert.isTrue(dateEncoderCalled) | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(16) }) | ||
| assert.strictEqual(decoded.tag, 16) | ||
| assert.deepEqual(decoded.value, [0]) | ||
| }) | ||
| it('rfc8949EncodeOptions sorts maps inside Tagged.value', () => { | ||
| // Build a Map whose insertion order differs from RFC 8949 bytewise order. | ||
| // RFC 8949 sorts keys by their canonical encoding bytes; for short | ||
| // strings the longer key sorts later. | ||
| const inner = new Map([ | ||
| ['bb', 2], | ||
| ['a', 1] | ||
| ]) | ||
| const sortedDefault = encode(new Tagged(16, inner)) | ||
| const sortedRfc8949 = encode(new Tagged(16, inner), rfc8949EncodeOptions) | ||
| // Default (RFC 7049, length-first) and RFC 8949 (bytewise) agree here: | ||
| // 'a' (1 byte) sorts before 'bb' (2 bytes) under both rules. | ||
| assert.deepEqual(sortedDefault, sortedRfc8949) | ||
| // Verify the tag header is present and the inner map is sorted | ||
| const decodedDefault = decode(sortedDefault, { tags: Tagged.preserve(16), useMaps: true }) | ||
| assert.strictEqual(decodedDefault.tag, 16) | ||
| assert.instanceOf(decodedDefault.value, Map) | ||
| assert.deepEqual([...decodedDefault.value.keys()], ['a', 'bb']) | ||
| }) | ||
| it('detects circular references inside Tagged.value', () => { | ||
| const arr = [] | ||
| arr.push(arr) | ||
| assert.throws(() => encode(new Tagged(16, arr)), /circular/i) | ||
| }) | ||
| it('works with encodeInto', () => { | ||
| const dest = new Uint8Array(64) | ||
| const { written } = encodeInto(new Tagged(1, 1363896240), dest) | ||
| assert.strictEqual(toHex(dest.subarray(0, written)), 'c11a514b67b0') | ||
| }) | ||
| it('works with encodedLength', () => { | ||
| const value = new Tagged(16, [new Uint8Array([1, 2, 3]), new Map([[1, 2]]), null]) | ||
| const expected = encode(value).length | ||
| assert.strictEqual(encodedLength(value), expected) | ||
| }) | ||
| }) | ||
| describe('decode', () => { | ||
| it('Tagged.decoder builds a passthrough decoder', () => { | ||
| const bytes = fromHex('c11a514b67b0') // tag(1) 1363896240 | ||
| const value = decode(bytes, { tags: { 1: Tagged.decoder(1) } }) | ||
| assert.instanceOf(value, Tagged) | ||
| assert.strictEqual(value.tag, 1) | ||
| assert.strictEqual(value.value, 1363896240) | ||
| }) | ||
| it('Tagged.preserve builds a tags map for multiple tags', () => { | ||
| const tags = Tagged.preserve(16, 96) | ||
| assert.typeOf(tags[16], 'function') | ||
| assert.typeOf(tags[96], 'function') | ||
| assert.isUndefined(tags[1]) | ||
| }) | ||
| it('Tagged.preserve with no arguments yields an empty tags map', () => { | ||
| const tags = Tagged.preserve() | ||
| assert.deepEqual(Object.keys(tags), []) | ||
| }) | ||
| it('unregistered tags still throw when Tagged.preserve is partial', () => { | ||
| // tag(2) wrapping bytes(0) | ||
| const bytes = fromHex('c240') | ||
| assert.throws(() => decode(bytes, { tags: Tagged.preserve(16) }), /tag not supported/) | ||
| }) | ||
| }) | ||
| describe('round-trip', () => { | ||
| it('round-trips a COSE_Encrypt0-shaped envelope', () => { | ||
| // Build a structure resembling COSE_Encrypt0 (RFC 9052): | ||
| // tag(16) [protected_bstr, unprotected_map, ciphertext_or_nil] | ||
| const protectedHeaders = encode(new Map([[1, -7]])) // alg = ES256 | ||
| const unprotected = new Map([[5, new Uint8Array([0xaa, 0xbb])]]) // iv | ||
| const envelope = new Tagged(16, [protectedHeaders, unprotected, null]) | ||
| const bytes = encode(envelope) | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(16), useMaps: true }) | ||
| assert.instanceOf(decoded, Tagged) | ||
| assert.strictEqual(decoded.tag, 16) | ||
| assert.deepEqual(decoded.value[0], protectedHeaders) | ||
| assert.instanceOf(decoded.value[1], Map) | ||
| assert.deepEqual(decoded.value[1].get(5), new Uint8Array([0xaa, 0xbb])) | ||
| assert.strictEqual(decoded.value[2], null) | ||
| }) | ||
| it('round-trips deeply nested Tagged instances', () => { | ||
| let v = /** @type {any} */ ('leaf') | ||
| for (let i = 1; i <= 5; i++) { | ||
| v = new Tagged(i, v) | ||
| } | ||
| const bytes = encode(v) | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(1, 2, 3, 4, 5) }) | ||
| let cur = decoded | ||
| for (let i = 5; i >= 1; i--) { | ||
| assert.instanceOf(cur, Tagged) | ||
| assert.strictEqual(cur.tag, i) | ||
| cur = cur.value | ||
| } | ||
| assert.strictEqual(cur, 'leaf') | ||
| }) | ||
| it('Tagged round-trips through rfc8949EncodeOptions', () => { | ||
| const value = new Tagged(16, [ | ||
| new Tagged(2, new Uint8Array([0xff])), | ||
| new Map([['z', 1], ['a', 2]]) | ||
| ]) | ||
| const bytes = encode(value, rfc8949EncodeOptions) | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(2, 16), useMaps: true }) | ||
| assert.strictEqual(decoded.tag, 16) | ||
| assert.strictEqual(decoded.value[0].tag, 2) | ||
| assert.deepEqual(decoded.value[0].value, new Uint8Array([0xff])) | ||
| assert.deepEqual([...decoded.value[1].keys()], ['a', 'z']) | ||
| }) | ||
| }) | ||
| }) |
| /** | ||
| * @typedef {import('../interface.js').TagDecodeControl} TagDecodeControl | ||
| * @typedef {(decode: TagDecodeControl) => Tagged} TaggedTagDecoder | ||
| */ | ||
| /** | ||
| * A wrapper class for representing a CBOR tag with an arbitrary nested value. | ||
| * | ||
| * `Tagged` is a symmetric primitive: it can be passed to `encode()` to emit | ||
| * a CBOR tag header followed by the encoded form of `value`, and it can be | ||
| * returned from a tag decoder (via `Tagged.decoder(tag)` or `Tagged.preserve()`) | ||
| * to round-trip a tag through decode without losing the tag number. | ||
| * | ||
| * Use `Tagged` for one-off tag handling where defining a dedicated | ||
| * `typeEncoders` entry and tag decoder pair would be heavyweight, e.g. when | ||
| * wrapping a structure in a single application-specific tag (COSE, dCBOR | ||
| * envelopes, etc.). | ||
| * | ||
| * For systematic mapping of a JS type to a tag (e.g. CID -> tag 42), prefer | ||
| * a dedicated `typeEncoders` entry instead. | ||
| */ | ||
| export class Tagged { | ||
| /** | ||
| * Build a tag decoder for use in `decode()`'s `tags` option that returns the | ||
| * decoded content wrapped in a `Tagged` instance, preserving the tag number | ||
| * for the caller to inspect. | ||
| * | ||
| * @param {number} tag - The CBOR tag number this decoder will be registered for | ||
| * @returns {TaggedTagDecoder} | ||
| * | ||
| * @example | ||
| * import { decode, Tagged } from 'cborg' | ||
| * const value = decode(bytes, { tags: { 16: Tagged.decoder(16) } }) | ||
| * // value instanceof Tagged; value.tag === 16 | ||
| */ | ||
| static decoder(tag: number): TaggedTagDecoder; | ||
| /** | ||
| * Build a `tags` option for `decode()` that wraps each listed tag number in | ||
| * a `Tagged` instance, preserving those tags through decode without | ||
| * registering a dedicated decoder per tag. | ||
| * | ||
| * @param {...number} tagNumbers - One or more CBOR tag numbers to preserve | ||
| * @returns {{[tagNumber: number]: TaggedTagDecoder}} | ||
| * | ||
| * @example | ||
| * import { decode, Tagged } from 'cborg' | ||
| * const value = decode(bytes, { tags: Tagged.preserve(16, 96) }) | ||
| */ | ||
| static preserve(...tagNumbers: number[]): { | ||
| [tagNumber: number]: TaggedTagDecoder; | ||
| }; | ||
| /** | ||
| * @param {number} tag - CBOR tag number, a non-negative integer | ||
| * @param {any} value - The value to be tagged; encoded recursively | ||
| */ | ||
| constructor(tag: number, value: any); | ||
| tag: number; | ||
| value: any; | ||
| } | ||
| export type TagDecodeControl = import("../interface.js").TagDecodeControl; | ||
| export type TaggedTagDecoder = (decode: TagDecodeControl) => Tagged; | ||
| //# sourceMappingURL=tagged.d.ts.map |
| {"version":3,"file":"tagged.d.ts","sourceRoot":"","sources":["../../lib/tagged.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AACH;IAaE;;;;;;;;;;;;OAYG;IACH,oBARW,MAAM,GACJ,gBAAgB,CAS5B;IAED;;;;;;;;;;;OAWG;IACH,+BAPc,MAAM,EAAA,GACP;QAAC,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAA;KAAC,CAanD;IAhDD;;;OAGG;IACH,iBAHW,MAAM,SACN,GAAG,EAQb;IAFC,YAAc;IACd,WAAkB;CAwCrB;+BAtEY,OAAO,iBAAiB,EAAE,gBAAgB;+BAC1C,CAAC,MAAM,EAAE,gBAAgB,KAAK,MAAM"} |
+4
-1
@@ -1,3 +0,4 @@ | ||
| import { encode, encodeInto, rfc8949EncodeOptions } from './lib/encode.js' | ||
| import { encode, encodeInto, objectToTokens, rfc8949EncodeOptions } from './lib/encode.js' | ||
| import { decode, decodeFirst, Tokeniser, tokensToObject } from './lib/decode.js' | ||
| import { Tagged } from './lib/tagged.js' | ||
| import { Token, Type } from './lib/token.js' | ||
@@ -22,5 +23,7 @@ | ||
| encodeInto, | ||
| objectToTokens, | ||
| rfc8949EncodeOptions, | ||
| Tagged, | ||
| Token, | ||
| Type | ||
| } |
+6
-0
@@ -0,1 +1,7 @@ | ||
| ## [5.1.0](https://github.com/rvagg/cborg/compare/v5.0.1...v5.1.0) (2026-04-07) | ||
| ### Features | ||
| * add Tagged class for one-off tag emission and round-trip preservation ([#174](https://github.com/rvagg/cborg/issues/174)) ([e2e7c20](https://github.com/rvagg/cborg/commit/e2e7c207e79d7131e3e941772f1d70ce1363b94f)) | ||
| ## [5.0.1](https://github.com/rvagg/cborg/compare/v5.0.0...v5.0.1) (2026-04-02) | ||
@@ -2,0 +8,0 @@ |
+18
-0
@@ -297,2 +297,20 @@ import { is } from './is.js' | ||
| return [new Token(Type.map, entries.length), entries] | ||
| }, | ||
| /** | ||
| * Encode a `Tagged` wrapper as a CBOR tag header followed by the encoded | ||
| * form of the wrapped value. The value is recursively tokenised through | ||
| * `objectToTokens()` so any registered `typeEncoders` apply to it. | ||
| * | ||
| * @param {any} obj | ||
| * @param {string} _typ | ||
| * @param {EncodeOptions} options | ||
| * @param {Reference} [refStack] | ||
| * @returns {TokenOrNestedTokens} | ||
| */ | ||
| Tagged (obj, _typ, options, refStack) { | ||
| return [ | ||
| new Token(Type.tag, obj.tag), | ||
| objectToTokens(obj.value, options, refStack) | ||
| ] | ||
| } | ||
@@ -299,0 +317,0 @@ } |
+2
-1
@@ -32,3 +32,4 @@ // This is an unfortunate replacement for @sindresorhus/is that we need to | ||
| 'BigInt64Array', | ||
| 'BigUint64Array' | ||
| 'BigUint64Array', | ||
| 'Tagged' | ||
| ] | ||
@@ -35,0 +36,0 @@ |
+1
-1
| { | ||
| "name": "cborg", | ||
| "version": "5.0.1", | ||
| "version": "5.1.0", | ||
| "description": "Fast CBOR with a focus on strictness", | ||
@@ -5,0 +5,0 @@ "main": "cborg.js", |
+67
-4
@@ -9,4 +9,2 @@ # cborg - fast CBOR with a focus on strictness | ||
| **cborg** supports CBOR tags, but does not ship with them enabled by default. If you want tags, you need to plug them in to the encoder and decoder. | ||
| * [Example](#example) | ||
@@ -34,2 +32,3 @@ * [CLI](#cli) | ||
| * [`encodedLength(data[, options])`](#encodedlengthdata-options) | ||
| * [`Tagged`](#tagged) | ||
| * [Type encoders](#type-encoders) | ||
@@ -330,2 +329,48 @@ * [Tag decoders](#tag-decoders) | ||
| ### `Tagged` | ||
| For applications that need to wrap a value in an application-specific CBOR tag (COSE envelopes, dCBOR application tags, custom protocols) without the ceremony of registering a `typeEncoders` entry and a matching tag decoder, cborg exports a `Tagged` wrapper class. `Tagged` is symmetric: pass it to `encode()` to emit a tag, and use `Tagged.decoder(tag)` or `Tagged.preserve(...tags)` on the decode side to round-trip the tag without losing it. | ||
| ```js | ||
| import { encode, decode, Tagged } from 'cborg' | ||
| // Encode: wrap any value in a tag | ||
| const bytes = encode(new Tagged(1234, 'hello')) | ||
| // Decode: preserve the tag through decode | ||
| const decoded = decode(bytes, { tags: Tagged.preserve(1234) }) | ||
| decoded instanceof Tagged // true | ||
| decoded.tag // 1234 | ||
| decoded.value // 'hello' | ||
| ``` | ||
| `Tagged.value` can be anything cborg can encode, including arrays, maps, other `Tagged` instances, or values handled by your own `typeEncoders` — cborg recurses into it with the same encode pipeline. | ||
| For finer-grained control on decode, use `Tagged.decoder(tag)` directly to mix preserved tags with other decoders: | ||
| ```js | ||
| import { decode, Tagged } from 'cborg' | ||
| const value = decode(bytes, { | ||
| tags: { | ||
| 16: Tagged.decoder(16), // preserve tag 16 as Tagged | ||
| 96: Tagged.decoder(96), // preserve tag 96 as Tagged | ||
| 42: cidDecoder // a custom decoder for tag 42 | ||
| } | ||
| }) | ||
| ``` | ||
| When to prefer `Tagged` over a custom `typeEncoders` entry: | ||
| - You have a one-off or application-specific tag and don't want to define a JS class for it. | ||
| - You want to inspect the tag number on the decode side rather than collapsing it into a JS type. | ||
| - Your downstream code already speaks `{ tag, value }`. | ||
| When to prefer a `typeEncoders` entry instead: | ||
| - You're systematically mapping a JS type to a tag (e.g. `CID` → tag 42, `Date` → tag 1) and want it to apply automatically wherever that type appears. | ||
| - You need a tighter binary representation than the default recursive encoding (e.g. flatten the value to a `bytes` token rather than a nested CBOR structure). | ||
| The default `Tagged` behaviour is itself implemented as a `typeEncoders` entry under the type name `'Tagged'`. You can override it by supplying your own `typeEncoders.Tagged` and returning `null` from it to fall through to the default for cases your override doesn't want to handle. | ||
| ### Type encoders | ||
@@ -337,8 +382,26 @@ | ||
| The `typeEncoders` option is an object whose property names match to @sindresorhus/is type names. When this option is provided and a property exists for any given object's type, the function provided as the value to that property is called with the object as an argument. | ||
| The `typeEncoders` option is an object whose property names match to @sindresorhus/is type names. When this option is provided and a property exists for any given object's type, the function is called with the signature `(obj, typ, options, refStack)`: | ||
| * `obj` - the value being encoded | ||
| * `typ` - the resolved type name (the same string used as the property key) | ||
| * `options` - the full encode options object, useful for recursive encoding (see below) | ||
| * `refStack` - an internal circular-reference tracker, opaque to user code, that should be threaded through any recursive call | ||
| If a type encoder function returns `null`, the default encoder, if any, is used instead. | ||
| If a type encoder function returns an array, cborg will expect it to contain zero or more `Token` objects that will be encoded to binary form. | ||
| If a type encoder function returns an array, cborg will expect it to contain zero or more `Token` objects (or nested arrays thereof) that will be encoded to binary form. To **recursively encode a nested JavaScript value** as part of your tokens (so that `typeEncoders` for the nested value still apply), import `objectToTokens` from `cborg` and call `objectToTokens(value, options, refStack)` from inside your encoder. This is how the built-in `Tagged` encoder, `mapEncoder`, and `setEncoder` recurse into their contents: | ||
| ```js | ||
| import { Token, Type, objectToTokens } from 'cborg' | ||
| function myWrapperEncoder (obj, _typ, options, refStack) { | ||
| return [ | ||
| new Token(Type.tag, 1234), | ||
| objectToTokens(obj.inner, options, refStack) | ||
| ] | ||
| } | ||
| ``` | ||
| For tag encoders that flatten their content to a leaf type (e.g. encode a `BigInt` as a `Type.bytes` token under tag 2), you don't need to recurse - just return the flat token sequence directly, as the `bigIntEncoder` example below does. | ||
| `Token`s map directly to CBOR entities. Each one has a `Type` and a `value`. A type encoder is responsible for turning a JavaScript object into a set of tags. | ||
@@ -345,0 +408,0 @@ |
+3
-1
@@ -27,6 +27,8 @@ /** | ||
| import { encodeInto } from './lib/encode.js'; | ||
| import { objectToTokens } from './lib/encode.js'; | ||
| import { rfc8949EncodeOptions } from './lib/encode.js'; | ||
| import { Tagged } from './lib/tagged.js'; | ||
| import { Token } from './lib/token.js'; | ||
| import { Type } from './lib/token.js'; | ||
| export { decode, decodeFirst, Tokeniser as Tokenizer, tokensToObject, encode, encodeInto, rfc8949EncodeOptions, Token, Type }; | ||
| export { decode, decodeFirst, Tokeniser as Tokenizer, tokensToObject, encode, encodeInto, objectToTokens, rfc8949EncodeOptions, Tagged, Token, Type }; | ||
| //# sourceMappingURL=cborg.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"cborg.d.ts","sourceRoot":"","sources":["../cborg.js"],"names":[],"mappings":";;;+BAMa,OAAO,gBAAgB,EAAE,gBAAgB;;;;yBACzC,OAAO,gBAAgB,EAAE,UAAU;;;;0BAEnC,OAAO,gBAAgB,EAAE,mBAAmB;;;;4BAC5C,OAAO,gBAAgB,EAAE,aAAa;;;;4BACtC,OAAO,gBAAgB,EAAE,aAAa;uBAVY,iBAAiB;4BAAjB,iBAAiB;0BAAjB,iBAAiB;+BAAjB,iBAAiB;uBADvB,iBAAiB;2BAAjB,iBAAiB;qCAAjB,iBAAiB;sBAE9C,gBAAgB;qBAAhB,gBAAgB"} | ||
| {"version":3,"file":"cborg.d.ts","sourceRoot":"","sources":["../cborg.js"],"names":[],"mappings":";;;+BAOa,OAAO,gBAAgB,EAAE,gBAAgB;;;;yBACzC,OAAO,gBAAgB,EAAE,UAAU;;;;0BAEnC,OAAO,gBAAgB,EAAE,mBAAmB;;;;4BAC5C,OAAO,gBAAgB,EAAE,aAAa;;;;4BACtC,OAAO,gBAAgB,EAAE,aAAa;uBAXY,iBAAiB;4BAAjB,iBAAiB;0BAAjB,iBAAiB;+BAAjB,iBAAiB;uBADP,iBAAiB;2BAAjB,iBAAiB;+BAAjB,iBAAiB;qCAAjB,iBAAiB;uBAEnE,iBAAiB;sBACZ,gBAAgB;qBAAhB,gBAAgB"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../lib/encode.js"],"names":[],"mappings":"AAwCA,oCAAoC;AACpC,oCADc,gBAAgB,EAAE,CAY/B;AAnBD,4BAA4B;AAC5B,mCADW,aAAa,CAKtB;sBA+XW,KAAK,GAAG;IAAE,SAAS,CAAC,EAAE,UAAU,CAAA;CAAE;4BApZlC,OAAO,iBAAiB,EAAE,aAAa;kCACvC,OAAO,iBAAiB,EAAE,mBAAmB;wBAC7C,OAAO,iBAAiB,EAAE,SAAS;gCACnC,OAAO,iBAAiB,EAAE,iBAAiB;+BAC3C,OAAO,iBAAiB,EAAE,gBAAgB;kCAC1C,OAAO,iBAAiB,EAAE,mBAAmB;yBAC7C,OAAO,iBAAiB,EAAE,UAAU;AA0RjD;;;;;GAKG;AACH,oCALW,GAAG,YACH,aAAa,aACb,SAAS,GACP,mBAAmB,CAgB/B;AAiUD;;;;GAIG;AACH,6BAJW,GAAG,YACH,aAAa,GACX,UAAU,CAatB;AA3DD;;;;;;GAMG;AACH,mCANW,GAAG,YACH,gBAAgB,EAAE,WAClB,aAAa,gBACb,UAAU,GACR,UAAU,CAoCtB;AAoBD;;;;;GAKG;AACH,iCALW,GAAG,eACH,UAAU,YACV,aAAa,GACX;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAc/B;AAhnBD,8BAA8B;AAC9B,4BADiB,SAAS;IA0BxB;;;;OAIG;IACH,0BAJW,SAAS,GAAC,SAAS,OACnB,MAAM,GAAC,GAAG,EAAE,GACV,SAAS,CAOrB;IAlCD;;;OAGG;IACH,iBAHW,MAAM,GAAC,GAAG,EAAE,UACZ,SAAS,GAAC,SAAS,EAK7B;IAFC,oBAAc;IACd,wDAAoB;IAGtB;;;OAGG;IACH,cAHW,MAAM,GAAC,GAAG,EAAE,GACV,OAAO,CAWnB;CAaF;sBA9F2B,YAAY"} | ||
| {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../lib/encode.js"],"names":[],"mappings":"AAwCA,oCAAoC;AACpC,oCADc,gBAAgB,EAAE,CAY/B;AAnBD,4BAA4B;AAC5B,mCADW,aAAa,CAKtB;sBAiZW,KAAK,GAAG;IAAE,SAAS,CAAC,EAAE,UAAU,CAAA;CAAE;4BAtalC,OAAO,iBAAiB,EAAE,aAAa;kCACvC,OAAO,iBAAiB,EAAE,mBAAmB;wBAC7C,OAAO,iBAAiB,EAAE,SAAS;gCACnC,OAAO,iBAAiB,EAAE,iBAAiB;+BAC3C,OAAO,iBAAiB,EAAE,gBAAgB;kCAC1C,OAAO,iBAAiB,EAAE,mBAAmB;yBAC7C,OAAO,iBAAiB,EAAE,UAAU;AA4SjD;;;;;GAKG;AACH,oCALW,GAAG,YACH,aAAa,aACb,SAAS,GACP,mBAAmB,CAgB/B;AAiUD;;;;GAIG;AACH,6BAJW,GAAG,YACH,aAAa,GACX,UAAU,CAatB;AA3DD;;;;;;GAMG;AACH,mCANW,GAAG,YACH,gBAAgB,EAAE,WAClB,aAAa,gBACb,UAAU,GACR,UAAU,CAoCtB;AAoBD;;;;;GAKG;AACH,iCALW,GAAG,eACH,UAAU,YACV,aAAa,GACX;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAc/B;AAloBD,8BAA8B;AAC9B,4BADiB,SAAS;IA0BxB;;;;OAIG;IACH,0BAJW,SAAS,GAAC,SAAS,OACnB,MAAM,GAAC,GAAG,EAAE,GACV,SAAS,CAOrB;IAlCD;;;OAGG;IACH,iBAHW,MAAM,GAAC,GAAG,EAAE,UACZ,SAAS,GAAC,SAAS,EAK7B;IAFC,oBAAc;IACd,wDAAoB;IAGtB;;;OAGG;IACH,cAHW,MAAM,GAAC,GAAG,EAAE,GACV,OAAO,CAWnB;CAaF;sBA9F2B,YAAY"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"is.d.ts","sourceRoot":"","sources":["../../lib/is.js"],"names":[],"mappings":"AAkCA;;;GAGG;AACH,0BAHW,GAAG,GACD,MAAM,CAqClB"} | ||
| {"version":3,"file":"is.d.ts","sourceRoot":"","sources":["../../lib/is.js"],"names":[],"mappings":"AAmCA;;;GAGG;AACH,0BAHW,GAAG,GACD,MAAM,CAqClB"} |
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
559853
3.55%132
3.13%12351
2.99%824
8.28%