Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 59057ee

Browse filesBrowse files
Pejman NikramPejman Nikram
Pejman Nikram
authored and
Pejman Nikram
committed
adding support for nonstandard map key in the decoder
fix #255
1 parent 588354f commit 59057ee
Copy full SHA for 59057ee

File tree

Expand file treeCollapse file tree

3 files changed

+44
-17
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+44
-17
lines changed

‎README.md

Copy file name to clipboardExpand all lines: README.md
+14-11Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,20 @@ NodeJS `Buffer` is also acceptable because it is a subclass of `Uint8Array`.
145145

146146
#### `DecoderOptions`
147147

148-
| Name | Type | Default |
149-
| -------------- | -------------- | ----------------------------- |
150-
| extensionCodec | ExtensionCodec | `ExtensionCodec.defaultCodec` |
151-
| context | user-defined | - |
152-
| useBigInt64 | boolean | false |
153-
| rawStrings | boolean | false |
154-
| maxStrLength | number | `4_294_967_295` (UINT32_MAX) |
155-
| maxBinLength | number | `4_294_967_295` (UINT32_MAX) |
156-
| maxArrayLength | number | `4_294_967_295` (UINT32_MAX) |
157-
| maxMapLength | number | `4_294_967_295` (UINT32_MAX) |
158-
| maxExtLength | number | `4_294_967_295` (UINT32_MAX) |
148+
| Name | Type | Default |
149+
| --------------- | ------------------- | ---------------------------------------------- |
150+
| extensionCodec | ExtensionCodec | `ExtensionCodec.defaultCodec` |
151+
| context | user-defined | - |
152+
| useBigInt64 | boolean | false |
153+
| rawStrings | boolean | false |
154+
| maxStrLength | number | `4_294_967_295` (UINT32_MAX) |
155+
| maxBinLength | number | `4_294_967_295` (UINT32_MAX) |
156+
| maxArrayLength | number | `4_294_967_295` (UINT32_MAX) |
157+
| maxMapLength | number | `4_294_967_295` (UINT32_MAX) |
158+
| maxExtLength | number | `4_294_967_295` (UINT32_MAX) |
159+
| mapKeyConverter | MapKeyConverterType | throw exception if key is not string or number |
160+
161+
`MapKeyConverterType` is defined as `(key: unknown) => string | number`.
159162

160163
To skip UTF-8 decoding of strings, `rawStrings` can be set to `true`. In this case, strings are decoded into `Uint8Array`.
161164

‎src/Decoder.ts

Copy file name to clipboardExpand all lines: src/Decoder.ts
+15-6Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ export type DecoderOptions<ContextType = undefined> = Readonly<
6868
* `null` is a special value to disable the use of the key decoder at all.
6969
*/
7070
keyDecoder: KeyDecoder | null;
71+
72+
/**
73+
* A function to convert decoded map key to a valid JS key type.
74+
*
75+
* Defaults to a function that throws an error if the key is not a string or a number.
76+
*/
77+
mapKeyConverter: (key: unknown) => MapKeyType;
7178
}>
7279
> &
7380
ContextOf<ContextType>;
@@ -78,8 +85,11 @@ const STATE_MAP_VALUE = "map_value";
7885

7986
type MapKeyType = string | number;
8087

81-
const isValidMapKeyType = (key: unknown): key is MapKeyType => {
82-
return typeof key === "string" || typeof key === "number";
88+
const mapKeyConverter = (key: unknown): MapKeyType => {
89+
if (typeof key === "string" || typeof key === "number") {
90+
return key;
91+
}
92+
throw new DecodeError("The type of key must be string or number but " + typeof key);
8393
};
8494

8595
type StackMapState = {
@@ -213,6 +223,7 @@ export class Decoder<ContextType = undefined> {
213223
private readonly maxMapLength: number;
214224
private readonly maxExtLength: number;
215225
private readonly keyDecoder: KeyDecoder | null;
226+
private readonly mapKeyConverter: (key: unknown) => MapKeyType;
216227

217228
private totalPos = 0;
218229
private pos = 0;
@@ -236,6 +247,7 @@ export class Decoder<ContextType = undefined> {
236247
this.maxMapLength = options?.maxMapLength ?? UINT32_MAX;
237248
this.maxExtLength = options?.maxExtLength ?? UINT32_MAX;
238249
this.keyDecoder = options?.keyDecoder !== undefined ? options.keyDecoder : sharedCachedKeyDecoder;
250+
this.mapKeyConverter = options?.mapKeyConverter ?? mapKeyConverter;
239251
}
240252

241253
private clone(): Decoder<ContextType> {
@@ -631,14 +643,11 @@ export class Decoder<ContextType = undefined> {
631643
continue DECODE;
632644
}
633645
} else if (state.type === STATE_MAP_KEY) {
634-
if (!isValidMapKeyType(object)) {
635-
throw new DecodeError("The type of key must be string or number but " + typeof object);
636-
}
637646
if (object === "__proto__") {
638647
throw new DecodeError("The key __proto__ is not allowed");
639648
}
640649

641-
state.key = object;
650+
state.key = this.mapKeyConverter(object);
642651
state.type = STATE_MAP_VALUE;
643652
continue DECODE;
644653
} else {

‎test/decodeAsync.test.ts

Copy file name to clipboardExpand all lines: test/decodeAsync.test.ts
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ describe("decodeAsync", () => {
3636
assert.deepStrictEqual(object, { "foo": "bar" });
3737
});
3838

39+
it("decodes fixmap {'[1, 2]': 'baz'} with custom map key converter", async () => {
40+
const createStream = async function* () {
41+
yield [0x81]; // fixmap size=1
42+
yield encode([1, 2]);
43+
yield encode("baz");
44+
};
45+
46+
const object = await decodeAsync(createStream(), {
47+
mapKeyConverter: (key) => JSON.stringify(key),
48+
});
49+
50+
const key = JSON.stringify([1, 2]);
51+
assert.deepStrictEqual(object, { [key]: "baz" });
52+
});
53+
3954
it("decodes multi-byte integer byte-by-byte", async () => {
4055
const createStream = async function* () {
4156
yield [0xcd]; // uint 16

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.