@@ -10,40 +10,69 @@ var isRegExp = require('util').isRegExp;
1010
1111// Generate an internal UID to make the regexp pattern harder to guess.
1212var UID = Math . floor ( Math . random ( ) * 0x10000000000 ) . toString ( 16 ) ;
13- var PLACE_HOLDER_REGEXP = new RegExp ( '"@__(FUNCTION|REGEXP )-' + UID + '-(\\d+)__@"' , 'g' ) ;
13+ var PLACE_HOLDER_REGEXP = new RegExp ( '"@__(F|R )-' + UID + '-(\\d+)__@"' , 'g' ) ;
1414
1515var IS_NATIVE_CODE_REGEXP = / \{ \s * \[ n a t i v e c o d e \] \s * \} / g;
1616var UNSAFE_CHARS_REGEXP = / [ < > \/ \u2028 \u2029 ] / g;
1717
1818// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
1919// Unicode char counterparts which are safe to use in JavaScript strings.
20- var UNICODE_CHARS = {
20+ var ESCAPED_CHARS = {
2121 '<' : '\\u003C' ,
2222 '>' : '\\u003E' ,
2323 '/' : '\\u002F' ,
2424 '\u2028' : '\\u2028' ,
2525 '\u2029' : '\\u2029'
2626} ;
2727
28- module . exports = function serialize ( obj , space ) {
28+ function escapeUnsafeChars ( unsafeChar ) {
29+ return ESCAPED_CHARS [ unsafeChar ] ;
30+ }
31+
32+ module . exports = function serialize ( obj , options ) {
33+ options || ( options = { } ) ;
34+
35+ // Backwards-compatability for `space` as the second argument.
36+ if ( typeof options === 'number' || typeof options === 'string' ) {
37+ options = { space : options } ;
38+ }
39+
2940 var functions = [ ] ;
3041 var regexps = [ ] ;
31- var str ;
3242
33- // Creates a JSON string representation of the object and uses placeholders
34- // for functions and regexps (identified by index) which are later
35- // replaced.
36- str = JSON . stringify ( obj , function ( key , value ) {
37- if ( typeof value === 'function' ) {
38- return '@__FUNCTION-' + UID + '-' + ( functions . push ( value ) - 1 ) + '__@' ;
43+ // Returns placeholders for functions and regexps (identified by index)
44+ // which are later replaced by their string representation.
45+ function replacer ( key , value ) {
46+ if ( ! value ) {
47+ return value ;
48+ }
49+
50+ var type = typeof value ;
51+
52+ if ( type === 'object' ) {
53+ if ( isRegExp ( value ) ) {
54+ return '@__R-' + UID + '-' + ( regexps . push ( value ) - 1 ) + '__@' ;
55+ }
56+
57+ return value ;
3958 }
4059
41- if ( typeof value === 'object' && isRegExp ( value ) ) {
42- return '@__REGEXP -' + UID + '-' + ( regexps . push ( value ) - 1 ) + '__@' ;
60+ if ( type === 'function' ) {
61+ return '@__F -' + UID + '-' + ( functions . push ( value ) - 1 ) + '__@' ;
4362 }
4463
4564 return value ;
46- } , space ) ;
65+ }
66+
67+ var str ;
68+
69+ // Creates a JSON string representation of the value.
70+ // NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
71+ if ( options . isJSON && ! options . space ) {
72+ str = JSON . stringify ( obj ) ;
73+ } else {
74+ str = JSON . stringify ( obj , options . isJSON ? null : replacer , options . space ) ;
75+ }
4776
4877 // Protects against `JSON.stringify()` returning `undefined`, by serializing
4978 // to the literal string: "undefined".
@@ -54,9 +83,7 @@ module.exports = function serialize(obj, space) {
5483 // Replace unsafe HTML and invalid JavaScript line terminator chars with
5584 // their safe Unicode char counterpart. This _must_ happen before the
5685 // regexps and functions are serialized and added back to the string.
57- str = str . replace ( UNSAFE_CHARS_REGEXP , function ( unsafeChar ) {
58- return UNICODE_CHARS [ unsafeChar ] ;
59- } ) ;
86+ str = str . replace ( UNSAFE_CHARS_REGEXP , escapeUnsafeChars ) ;
6087
6188 if ( functions . length === 0 && regexps . length === 0 ) {
6289 return str ;
@@ -66,7 +93,7 @@ module.exports = function serialize(obj, space) {
6693 // string with their string representations. If the original value can not
6794 // be found, then `undefined` is used.
6895 return str . replace ( PLACE_HOLDER_REGEXP , function ( match , type , valueIndex ) {
69- if ( type === 'REGEXP ' ) {
96+ if ( type === 'R ' ) {
7097 return regexps [ valueIndex ] . toString ( ) ;
7198 }
7299
0 commit comments