@@ -5,8 +5,7 @@ const escaped: Record<string, string> = { '<': '\\u003C', '>' : '\\u003E', '/':
5
5
const objectProtoOwnPropertyNames = Object . getOwnPropertyNames ( Object . prototype ) . sort ( ) . join ( '\0' ) ;
6
6
7
7
export default function devalue ( value : any ) {
8
- const repeated = new Map ( ) ;
9
- const seen = new Set ( ) ;
8
+ const counts = new Map ( ) ;
10
9
11
10
let n = 0 ;
12
11
@@ -15,12 +14,12 @@ export default function devalue(value: any) {
15
14
throw new Error ( `Cannot stringify a function` ) ;
16
15
}
17
16
18
- if ( seen . has ( thing ) ) {
19
- repeated . set ( thing , getName ( n ++ ) ) ;
17
+ if ( counts . has ( thing ) ) {
18
+ counts . set ( thing , counts . get ( thing ) + 1 ) ;
20
19
return ;
21
20
}
22
21
23
- seen . add ( thing ) ;
22
+ counts . set ( thing , 1 ) ;
24
23
25
24
if ( ! isPrimitive ( thing ) ) {
26
25
const type = getType ( thing ) ;
@@ -46,11 +45,11 @@ export default function devalue(value: any) {
46
45
const proto = Object . getPrototypeOf ( thing ) ;
47
46
48
47
if (
49
- proto !== Object . prototype &&
50
- proto !== null &&
51
- Object . getOwnPropertyNames ( proto ) . sort ( ) . join ( '\0' ) !== objectProtoOwnPropertyNames
48
+ proto !== Object . prototype &&
49
+ proto !== null &&
50
+ Object . getOwnPropertyNames ( proto ) . sort ( ) . join ( '\0' ) !== objectProtoOwnPropertyNames
52
51
) {
53
- throw new Error ( `Cannot stringify arbitrary non-POJOs` ) ;
52
+ throw new Error ( `Cannot stringify arbitrary non-POJOs` ) ;
54
53
}
55
54
56
55
if ( Object . getOwnPropertySymbols ( thing ) . length > 0 ) {
@@ -62,9 +61,20 @@ export default function devalue(value: any) {
62
61
}
63
62
}
64
63
64
+ walk ( value ) ;
65
+
66
+ const names = new Map ( ) ;
67
+
68
+ Array . from ( counts )
69
+ . filter ( entry => entry [ 1 ] > 1 )
70
+ . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] )
71
+ . forEach ( ( entry , i ) => {
72
+ names . set ( entry [ 0 ] , getName ( i ) ) ;
73
+ } ) ;
74
+
65
75
function stringify ( thing : any ) : string {
66
- if ( repeated . has ( thing ) ) {
67
- return repeated . get ( thing ) ;
76
+ if ( names . has ( thing ) ) {
77
+ return names . get ( thing ) ;
68
78
}
69
79
70
80
if ( isPrimitive ( thing ) ) {
@@ -107,15 +117,14 @@ export default function devalue(value: any) {
107
117
}
108
118
}
109
119
110
- walk ( value ) ;
111
120
const str = stringify ( value ) ;
112
121
113
- if ( repeated . size ) {
122
+ if ( names . size ) {
114
123
const params : string [ ] = [ ] ;
115
124
const statements : string [ ] = [ ] ;
116
125
const values : string [ ] = [ ] ;
117
126
118
- repeated . forEach ( ( name , thing ) => {
127
+ names . forEach ( ( name , thing ) => {
119
128
params . push ( name ) ;
120
129
121
130
if ( isPrimitive ( thing ) ) {
@@ -196,7 +205,9 @@ function stringifyPrimitive(thing: any) {
196
205
if ( typeof thing === 'string' ) return JSON . stringify ( thing ) . replace ( unsafe , escape ) ;
197
206
if ( thing === void 0 ) return 'void 0' ;
198
207
if ( thing === 0 && 1 / thing < 0 ) return '-0' ;
199
- return String ( thing ) ;
208
+ const str = String ( thing ) ;
209
+ if ( typeof thing === 'number' ) return str . replace ( / ^ ( - ) ? 0 \. / , '$1.' ) ;
210
+ return str ;
200
211
}
201
212
202
213
function getType ( thing : any ) {
0 commit comments