Skip to content

Commit a81aaca

Browse files
Stuart RobinsonStuart Robinson
authored andcommitted
wip
1 parent 9e6b3f6 commit a81aaca

File tree

6 files changed

+254
-4
lines changed

6 files changed

+254
-4
lines changed

browserified/index.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

browserified/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2263,7 +2263,8 @@ function deleteFunctions(obj){
22632263
}
22642264
}
22652265

2266-
module.exports =
2266+
// module.exportsPRESERVED =
2267+
22672268
function serialize(obj, options) {
22682269
options || (options = {});
22692270

browserified/min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function deleteFunctions(obj){
5555
}
5656
}
5757

58+
// module.exportsPRESERVED =
5859
module.exports =
5960
function serialize(obj, options) {
6061
options || (options = {});

indexPrepared.js

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"benchmark": "node -v && node test/benchmark/serialize.js",
88
"test": "nyc --reporter=lcov mocha test/unit",
9-
"browserify": "browserify index.js | uglifyjs > browserified/min.js; browserify index.js -o browserified/index.js; "
9+
"browserify": "sed 's/module.exports =//g' index.js > indexPrepared.js; browserify indexPrepared.js | uglifyjs > browserified/min.js; browserify indexPrepared.js -o browserified/index.js; "
1010
},
1111
"repository": {
1212
"type": "git",

0 commit comments

Comments
 (0)