3
3
get_type ,
4
4
is_plain_object ,
5
5
is_primitive ,
6
- stringify_primitive
6
+ stringify_string
7
7
} from './utils.js' ;
8
8
9
9
const UNDEFINED = - 1 ;
@@ -19,14 +19,16 @@ const NEGATIVE_ZERO = -6;
19
19
*/
20
20
export function stringify ( value ) {
21
21
/** @type {any[] } */
22
- const array = [ ] ;
22
+ const stringified = [ ] ;
23
23
24
24
/** @type {Map<any, number> } */
25
25
const map = new Map ( ) ;
26
26
27
27
/** @type {string[] } */
28
28
const keys = [ ] ;
29
29
30
+ let p = 0 ;
31
+
30
32
/** @param {any } thing */
31
33
function flatten ( thing ) {
32
34
if ( map . has ( thing ) ) return map . get ( thing ) ;
@@ -37,42 +39,43 @@ export function stringify(value) {
37
39
if ( thing === - Infinity ) return NEGATIVE_INFINITY ;
38
40
if ( thing === 0 && 1 / thing < 0 ) return NEGATIVE_ZERO ;
39
41
40
- const index = array . length ;
42
+ const index = p ++ ;
41
43
map . set ( thing , index ) ;
42
44
43
45
if ( typeof thing === 'function' ) {
44
46
throw new DevalueError ( `Cannot stringify a function` , keys ) ;
45
47
}
46
48
47
49
if ( is_primitive ( thing ) ) {
48
- array . push ( thing ) ;
50
+ stringified [ index ] = stringify_primitive ( thing ) ;
49
51
} else {
50
52
const type = get_type ( thing ) ;
51
53
52
54
switch ( type ) {
53
55
case 'Number' :
54
56
case 'String' :
55
57
case 'Boolean' :
56
- array . push ( [ ' Object' , thing ] ) ;
58
+ stringified [ index ] = `[" Object", ${ stringify_primitive ( thing ) } ]` ;
57
59
break ;
58
60
59
61
case 'BigInt' :
60
- array . push ( [ ' BigInt' , thing . toString ( ) ] ) ;
62
+ stringified [ index ] = `[" BigInt", ${ thing } ]` ;
61
63
break ;
62
64
63
65
case 'Date' :
64
- array . push ( [ ' Date' , thing . toISOString ( ) ] ) ;
66
+ stringified [ index ] = `[" Date"," ${ thing . toISOString ( ) } "]` ;
65
67
break ;
66
68
67
69
case 'RegExp' :
68
70
const { source, flags } = thing ;
69
- array . push ( flags ? [ 'RegExp' , source , flags ] : [ 'RegExp' , source ] ) ;
71
+ stringified [ index ] = flags
72
+ ? `["RegExp",${ stringify_string ( source ) } ,"${ flags } "]`
73
+ : `["RegExp",${ stringify_string ( source ) } ]` ;
70
74
break ;
71
75
72
76
case 'Array' :
73
77
/** @type {number[] } */
74
- const flattened_array = [ ] ;
75
- array . push ( flattened_array ) ;
78
+ let flattened_array = [ ] ;
76
79
77
80
for ( let i = 0 ; i < thing . length ; i += 1 ) {
78
81
if ( i in thing ) {
@@ -84,29 +87,33 @@ export function stringify(value) {
84
87
}
85
88
}
86
89
90
+ stringified [ index ] = `[${ flattened_array . join ( ',' ) } ]` ;
91
+
87
92
break ;
88
93
89
94
case 'Set' :
90
- /** @type {any[] } */
91
- const flattened_set = [ 'Set' , [ ] ] ;
92
- array . push ( flattened_set ) ;
95
+ /** @type {number[] } */
96
+ const flattened_set = [ ] ;
93
97
94
98
for ( const value of thing ) {
95
- flattened_set [ 1 ] . push ( flatten ( value ) ) ;
99
+ flattened_set . push ( flatten ( value ) ) ;
96
100
}
101
+
102
+ stringified [ index ] = `["Set",[${ flattened_set . join ( ',' ) } ]]` ;
97
103
break ;
98
104
99
105
case 'Map' :
100
- /** @type {any[] } */
101
- const flattened_map = [ 'Map' , [ ] ] ;
102
- array . push ( flattened_map ) ;
106
+ /** @type {number[] } */
107
+ const flattened_map = [ ] ;
103
108
104
109
for ( const [ key , value ] of thing ) {
105
110
keys . push (
106
111
`.get(${ is_primitive ( key ) ? stringify_primitive ( key ) : '...' } )`
107
112
) ;
108
- flattened_map [ 1 ] . push ( flatten ( key ) , flatten ( value ) ) ;
113
+ flattened_map . push ( flatten ( key ) , flatten ( value ) ) ;
109
114
}
115
+
116
+ stringified [ index ] = `["Map",[${ flattened_map . join ( ',' ) } ]]` ;
110
117
break ;
111
118
112
119
default :
@@ -124,15 +131,22 @@ export function stringify(value) {
124
131
) ;
125
132
}
126
133
127
- /** @type {Record<string, any> } */
128
- const flattened_object = { } ;
129
- array . push ( flattened_object ) ;
134
+ /** @type {string[] } */
135
+ const flattened_object = [ ] ;
130
136
131
137
for ( const key in thing ) {
132
138
keys . push ( `.${ key } ` ) ;
133
- flattened_object [ key ] = flatten ( thing [ key ] ) ;
139
+ flattened_object . push (
140
+ `${ stringify_string ( key ) } :${ flatten ( thing [ key ] ) } `
141
+ ) ;
134
142
keys . pop ( ) ;
135
143
}
144
+
145
+ stringified [ index ] = `{${ flattened_object . join ( ',' ) } }` ;
146
+
147
+ if ( Object . getPrototypeOf ( thing ) === null ) {
148
+ stringified [ index ] = `["null",${ stringified [ index ] } ]` ;
149
+ }
136
150
}
137
151
}
138
152
@@ -144,5 +158,19 @@ export function stringify(value) {
144
158
// special case — value is represented as a negative index
145
159
if ( index < 0 ) return `[${ index } ]` ;
146
160
147
- return JSON . stringify ( array ) ;
161
+ return `[${ stringified . join ( ',' ) } ]` ;
162
+ }
163
+
164
+ /**
165
+ * @param {any } thing
166
+ * @returns {string }
167
+ */
168
+ function stringify_primitive ( thing ) {
169
+ const type = typeof thing ;
170
+ if ( type === 'string' ) return stringify_string ( thing ) ;
171
+ if ( thing instanceof String ) return stringify_string ( thing . toString ( ) ) ;
172
+ if ( thing === void 0 ) return UNDEFINED . toString ( ) ;
173
+ if ( thing === 0 && 1 / thing < 0 ) return NEGATIVE_ZERO . toString ( ) ;
174
+ if ( type === 'bigint' ) return `["BigInt","${ thing } "]` ;
175
+ return String ( thing ) ;
148
176
}
0 commit comments