UNPKG

2.74 kBJavaScriptView Raw
1/*
2Copyright (c) 2014, Yahoo! Inc. All rights reserved.
3Copyrights licensed under the New BSD License.
4See the accompanying LICENSE file for terms.
5*/
6
7// Adapted from https://github.com/yahoo/serialize-javascript so that it is
8// deserializable as well and doesn't care about functions.
9
10var isRegExp = require('util').isRegExp;
11var stringify = require('json-stringify-safe');
12
13var PLACE_HOLDER_REGEXP = new RegExp('"@__(REGEXP){(\\d+)}@"', 'g');
14
15var UNSAFE_CHARS_REGEXP = /[<>\/\u2028\u2029]/g;
16
17// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
18// Unicode char counterparts which are safe to use in JavaScript strings.
19var UNICODE_CHARS = {
20 '<' : '\\u003C',
21 '>' : '\\u003E',
22 '/' : '\\u002F',
23 '\u2028': '\\u2028',
24 '\u2029': '\\u2029'
25};
26
27exports.serialize = function(obj) {
28 var regexps = [];
29 var str;
30
31 // Creates a JSON string representation of the object and uses placeholders
32 // for functions and regexps (identified by index) which are later
33 // replaced.
34 str = stringify(obj, function (key, value) {
35 if (typeof value === 'object' && isRegExp(value)) {
36 return '@__REGEXP{' + (regexps.push(value) - 1) + '}@';
37 }
38
39 return value;
40 });
41
42 // Protects against `JSON.stringify()` returning `undefined`, by serializing
43 // to the literal string: "undefined".
44 if (typeof str !== 'string') {
45 return String(str);
46 }
47
48 // Replace unsafe HTML and invalid JavaScript line terminator chars with
49 // their safe Unicode char counterpart. This _must_ happen before the
50 // regexps and functions are serialized and added back to the string.
51 str = str.replace(UNSAFE_CHARS_REGEXP, function (unsafeChar) {
52 return UNICODE_CHARS[unsafeChar];
53 });
54
55 if (regexps.length === 0) {
56 return str;
57 }
58
59 // Replaces all occurrences of function and regexp placeholders in the JSON
60 // string with their string representations. If the original value can not
61 // be found, then `undefined` is used.
62 return str.replace(PLACE_HOLDER_REGEXP, function (match, type, valueIndex) {
63 if (type === 'REGEXP') {
64 return JSON.stringify(serializeRegExp(regexps[valueIndex]));
65 }
66
67 return match;
68 }, 0, function() {});
69}
70
71exports.deserialize = function(string) {
72 return JSON.parse(string, function(key, value) {
73 if (Array.isArray(value) && value.length === 3 && value[0] === '@__REGEXP') {
74 return new RegExp(value[1], value[2]);
75 }
76
77 return value;
78 });
79};
80
81function serializeRegExp(regex) {
82 var flags = '';
83
84 if (regex.global) flags += 'g';
85 if (regex.ignoreCase) flags += 'i';
86 if (regex.multiline) flags += 'm';
87 if (regex.sticky) flags += 'y';
88 if (regex.unicode) flags += 'u';
89
90 return ['@__REGEXP', regex.source, flags];
91}
\No newline at end of file