diff --git a/CHANGELOG.md b/CHANGELOG.md index db70c72b..d97bcf0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ https://github.com/msgpack/msgpack-javascript/compare/v2.8.0...v3.0.0-beta1 * Add an option `useBigInt64` to map JavaScript's BigInt to MessagePack's int64 and uint64 ([#223](https://github.com/msgpack/msgpack-javascript/pull/223)) * Drop IE11 support ([#221](https://github.com/msgpack/msgpack-javascript/pull/221)) * It also fixes [feature request: option to disable TEXT_ENCODING env check #219](https://github.com/msgpack/msgpack-javascript/issues/219) -* +* Change the interfaces of `Encoder` and `Decoder`, and describe the interfaces in README.md ([#224](https://github.com/msgpack/msgpack-javascript/pull/224)): + * `new Encoder(options: EncoderOptions)`: it takes the same named-options as `encode()` + * `new Decoder(options: DecoderOptions)`: it takes the same named-options as `decode()` ## 2.8.0 2022-09-02 diff --git a/README.md b/README.md index 19854d60..c5910692 100644 --- a/README.md +++ b/README.md @@ -38,14 +38,14 @@ deepStrictEqual(decode(encoded), object); - [Table of Contents](#table-of-contents) - [Install](#install) - [API](#api) - - [`encode(data: unknown, options?: EncodeOptions): Uint8Array`](#encodedata-unknown-options-encodeoptions-uint8array) - - [`EncodeOptions`](#encodeoptions) - - [`decode(buffer: ArrayLike | BufferSource, options?: DecodeOptions): unknown`](#decodebuffer-arraylikenumber--buffersource-options-decodeoptions-unknown) - - [`DecodeOptions`](#decodeoptions) - - [`decodeMulti(buffer: ArrayLike | BufferSource, options?: DecodeOptions): Generator`](#decodemultibuffer-arraylikenumber--buffersource-options-decodeoptions-generatorunknown-void-unknown) - - [`decodeAsync(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): Promise`](#decodeasyncstream-readablestreamlikearraylikenumber--buffersource-options-decodeasyncoptions-promiseunknown) - - [`decodeArrayStream(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): AsyncIterable`](#decodearraystreamstream-readablestreamlikearraylikenumber--buffersource-options-decodeasyncoptions-asynciterableunknown) - - [`decodeMultiStream(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): AsyncIterable`](#decodemultistreamstream-readablestreamlikearraylikenumber--buffersource-options-decodeasyncoptions-asynciterableunknown) + - [`encode(data: unknown, options?: EncoderOptions): Uint8Array`](#encodedata-unknown-options-encoderoptions-uint8array) + - [`EncoderOptions`](#encoderoptions) + - [`decode(buffer: ArrayLike | BufferSource, options?: DecoderOptions): unknown`](#decodebuffer-arraylikenumber--buffersource-options-decoderoptions-unknown) + - [`DecoderOptions`](#decoderoptions) + - [`decodeMulti(buffer: ArrayLike | BufferSource, options?: DecoderOptions): Generator`](#decodemultibuffer-arraylikenumber--buffersource-options-decoderoptions-generatorunknown-void-unknown) + - [`decodeAsync(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): Promise`](#decodeasyncstream-readablestreamlikearraylikenumber--buffersource-options-decoderoptions-promiseunknown) + - [`decodeArrayStream(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): AsyncIterable`](#decodearraystreamstream-readablestreamlikearraylikenumber--buffersource-options-decoderoptions-asynciterableunknown) + - [`decodeMultiStream(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): AsyncIterable`](#decodemultistreamstream-readablestreamlikearraylikenumber--buffersource-options-decoderoptions-asynciterableunknown) - [Reusing Encoder and Decoder instances](#reusing-encoder-and-decoder-instances) - [Extension Types](#extension-types) - [ExtensionCodec context](#extensioncodec-context) @@ -80,7 +80,7 @@ npm install @msgpack/msgpack ## API -### `encode(data: unknown, options?: EncodeOptions): Uint8Array` +### `encode(data: unknown, options?: EncoderOptions): Uint8Array` It encodes `data` into a single MessagePack-encoded object, and returns a byte array as `Uint8Array`. It throws errors if `data` is, or includes, a non-serializable object such as a `function` or a `symbol`. @@ -105,7 +105,7 @@ const buffer: Buffer = Buffer.from(encoded.buffer, encoded.byteOffset, encoded.b console.log(buffer); ``` -#### `EncodeOptions` +#### `EncoderOptions` Name|Type|Default ----|----|---- @@ -118,7 +118,7 @@ forceIntegerToFloat | boolean | false ignoreUndefined | boolean | false context | user-defined | - -### `decode(buffer: ArrayLike | BufferSource, options?: DecodeOptions): unknown` +### `decode(buffer: ArrayLike | BufferSource, options?: DecoderOptions): unknown` It decodes `buffer` that includes a MessagePack-encoded object, and returns the decoded object typed `unknown`. @@ -138,7 +138,7 @@ console.log(object); NodeJS `Buffer` is also acceptable because it is a subclass of `Uint8Array`. -#### `DecodeOptions` +#### `DecoderOptions` Name|Type|Default ----|----|---- @@ -152,7 +152,7 @@ context | user-defined | - You can use `max${Type}Length` to limit the length of each type decoded. -### `decodeMulti(buffer: ArrayLike | BufferSource, options?: DecodeOptions): Generator` +### `decodeMulti(buffer: ArrayLike | BufferSource, options?: DecoderOptions): Generator` It decodes `buffer` that includes multiple MessagePack-encoded objects, and returns decoded objects as a generator. See also `decodeMultiStream()`, which is an asynchronous variant of this function. @@ -170,14 +170,12 @@ for (const object of decodeMulti(encoded)) { } ``` -### `decodeAsync(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): Promise` +### `decodeAsync(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): Promise` It decodes `stream`, where `ReadableStreamLike` is defined as `ReadableStream | AsyncIterable`, in an async iterable of byte arrays, and returns decoded object as `unknown` type, wrapped in `Promise`. This function works asynchronously, and might CPU resources more efficiently compared with synchronous `decode()`, because it doesn't wait for the completion of downloading. -`DecodeAsyncOptions` is the same as `DecodeOptions` for `decode()`. - This function is designed to work with whatwg `fetch()` like this: ```typescript @@ -193,7 +191,7 @@ if (contentType && contentType.startsWith(MSGPACK_TYPE) && response.body != null } else { /* handle errors */ } ``` -### `decodeArrayStream(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): AsyncIterable` +### `decodeArrayStream(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): AsyncIterable` It is alike to `decodeAsync()`, but only accepts a `stream` that includes an array of items, and emits a decoded item one by one. @@ -210,7 +208,7 @@ for await (const item of decodeArrayStream(stream)) { } ``` -### `decodeMultiStream(stream: ReadableStreamLike | BufferSource>, options?: DecodeAsyncOptions): AsyncIterable` +### `decodeMultiStream(stream: ReadableStreamLike | BufferSource>, options?: DecoderOptions): AsyncIterable` It is alike to `decodeAsync()` and `decodeArrayStream()`, but the input `stream` must consist of multiple MessagePack-encoded items. This is an asynchronous variant for `decodeMulti()`. @@ -233,7 +231,7 @@ This function is available since v2.4.0; previously it was called as `decodeStre ### Reusing Encoder and Decoder instances -`Encoder` and `Decoder` classes is provided to have better performance by reusing instances: +`Encoder` and `Decoder` classes are provided to have better performance by reusing instances: ```typescript import { deepStrictEqual } from "assert"; @@ -251,6 +249,8 @@ than `encode()` function, and reusing `Decoder` instance is about 2% faster than `decode()` function. Note that the result should vary in environments and data structure. +`Encoder` and `Decoder` take the same options as `encode()` and `decode()` respectively. + ## Extension Types To handle [MessagePack Extension Types](https://github.com/msgpack/msgpack/blob/master/spec.md#extension-types), this library provides `ExtensionCodec` class. @@ -304,7 +304,7 @@ Not that extension types for custom objects must be `[0, 127]`, while `[-1, -128 #### ExtensionCodec context -When you use an extension codec, it might be necessary to have encoding/decoding state to keep track of which objects got encoded/re-created. To do this, pass a `context` to the `EncodeOptions` and `DecodeOptions`: +When you use an extension codec, it might be necessary to have encoding/decoding state to keep track of which objects got encoded/re-created. To do this, pass a `context` to the `EncoderOptions` and `DecoderOptions`: ```typescript import { encode, decode, ExtensionCodec } from "@msgpack/msgpack"; diff --git a/src/Decoder.ts b/src/Decoder.ts index 356a8310..260b5742 100644 --- a/src/Decoder.ts +++ b/src/Decoder.ts @@ -5,6 +5,61 @@ import { utf8Decode } from "./utils/utf8"; import { createDataView, ensureUint8Array } from "./utils/typedArrays"; import { CachedKeyDecoder, KeyDecoder } from "./CachedKeyDecoder"; import { DecodeError } from "./DecodeError"; +import type { ContextOf } from "./context"; + +export type DecoderOptions = Readonly< + Partial<{ + extensionCodec: ExtensionCodecType; + + /** + * Decodes Int64 and Uint64 as bigint if it's set to true. + * Depends on ES2020's {@link DataView#getBigInt64} and + * {@link DataView#getBigUint64}. + * + * Defaults to false. + */ + useBigInt64: boolean; + + /** + * Maximum string length. + * + * Defaults to 4_294_967_295 (UINT32_MAX). + */ + maxStrLength: number; + /** + * Maximum binary length. + * + * Defaults to 4_294_967_295 (UINT32_MAX). + */ + maxBinLength: number; + /** + * Maximum array length. + * + * Defaults to 4_294_967_295 (UINT32_MAX). + */ + maxArrayLength: number; + /** + * Maximum map length. + * + * Defaults to 4_294_967_295 (UINT32_MAX). + */ + maxMapLength: number; + /** + * Maximum extension length. + * + * Defaults to 4_294_967_295 (UINT32_MAX). + */ + maxExtLength: number; + + /** + * An object key decoder. Defaults to the shared instance of {@link CachedKeyDecoder}. + * `null` is a special value to disable the use of the key decoder at all. + */ + keyDecoder: KeyDecoder | null; + }> +> & + ContextOf; + const STATE_ARRAY = "array"; const STATE_MAP_KEY = "map_key"; @@ -54,6 +109,16 @@ const MORE_DATA = new DataViewIndexOutOfBoundsError("Insufficient data"); const sharedCachedKeyDecoder = new CachedKeyDecoder(); export class Decoder { + private readonly extensionCodec: ExtensionCodecType; + private readonly context: ContextType; + private readonly useBigInt64: boolean; + private readonly maxStrLength: number; + private readonly maxBinLength: number; + private readonly maxArrayLength: number; + private readonly maxMapLength: number; + private readonly maxExtLength: number; + private readonly keyDecoder: KeyDecoder | null; + private totalPos = 0; private pos = 0; @@ -62,17 +127,18 @@ export class Decoder { private headByte = HEAD_BYTE_REQUIRED; private readonly stack: Array = []; - public constructor( - private readonly extensionCodec: ExtensionCodecType = ExtensionCodec.defaultCodec as any, - private readonly context: ContextType = undefined as any, - private readonly useBigInt64 = false, - private readonly maxStrLength = UINT32_MAX, - private readonly maxBinLength = UINT32_MAX, - private readonly maxArrayLength = UINT32_MAX, - private readonly maxMapLength = UINT32_MAX, - private readonly maxExtLength = UINT32_MAX, - private readonly keyDecoder: KeyDecoder | null = sharedCachedKeyDecoder, - ) {} + public constructor(options?: DecoderOptions) { + this.extensionCodec = options?.extensionCodec ?? (ExtensionCodec.defaultCodec as ExtensionCodecType); + this.context = (options as { context: ContextType } | undefined)?.context as ContextType; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined + + this.useBigInt64 = options?.useBigInt64 ?? false; + this.maxStrLength = options?.maxStrLength ?? UINT32_MAX; + this.maxBinLength = options?.maxBinLength ?? UINT32_MAX; + this.maxArrayLength = options?.maxArrayLength ?? UINT32_MAX; + this.maxMapLength = options?.maxMapLength ?? UINT32_MAX; + this.maxExtLength = options?.maxExtLength ?? UINT32_MAX; + this.keyDecoder = (options?.keyDecoder !== undefined) ? options.keyDecoder : sharedCachedKeyDecoder; + } private reinitializeState() { this.totalPos = 0; diff --git a/src/Encoder.ts b/src/Encoder.ts index 7312471d..da02ff32 100644 --- a/src/Encoder.ts +++ b/src/Encoder.ts @@ -3,26 +3,105 @@ import { ExtensionCodec, ExtensionCodecType } from "./ExtensionCodec"; import { setInt64, setUint64 } from "./utils/int"; import { ensureUint8Array } from "./utils/typedArrays"; import type { ExtData } from "./ExtData"; +import type { ContextOf, SplitUndefined } from "./context"; + export const DEFAULT_MAX_DEPTH = 100; export const DEFAULT_INITIAL_BUFFER_SIZE = 2048; +export type EncoderOptions = Partial< + Readonly<{ + extensionCodec: ExtensionCodecType; + + /** + * Encodes bigint as Int64 or Uint64 if it's set to true. + * {@link forceIntegerToFloat} does not affect bigint. + * Depends on ES2020's {@link DataView#setBigInt64} and + * {@link DataView#setBigUint64}. + * + * Defaults to false. + */ + useBigInt64: boolean; + + /** + * The maximum depth in nested objects and arrays. + * + * Defaults to 100. + */ + maxDepth: number; + + /** + * The initial size of the internal buffer. + * + * Defaults to 2048. + */ + initialBufferSize: number; + + /** + * If `true`, the keys of an object is sorted. In other words, the encoded + * binary is canonical and thus comparable to another encoded binary. + * + * Defaults to `false`. If enabled, it spends more time in encoding objects. + */ + sortKeys: boolean; + /** + * If `true`, non-integer numbers are encoded in float32, not in float64 (the default). + * + * Only use it if precisions don't matter. + * + * Defaults to `false`. + */ + forceFloat32: boolean; + + /** + * If `true`, an object property with `undefined` value are ignored. + * e.g. `{ foo: undefined }` will be encoded as `{}`, as `JSON.stringify()` does. + * + * Defaults to `false`. If enabled, it spends more time in encoding objects. + */ + ignoreUndefined: boolean; + + /** + * If `true`, integer numbers are encoded as floating point numbers, + * with the `forceFloat32` option taken into account. + * + * Defaults to `false`. + */ + forceIntegerToFloat: boolean; + }> +> & ContextOf; + export class Encoder { - private pos = 0; - private view = new DataView(new ArrayBuffer(this.initialBufferSize)); - private bytes = new Uint8Array(this.view.buffer); - - public constructor( - private readonly extensionCodec: ExtensionCodecType = ExtensionCodec.defaultCodec as any, - private readonly context: ContextType = undefined as any, - private readonly useBigInt64 = false, - private readonly maxDepth = DEFAULT_MAX_DEPTH, - private readonly initialBufferSize = DEFAULT_INITIAL_BUFFER_SIZE, - private readonly sortKeys = false, - private readonly forceFloat32 = false, - private readonly ignoreUndefined = false, - private readonly forceIntegerToFloat = false, - ) {} + private readonly extensionCodec: ExtensionCodecType; + private readonly context: ContextType; + private readonly useBigInt64: boolean; + private readonly maxDepth: number; + private readonly initialBufferSize: number; + private readonly sortKeys: boolean; + private readonly forceFloat32: boolean; + private readonly ignoreUndefined: boolean; + private readonly forceIntegerToFloat: boolean; + + private pos: number; + private view: DataView; + private bytes: Uint8Array; + + public constructor(options?: EncoderOptions) { + this.extensionCodec = options?.extensionCodec ?? (ExtensionCodec.defaultCodec as ExtensionCodecType); + this.context = (options as { context: ContextType } | undefined)?.context as ContextType; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined + + this.useBigInt64 = options?.useBigInt64 ?? false; + this.maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH; + this.initialBufferSize = options?.initialBufferSize ?? DEFAULT_INITIAL_BUFFER_SIZE; + this.sortKeys = options?.sortKeys ?? false; + this.forceFloat32 = options?.forceFloat32 ?? false; + this.ignoreUndefined = options?.ignoreUndefined ?? false; + this.forceIntegerToFloat = options?.forceIntegerToFloat ?? false; + + this.pos = 0; + this.view = new DataView(new ArrayBuffer(this.initialBufferSize)); + this.bytes = new Uint8Array(this.view.buffer); + } private reinitializeState() { this.pos = 0; diff --git a/src/decode.ts b/src/decode.ts index 03c78f6b..9398f743 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -1,55 +1,16 @@ import { Decoder } from "./Decoder"; -import type { ExtensionCodecType } from "./ExtensionCodec"; -import type { ContextOf, SplitUndefined } from "./context"; +import type { DecoderOptions } from "./Decoder"; +import type { SplitUndefined } from "./context"; -export type DecodeOptions = Readonly< - Partial<{ - extensionCodec: ExtensionCodecType; - - /** - * Decodes Int64 and Uint64 as bigint if it's set to true. - * Depends on ES2020's {@link DataView#getBigInt64} and - * {@link DataView#getBigUint64}. - * - * Defaults to false. - */ - useBigInt64: boolean; - - /** - * Maximum string length. - * - * Defaults to 4_294_967_295 (UINT32_MAX). - */ - maxStrLength: number; - /** - * Maximum binary length. - * - * Defaults to 4_294_967_295 (UINT32_MAX). - */ - maxBinLength: number; - /** - * Maximum array length. - * - * Defaults to 4_294_967_295 (UINT32_MAX). - */ - maxArrayLength: number; - /** - * Maximum map length. - * - * Defaults to 4_294_967_295 (UINT32_MAX). - */ - maxMapLength: number; - /** - * Maximum extension length. - * - * Defaults to 4_294_967_295 (UINT32_MAX). - */ - maxExtLength: number; - }> -> & - ContextOf; +/** + * @deprecated Use {@link DecoderOptions} instead. + */ +export type DecodeOptions = never; -export const defaultDecodeOptions: DecodeOptions = {}; +/** + * @deprecated No longer supported. + */ +export const defaultDecodeOptions: never = undefined as never; /** * It decodes a single MessagePack object in a buffer. @@ -62,18 +23,9 @@ export const defaultDecodeOptions: DecodeOptions = {}; */ export function decode( buffer: ArrayLike | BufferSource, - options: DecodeOptions> = defaultDecodeOptions as any, + options?: DecoderOptions>, ): unknown { - const decoder = new Decoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxStrLength, - options.maxBinLength, - options.maxArrayLength, - options.maxMapLength, - options.maxExtLength, - ); + const decoder = new Decoder(options); return decoder.decode(buffer); } @@ -86,17 +38,8 @@ export function decode( */ export function decodeMulti( buffer: ArrayLike | BufferSource, - options: DecodeOptions> = defaultDecodeOptions as any, + options?: DecoderOptions>, ): Generator { - const decoder = new Decoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxStrLength, - options.maxBinLength, - options.maxArrayLength, - options.maxMapLength, - options.maxExtLength, - ); + const decoder = new Decoder(options); return decoder.decodeMulti(buffer); } diff --git a/src/decodeAsync.ts b/src/decodeAsync.ts index 9ec8f2c9..1cdb901e 100644 --- a/src/decodeAsync.ts +++ b/src/decodeAsync.ts @@ -1,30 +1,19 @@ import { Decoder } from "./Decoder"; import { ensureAsyncIterable } from "./utils/stream"; -import { defaultDecodeOptions } from "./decode"; +import type { DecoderOptions } from "./Decoder"; import type { ReadableStreamLike } from "./utils/stream"; -import type { DecodeOptions } from "./decode"; import type { SplitUndefined } from "./context"; /** * @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty. * @throws {@link DecodeError} if the buffer contains invalid data. */ - export async function decodeAsync( + export async function decodeAsync( streamLike: ReadableStreamLike | BufferSource>, - options: DecodeOptions> = defaultDecodeOptions as any, + options?: DecoderOptions>, ): Promise { const stream = ensureAsyncIterable(streamLike); - - const decoder = new Decoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxStrLength, - options.maxBinLength, - options.maxArrayLength, - options.maxMapLength, - options.maxExtLength, - ); + const decoder = new Decoder(options); return decoder.decodeAsync(stream); } @@ -34,21 +23,10 @@ import type { SplitUndefined } from "./context"; */ export function decodeArrayStream( streamLike: ReadableStreamLike | BufferSource>, - options: DecodeOptions> = defaultDecodeOptions as any, + options?: DecoderOptions>, ): AsyncGenerator { const stream = ensureAsyncIterable(streamLike); - - const decoder = new Decoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxStrLength, - options.maxBinLength, - options.maxArrayLength, - options.maxMapLength, - options.maxExtLength, - ); - + const decoder = new Decoder(options); return decoder.decodeArrayStream(stream); } @@ -58,30 +36,14 @@ import type { SplitUndefined } from "./context"; */ export function decodeMultiStream( streamLike: ReadableStreamLike | BufferSource>, - options: DecodeOptions> = defaultDecodeOptions as any, + options?: DecoderOptions>, ): AsyncGenerator { const stream = ensureAsyncIterable(streamLike); - - const decoder = new Decoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxStrLength, - options.maxBinLength, - options.maxArrayLength, - options.maxMapLength, - options.maxExtLength, - ); - + const decoder = new Decoder(options); return decoder.decodeStream(stream); } /** * @deprecated Use {@link decodeMultiStream()} instead. */ -export function decodeStream( - streamLike: ReadableStreamLike | BufferSource>, - options: DecodeOptions> = defaultDecodeOptions as any, -): AsyncGenerator { - return decodeMultiStream(streamLike, options); -} +export const decodeStream: never = undefined as never; diff --git a/src/encode.ts b/src/encode.ts index 898dd840..581c928c 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -1,71 +1,16 @@ import { Encoder } from "./Encoder"; -import type { ExtensionCodecType } from "./ExtensionCodec"; -import type { ContextOf, SplitUndefined } from "./context"; +import type { EncoderOptions } from "./Encoder"; +import type { SplitUndefined } from "./context"; -export type EncodeOptions = Partial< - Readonly<{ - extensionCodec: ExtensionCodecType; - - /** - * Encodes bigint as Int64 or Uint64 if it's set to true. - * {@link forceIntegerToFloat} does not affect bigint. - * Depends on ES2020's {@link DataView#setBigInt64} and - * {@link DataView#setBigUint64}. - * - * Defaults to false. - */ - useBigInt64: boolean; - - /** - * The maximum depth in nested objects and arrays. - * - * Defaults to 100. - */ - maxDepth: number; - - /** - * The initial size of the internal buffer. - * - * Defaults to 2048. - */ - initialBufferSize: number; - - /** - * If `true`, the keys of an object is sorted. In other words, the encoded - * binary is canonical and thus comparable to another encoded binary. - * - * Defaults to `false`. If enabled, it spends more time in encoding objects. - */ - sortKeys: boolean; - /** - * If `true`, non-integer numbers are encoded in float32, not in float64 (the default). - * - * Only use it if precisions don't matter. - * - * Defaults to `false`. - */ - forceFloat32: boolean; - - /** - * If `true`, an object property with `undefined` value are ignored. - * e.g. `{ foo: undefined }` will be encoded as `{}`, as `JSON.stringify()` does. - * - * Defaults to `false`. If enabled, it spends more time in encoding objects. - */ - ignoreUndefined: boolean; - - /** - * If `true`, integer numbers are encoded as floating point numbers, - * with the `forceFloat32` option taken into account. - * - * Defaults to `false`. - */ - forceIntegerToFloat: boolean; - }> -> & - ContextOf; +/** + * @deprecated Use {@link EncoderOptions} instead. + */ +export type EncodeOptions = never; -const defaultEncodeOptions: EncodeOptions = {}; +/** + * @deprecated No longer supported. + */ +export const defaultEncodeOptions: never = undefined as never; /** * It encodes `value` in the MessagePack format and @@ -75,18 +20,8 @@ const defaultEncodeOptions: EncodeOptions = {}; */ export function encode( value: unknown, - options: EncodeOptions> = defaultEncodeOptions as any, + options?: EncoderOptions>, ): Uint8Array { - const encoder = new Encoder( - options.extensionCodec, - (options as typeof options & { context: any }).context, - options.useBigInt64, - options.maxDepth, - options.initialBufferSize, - options.sortKeys, - options.forceFloat32, - options.ignoreUndefined, - options.forceIntegerToFloat, - ); + const encoder = new Encoder(options); return encoder.encodeSharedRef(value); } diff --git a/src/index.ts b/src/index.ts index 28560f1b..b4765525 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,13 +14,18 @@ import { decodeAsync, decodeArrayStream, decodeMultiStream, decodeStream } from export { decodeAsync, decodeArrayStream, decodeMultiStream, decodeStream }; import { Decoder, DataViewIndexOutOfBoundsError } from "./Decoder"; +export { Decoder, DataViewIndexOutOfBoundsError }; +import type { DecoderOptions } from "./Decoder"; +export type { DecoderOptions }; import { DecodeError } from "./DecodeError"; -export { Decoder, DecodeError, DataViewIndexOutOfBoundsError }; +export { DecodeError }; import { Encoder } from "./Encoder"; export { Encoder }; +import type { EncoderOptions } from "./Encoder"; +export type { EncoderOptions }; -// Utilitiies for Extension Types: +// Utilities for Extension Types: import { ExtensionCodec } from "./ExtensionCodec"; export { ExtensionCodec }; diff --git a/test/decode-max-length.test.ts b/test/decode-max-length.test.ts index f3774eef..7ee2e33a 100644 --- a/test/decode-max-length.test.ts +++ b/test/decode-max-length.test.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { encode, decode, decodeAsync } from "../src"; -import type { DecodeOptions } from "../src/decode"; +import type { DecoderOptions } from "../src"; describe("decode with max${Type}Length specified", () => { async function* createStream(input: T) { @@ -9,7 +9,7 @@ describe("decode with max${Type}Length specified", () => { context("maxStrLength", () => { const input = encode("foo"); - const options: DecodeOptions = { maxStrLength: 1 }; + const options = { maxStrLength: 1 } satisfies DecoderOptions; it("throws errors (synchronous)", () => { assert.throws(() => { @@ -26,7 +26,7 @@ describe("decode with max${Type}Length specified", () => { context("maxBinLength", () => { const input = encode(Uint8Array.from([1, 2, 3])); - const options: DecodeOptions = { maxBinLength: 1 }; + const options = { maxBinLength: 1 } satisfies DecoderOptions; it("throws errors (synchronous)", () => { assert.throws(() => { @@ -43,7 +43,7 @@ describe("decode with max${Type}Length specified", () => { context("maxArrayLength", () => { const input = encode([1, 2, 3]); - const options: DecodeOptions = { maxArrayLength: 1 }; + const options = { maxArrayLength: 1 } satisfies DecoderOptions; it("throws errors (synchronous)", () => { assert.throws(() => { @@ -60,7 +60,7 @@ describe("decode with max${Type}Length specified", () => { context("maxMapLength", () => { const input = encode({ foo: 1, bar: 1, baz: 3 }); - const options: DecodeOptions = { maxMapLength: 1 }; + const options = { maxMapLength: 1 } satisfies DecoderOptions; it("throws errors (synchronous)", () => { assert.throws(() => { @@ -78,7 +78,7 @@ describe("decode with max${Type}Length specified", () => { context("maxExtType", () => { const input = encode(new Date()); // timextamp ext requires at least 4 bytes. - const options: DecodeOptions = { maxExtLength: 1 }; + const options = { maxExtLength: 1 } satisfies DecoderOptions; it("throws errors (synchronous)", () => { assert.throws(() => {