@@ -53,6 +53,13 @@ export type EncoderOptions<ContextType = undefined> = Partial<
53
53
*/
54
54
forceFloat32 : boolean ;
55
55
56
+ /**
57
+ * If `true`, numeric map keys will be encoded as ints/floats (as appropriate) rather than strings (the default).
58
+ *
59
+ * Defaults to `false`.
60
+ */
61
+ forceNumericMapKeys : boolean ;
62
+
56
63
/**
57
64
* If `true`, an object property with `undefined` value are ignored.
58
65
* e.g. `{ foo: undefined }` will be encoded as `{}`, as `JSON.stringify()` does.
@@ -82,6 +89,7 @@ export class Encoder<ContextType = undefined> {
82
89
private readonly forceFloat32 : boolean ;
83
90
private readonly ignoreUndefined : boolean ;
84
91
private readonly forceIntegerToFloat : boolean ;
92
+ private readonly forceNumericMapKeys : boolean ;
85
93
86
94
private pos : number ;
87
95
private view : DataView ;
@@ -98,6 +106,7 @@ export class Encoder<ContextType = undefined> {
98
106
this . forceFloat32 = options ?. forceFloat32 ?? false ;
99
107
this . ignoreUndefined = options ?. ignoreUndefined ?? false ;
100
108
this . forceIntegerToFloat = options ?. forceIntegerToFloat ?? false ;
109
+ this . forceNumericMapKeys = options ?. forceNumericMapKeys ?? false ;
101
110
102
111
this . pos = 0 ;
103
112
this . view = new DataView ( new ArrayBuffer ( this . initialBufferSize ) ) ;
@@ -383,13 +392,23 @@ export class Encoder<ContextType = undefined> {
383
392
return count ;
384
393
}
385
394
395
+ private isNumber ( value : string | number ) {
396
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
397
+ return ! isNaN ( value as any ) && ! isNaN ( parseFloat ( value as any ) ) ;
398
+ }
399
+
386
400
private encodeMap ( object : Record < string , unknown > , depth : number ) {
387
- const keys = Object . keys ( object ) ;
401
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
402
+ const keys = Object . keys ( object ) . map ( ( key ) => ( this . forceNumericMapKeys && this . isNumber ( key ) ? Number ( key ) : key ) ) ;
388
403
if ( this . sortKeys ) {
389
- keys . sort ( ) ;
404
+ if ( keys . filter ( ( k ) => typeof k === "number" ) . length > 0 ) {
405
+ keys . sort ( ) . sort ( ( a , b ) => + a - + b ) ;
406
+ } else {
407
+ keys . sort ( ) ;
408
+ }
390
409
}
391
410
392
- const size = this . ignoreUndefined ? this . countWithoutUndefined ( object , keys ) : keys . length ;
411
+ const size = this . ignoreUndefined ? this . countWithoutUndefined ( object , Object . keys ( object ) ) : keys . length ;
393
412
394
413
if ( size < 16 ) {
395
414
// fixmap
@@ -410,7 +429,11 @@ export class Encoder<ContextType = undefined> {
410
429
const value = object [ key ] ;
411
430
412
431
if ( ! ( this . ignoreUndefined && value === undefined ) ) {
413
- this . encodeString ( key ) ;
432
+ if ( typeof key === "string" ) {
433
+ this . encodeString ( key ) ;
434
+ } else {
435
+ this . encodeNumber ( key ) ;
436
+ }
414
437
this . doEncode ( value , depth + 1 ) ;
415
438
}
416
439
}
0 commit comments