1
1
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$' ;
2
2
const reserved = / ^ (?: d o | i f | i n | f o r | i n t | l e t | n e w | t r y | v a r | b y t e | c a s e | c h a r | e l s e | e n u m | g o t o | l o n g | t h i s | v o i d | w i t h | a w a i t | b r e a k | c a t c h | c l a s s | c o n s t | f i n a l | f l o a t | s h o r t | s u p e r | t h r o w | w h i l e | y i e l d | d e l e t e | d o u b l e | e x p o r t | i m p o r t | n a t i v e | r e t u r n | s w i t c h | t h r o w s | t y p e o f | b o o l e a n | d e f a u l t | e x t e n d s | f i n a l l y | p a c k a g e | p r i v a t e | a b s t r a c t | c o n t i n u e | d e b u g g e r | f u n c t i o n | v o l a t i l e | i n t e r f a c e | p r o t e c t e d | t r a n s i e n t | i m p l e m e n t s | i n s t a n c e o f | s y n c h r o n i z e d ) $ / ;
3
- const unsafe = / [ < > \/ \u2028 \u2029 ] / g;
4
- const escaped : Record < string , string > = { '<' : '\\u003C' , '>' : '\\u003E' , '/' : '\\u002F' , '\u2028' : '\\u2028' , '\u2029' : '\\u2029' } ;
3
+ const escaped : Record < string , string > = {
4
+ '<' : '\\u003C' ,
5
+ '>' : '\\u003E' ,
6
+ '/' : '\\u002F' ,
7
+ '\\' : '\\\\' ,
8
+ '\b' : '\\b' ,
9
+ '\f' : '\\f' ,
10
+ '\n' : '\\n' ,
11
+ '\r' : '\\r' ,
12
+ '\t' : '\\t' ,
13
+ '\0' : '\\0' ,
14
+ '\u2028' : '\\u2028' ,
15
+ '\u2029' : '\\u2029'
16
+ } ;
5
17
const objectProtoOwnPropertyNames = Object . getOwnPropertyNames ( Object . prototype ) . sort ( ) . join ( '\0' ) ;
6
18
7
19
export default function devalue ( value : any ) {
8
20
const counts = new Map ( ) ;
9
21
10
- let n = 0 ;
11
-
12
22
function walk ( thing : any ) {
13
23
if ( typeof thing === 'function' ) {
14
24
throw new Error ( `Cannot stringify a function` ) ;
@@ -197,12 +207,8 @@ function isPrimitive(thing: any) {
197
207
return Object ( thing ) !== thing ;
198
208
}
199
209
200
- function escape ( char : string ) {
201
- return escaped [ char ] ;
202
- }
203
-
204
210
function stringifyPrimitive ( thing : any ) {
205
- if ( typeof thing === 'string' ) return JSON . stringify ( thing ) . replace ( unsafe , escape ) ;
211
+ if ( typeof thing === 'string' ) return stringifyString ( thing ) ;
206
212
if ( thing === void 0 ) return 'void 0' ;
207
213
if ( thing === 0 && 1 / thing < 0 ) return '-0' ;
208
214
const str = String ( thing ) ;
@@ -220,4 +226,34 @@ function safeKey(key: string) {
220
226
221
227
function safeProp ( key : string ) {
222
228
return / ^ [ _ $ a - z A - Z ] [ _ $ a - z A - Z 0 - 9 ] * $ / . test ( key ) ? `.${ key } ` : `[${ JSON . stringify ( key ) } ]` ;
229
+ }
230
+
231
+ function stringifyString ( str : string ) {
232
+ let result = '"' ;
233
+
234
+ for ( let i = 0 ; i < str . length ; i += 1 ) {
235
+ const char = str . charAt ( i ) ;
236
+ const code = char . charCodeAt ( 0 ) ;
237
+
238
+ if ( char === '"' ) {
239
+ result += '\\"' ;
240
+ } else if ( char in escaped ) {
241
+ result += escaped [ char ] ;
242
+ } else if ( code >= 0xd800 && code <= 0xdfff ) {
243
+ const next = str . charCodeAt ( i + 1 ) ;
244
+
245
+ // If this is the beginning of a [high, low] surrogate pair,
246
+ // add the next two characters, otherwise escape
247
+ if ( code <= 0xdbff && ( next >= 0xdc00 && next <= 0xdfff ) ) {
248
+ result += char + str [ ++ i ] ;
249
+ } else {
250
+ result += `\\u${ code . toString ( 16 ) . toUpperCase ( ) } ` ;
251
+ }
252
+ } else {
253
+ result += char ;
254
+ }
255
+ }
256
+
257
+ result += '"' ;
258
+ return result ;
223
259
}
0 commit comments