@@ -6,274 +6,10 @@ See the accompanying LICENSE file for terms.
6
6
7
7
'use strict' ;
8
8
9
- // Generate an internal UID to make the regexp pattern harder to guess.
10
- var UID_LENGTH = 16 ;
11
- var UID = generateUID ( ) ;
12
- var PLACE_HOLDER_REGEXP = new RegExp ( '(\\\\)?"@__(F|R|D|M|S|A|U|I|B|L)-' + UID + '-(\\d+)__@"' , 'g' ) ;
13
-
14
- var IS_NATIVE_CODE_REGEXP = / \{ \s * \[ n a t i v e c o d e \] \s * \} / g;
15
- var IS_PURE_FUNCTION = / f u n c t i o n .* ?\( / ;
16
- var IS_ARROW_FUNCTION = / .* ?= > .* ?/ ;
17
- var UNSAFE_CHARS_REGEXP = / [ < > \/ \u2028 \u2029 ] / g;
18
-
19
- var RESERVED_SYMBOLS = [ '*' , 'async' ] ;
20
-
21
- // Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
22
- // Unicode char counterparts which are safe to use in JavaScript strings.
23
- var ESCAPED_CHARS = {
24
- '<' : '\\u003C' ,
25
- '>' : '\\u003E' ,
26
- '/' : '\\u002F' ,
27
- '\u2028' : '\\u2028' ,
28
- '\u2029' : '\\u2029'
29
- } ;
30
-
31
- function escapeUnsafeChars ( unsafeChar ) {
32
- return ESCAPED_CHARS [ unsafeChar ] ;
33
- }
34
-
35
- function generateUID ( ) {
36
- var bytes ;
37
- if ( typeof crypto !== 'undefined' ) {
38
- bytes = crypto . getRandomValues ( new Uint8Array ( UID_LENGTH ) ) ;
39
- } else {
40
- try {
41
- var nodeCrypto = require ( 'crypto' ) ;
42
- bytes = nodeCrypto . randomBytes ( UID_LENGTH ) ;
43
- } catch {
44
- // We'll throw an error later
45
- }
46
- }
47
- if ( ! bytes ) {
48
- throw new Error ( 'Secure random number generation is not supported by this platform.' ) ;
49
- }
50
- var result = '' ;
51
- for ( var i = 0 ; i < UID_LENGTH ; ++ i ) {
52
- result += bytes [ i ] . toString ( 16 ) ;
53
- }
54
- return result ;
55
- }
56
-
57
- function deleteFunctions ( obj ) {
58
- var functionKeys = [ ] ;
59
- for ( var key in obj ) {
60
- if ( typeof obj [ key ] === "function" ) {
61
- functionKeys . push ( key ) ;
62
- }
63
- }
64
- for ( var i = 0 ; i < functionKeys . length ; i ++ ) {
65
- delete obj [ functionKeys [ i ] ] ;
66
- }
67
- }
68
-
69
- module . exports = function serialize ( obj , options ) {
70
- options || ( options = { } ) ;
71
-
72
- // Backwards-compatibility for `space` as the second argument.
73
- if ( typeof options === 'number' || typeof options === 'string' ) {
74
- options = { space : options } ;
75
- }
76
-
77
- var functions = [ ] ;
78
- var regexps = [ ] ;
79
- var dates = [ ] ;
80
- var maps = [ ] ;
81
- var sets = [ ] ;
82
- var arrays = [ ] ;
83
- var undefs = [ ] ;
84
- var infinities = [ ] ;
85
- var bigInts = [ ] ;
86
- var urls = [ ] ;
87
-
88
- // Returns placeholders for functions and regexps (identified by index)
89
- // which are later replaced by their string representation.
90
- function replacer ( key , value ) {
91
-
92
- // For nested function
93
- if ( options . ignoreFunction ) {
94
- deleteFunctions ( value ) ;
95
- }
96
-
97
- if ( ! value && value !== undefined && value !== BigInt ( 0 ) ) {
98
- return value ;
99
- }
100
-
101
- // If the value is an object w/ a toJSON method, toJSON is called before
102
- // the replacer runs, so we use this[key] to get the non-toJSONed value.
103
- var origValue = this [ key ] ;
104
- var type = typeof origValue ;
105
-
106
- if ( type === 'object' ) {
107
- if ( origValue instanceof RegExp ) {
108
- return '@__R-' + UID + '-' + ( regexps . push ( origValue ) - 1 ) + '__@' ;
109
- }
110
-
111
- if ( origValue instanceof Date ) {
112
- return '@__D-' + UID + '-' + ( dates . push ( origValue ) - 1 ) + '__@' ;
113
- }
114
-
115
- if ( origValue instanceof Map ) {
116
- return '@__M-' + UID + '-' + ( maps . push ( origValue ) - 1 ) + '__@' ;
117
- }
118
-
119
- if ( origValue instanceof Set ) {
120
- return '@__S-' + UID + '-' + ( sets . push ( origValue ) - 1 ) + '__@' ;
121
- }
122
-
123
- if ( origValue instanceof Array ) {
124
- var isSparse = origValue . filter ( function ( ) { return true } ) . length !== origValue . length ;
125
- if ( isSparse ) {
126
- return '@__A-' + UID + '-' + ( arrays . push ( origValue ) - 1 ) + '__@' ;
127
- }
128
- }
129
-
130
- if ( origValue instanceof URL ) {
131
- return '@__L-' + UID + '-' + ( urls . push ( origValue ) - 1 ) + '__@' ;
132
- }
133
- }
134
-
135
- if ( type === 'function' ) {
136
- return '@__F-' + UID + '-' + ( functions . push ( origValue ) - 1 ) + '__@' ;
137
- }
138
-
139
- if ( type === 'undefined' ) {
140
- return '@__U-' + UID + '-' + ( undefs . push ( origValue ) - 1 ) + '__@' ;
141
- }
142
-
143
- if ( type === 'number' && ! isNaN ( origValue ) && ! isFinite ( origValue ) ) {
144
- return '@__I-' + UID + '-' + ( infinities . push ( origValue ) - 1 ) + '__@' ;
145
- }
146
-
147
- if ( type === 'bigint' ) {
148
- return '@__B-' + UID + '-' + ( bigInts . push ( origValue ) - 1 ) + '__@' ;
149
- }
150
-
151
- return value ;
152
- }
9
+ var crypto = require ( 'crypto' ) ;
10
+ var createSerializer = require ( './lib' ) ;
153
11
154
- function serializeFunc ( fn ) {
155
- var serializedFn = fn . toString ( ) ;
156
- if ( IS_NATIVE_CODE_REGEXP . test ( serializedFn ) ) {
157
- throw new TypeError ( 'Serializing native function: ' + fn . name ) ;
158
- }
159
-
160
- // pure functions, example: {key: function() {}}
161
- if ( IS_PURE_FUNCTION . test ( serializedFn ) ) {
162
- return serializedFn ;
163
- }
164
-
165
- // arrow functions, example: arg1 => arg1+5
166
- if ( IS_ARROW_FUNCTION . test ( serializedFn ) ) {
167
- return serializedFn ;
168
- }
169
-
170
- var argsStartsAt = serializedFn . indexOf ( '(' ) ;
171
- var def = serializedFn . substr ( 0 , argsStartsAt )
172
- . trim ( )
173
- . split ( ' ' )
174
- . filter ( function ( val ) { return val . length > 0 } ) ;
175
-
176
- var nonReservedSymbols = def . filter ( function ( val ) {
177
- return RESERVED_SYMBOLS . indexOf ( val ) === - 1
178
- } ) ;
179
-
180
- // enhanced literal objects, example: {key() {}}
181
- if ( nonReservedSymbols . length > 0 ) {
182
- return ( def . indexOf ( 'async' ) > - 1 ? 'async ' : '' ) + 'function'
183
- + ( def . join ( '' ) . indexOf ( '*' ) > - 1 ? '*' : '' )
184
- + serializedFn . substr ( argsStartsAt ) ;
185
- }
186
-
187
- // arrow functions
188
- return serializedFn ;
189
- }
190
-
191
- // Check if the parameter is function
192
- if ( options . ignoreFunction && typeof obj === "function" ) {
193
- obj = undefined ;
194
- }
195
- // Protects against `JSON.stringify()` returning `undefined`, by serializing
196
- // to the literal string: "undefined".
197
- if ( obj === undefined ) {
198
- return String ( obj ) ;
199
- }
200
-
201
- var str ;
202
-
203
- // Creates a JSON string representation of the value.
204
- // NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
205
- if ( options . isJSON && ! options . space ) {
206
- str = JSON . stringify ( obj ) ;
207
- } else {
208
- str = JSON . stringify ( obj , options . isJSON ? null : replacer , options . space ) ;
209
- }
210
-
211
- // Protects against `JSON.stringify()` returning `undefined`, by serializing
212
- // to the literal string: "undefined".
213
- if ( typeof str !== 'string' ) {
214
- return String ( str ) ;
215
- }
216
-
217
- // Replace unsafe HTML and invalid JavaScript line terminator chars with
218
- // their safe Unicode char counterpart. This _must_ happen before the
219
- // regexps and functions are serialized and added back to the string.
220
- if ( options . unsafe !== true ) {
221
- str = str . replace ( UNSAFE_CHARS_REGEXP , escapeUnsafeChars ) ;
222
- }
223
-
224
- if ( functions . length === 0 && regexps . length === 0 && dates . length === 0 && maps . length === 0 && sets . length === 0 && arrays . length === 0 && undefs . length === 0 && infinities . length === 0 && bigInts . length === 0 && urls . length === 0 ) {
225
- return str ;
226
- }
227
-
228
- // Replaces all occurrences of function, regexp, date, map and set placeholders in the
229
- // JSON string with their string representations. If the original value can
230
- // not be found, then `undefined` is used.
231
- return str . replace ( PLACE_HOLDER_REGEXP , function ( match , backSlash , type , valueIndex ) {
232
- // The placeholder may not be preceded by a backslash. This is to prevent
233
- // replacing things like `"a\"@__R-<UID>-0__@"` and thus outputting
234
- // invalid JS.
235
- if ( backSlash ) {
236
- return match ;
237
- }
238
-
239
- if ( type === 'D' ) {
240
- return "new Date(\"" + dates [ valueIndex ] . toISOString ( ) + "\")" ;
241
- }
242
-
243
- if ( type === 'R' ) {
244
- return "new RegExp(" + serialize ( regexps [ valueIndex ] . source ) + ", \"" + regexps [ valueIndex ] . flags + "\")" ;
245
- }
246
-
247
- if ( type === 'M' ) {
248
- return "new Map(" + serialize ( Array . from ( maps [ valueIndex ] . entries ( ) ) , options ) + ")" ;
249
- }
250
-
251
- if ( type === 'S' ) {
252
- return "new Set(" + serialize ( Array . from ( sets [ valueIndex ] . values ( ) ) , options ) + ")" ;
253
- }
254
-
255
- if ( type === 'A' ) {
256
- return "Array.prototype.slice.call(" + serialize ( Object . assign ( { length : arrays [ valueIndex ] . length } , arrays [ valueIndex ] ) , options ) + ")" ;
257
- }
258
-
259
- if ( type === 'U' ) {
260
- return 'undefined'
261
- }
262
-
263
- if ( type === 'I' ) {
264
- return infinities [ valueIndex ] ;
265
- }
266
-
267
- if ( type === 'B' ) {
268
- return "BigInt(\"" + bigInts [ valueIndex ] + "\")" ;
269
- }
270
-
271
- if ( type === 'L' ) {
272
- return "new URL(" + serialize ( urls [ valueIndex ] . toString ( ) , options ) + ")" ;
273
- }
274
-
275
- var fn = functions [ valueIndex ] ;
12
+ // Generate an internal UID to make the regexp pattern harder to guess.
13
+ var UID_LENGTH = 16 ;
276
14
277
- return serializeFunc ( fn ) ;
278
- } ) ;
279
- }
15
+ module . exports = createSerializer ( crypto . randomBytes ( UID_LENGTH ) ) ;
0 commit comments