@@ -52,6 +52,13 @@ export type EncoderOptions<ContextType = undefined> = Partial<
52
52
*/
53
53
forceFloat32 : boolean ;
54
54
55
+ /**
56
+ * If `true`, numeric map keys will be encoded as ints/floats (as appropriate) rather than strings (the default).
57
+ *
58
+ * Defaults to `false`.
59
+ */
60
+ forceNumericMapKeys : boolean ;
61
+
55
62
/**
56
63
* If `true`, an object property with `undefined` value are ignored.
57
64
* e.g. `{ foo: undefined }` will be encoded as `{}`, as `JSON.stringify()` does.
@@ -81,6 +88,7 @@ export class Encoder<ContextType = undefined> {
81
88
private readonly forceFloat32 : boolean ;
82
89
private readonly ignoreUndefined : boolean ;
83
90
private readonly forceIntegerToFloat : boolean ;
91
+ private readonly forceNumericMapKeys : boolean ;
84
92
85
93
private pos : number ;
86
94
private view : DataView ;
@@ -97,6 +105,7 @@ export class Encoder<ContextType = undefined> {
97
105
this . forceFloat32 = options ?. forceFloat32 ?? false ;
98
106
this . ignoreUndefined = options ?. ignoreUndefined ?? false ;
99
107
this . forceIntegerToFloat = options ?. forceIntegerToFloat ?? false ;
108
+ this . forceNumericMapKeys = options ?. forceNumericMapKeys ?? false ;
100
109
101
110
this . pos = 0 ;
102
111
this . view = new DataView ( new ArrayBuffer ( this . initialBufferSize ) ) ;
@@ -362,13 +371,23 @@ export class Encoder<ContextType = undefined> {
362
371
return count ;
363
372
}
364
373
374
+ private isNumber ( value : string | number ) {
375
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
376
+ return ! isNaN ( value as any ) && ! isNaN ( parseFloat ( value as any ) ) ;
377
+ }
378
+
365
379
private encodeMap ( object : Record < string , unknown > , depth : number ) {
366
- const keys = Object . keys ( object ) ;
380
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
381
+ const keys = Object . keys ( object ) . map ( ( key ) => ( this . forceNumericMapKeys && this . isNumber ( key ) ? Number ( key ) : key ) ) ;
367
382
if ( this . sortKeys ) {
368
- keys . sort ( ) ;
383
+ if ( keys . filter ( ( k ) => typeof k === "number" ) . length > 0 ) {
384
+ keys . sort ( ) . sort ( ( a , b ) => + a - + b ) ;
385
+ } else {
386
+ keys . sort ( ) ;
387
+ }
369
388
}
370
389
371
- const size = this . ignoreUndefined ? this . countWithoutUndefined ( object , keys ) : keys . length ;
390
+ const size = this . ignoreUndefined ? this . countWithoutUndefined ( object , Object . keys ( object ) ) : keys . length ;
372
391
373
392
if ( size < 16 ) {
374
393
// fixmap
@@ -389,7 +408,11 @@ export class Encoder<ContextType = undefined> {
389
408
const value = object [ key ] ;
390
409
391
410
if ( ! ( this . ignoreUndefined && value === undefined ) ) {
392
- this . encodeString ( key ) ;
411
+ if ( typeof key === "string" ) {
412
+ this . encodeString ( key ) ;
413
+ } else {
414
+ this . encodeNumber ( key ) ;
415
+ }
393
416
this . doEncode ( value , depth + 1 ) ;
394
417
}
395
418
}
0 commit comments