You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

404 lines
12 KiB

2 years ago
var escapeJsStr = require('./escapeJsStr');
var type = require('./type');
var toStr = require('./toStr');
var endWith = require('./endWith');
var toSrc = require('./toSrc');
var keys = require('./keys');
var each = require('./each');
var Class = require('./Class');
var getProto = require('./getProto');
var difference = require('./difference');
var extend = require('./extend');
var isPromise = require('./isPromise');
var filter = require('./filter');
var now = require('./now');
var allKeys = require('./allKeys');
var contain = require('./contain');
var isObj = require('./isObj');
var isMiniProgram = require('./isMiniProgram');
var create = require('./create');
var startWith = require('./startWith');
var safeSet = require('./safeSet');
var defineProp = require('./defineProp');
var pick = require('./pick');
var isArrLike = require('./isArrLike');
exports = function(obj) {
var _ref =
arguments.length > 1 && arguments[1] !== undefined
? arguments[1]
: {},
self = _ref.self,
_ref$startTime = _ref.startTime,
startTime = _ref$startTime === void 0 ? now() : _ref$startTime,
_ref$timeout = _ref.timeout,
timeout = _ref$timeout === void 0 ? 0 : _ref$timeout,
_ref$depth = _ref.depth,
depth = _ref$depth === void 0 ? 0 : _ref$depth,
_ref$curDepth = _ref.curDepth,
curDepth = _ref$curDepth === void 0 ? 1 : _ref$curDepth,
_ref$visitor = _ref.visitor,
visitor = _ref$visitor === void 0 ? new Visitor() : _ref$visitor,
_ref$unenumerable = _ref.unenumerable,
unenumerable = _ref$unenumerable === void 0 ? false : _ref$unenumerable,
_ref$symbol = _ref.symbol,
symbol = _ref$symbol === void 0 ? false : _ref$symbol,
_ref$accessGetter = _ref.accessGetter,
accessGetter = _ref$accessGetter === void 0 ? false : _ref$accessGetter,
_ref$ignore = _ref.ignore,
ignore = _ref$ignore === void 0 ? [] : _ref$ignore;
var json = '';
var options = {
visitor: visitor,
unenumerable: unenumerable,
symbol: symbol,
accessGetter: accessGetter,
depth: depth,
curDepth: curDepth + 1,
timeout: timeout,
startTime: startTime,
ignore: ignore
};
var t = type(obj, false);
if (t === 'String') {
json = wrapStr(obj);
} else if (t === 'Number') {
json = toStr(obj);
if (endWith(json, 'Infinity')) {
json = '{"value":"'.concat(json, '","type":"Number"}');
}
} else if (t === 'NaN') {
json = '{"value":"NaN","type":"Number"}';
} else if (t === 'Boolean') {
json = obj ? 'true' : 'false';
} else if (t === 'Null') {
json = 'null';
} else if (t === 'Undefined') {
json = '{"type":"Undefined"}';
} else if (t === 'Symbol') {
var val = 'Symbol';
try {
val = toStr(obj);
} catch (e) {}
json = '{"value":'.concat(wrapStr(val), ',"type":"Symbol"}');
} else {
if (timeout && now() - startTime > timeout) {
return wrapStr('Timeout');
}
if (depth && curDepth > depth) {
return wrapStr('{...}');
}
json = '{';
var parts = [];
var visitedObj = visitor.get(obj);
var id;
if (visitedObj) {
id = visitedObj.id;
parts.push('"reference":'.concat(id));
} else {
id = visitor.set(obj);
parts.push('"id":'.concat(id));
}
parts.push('"type":"'.concat(t, '"'));
if (endWith(t, 'Function')) {
parts.push('"value":'.concat(wrapStr(toSrc(obj))));
} else if (t === 'RegExp') {
parts.push('"value":'.concat(wrapStr(obj)));
}
if (!visitedObj) {
var enumerableKeys = keys(obj);
if (enumerableKeys.length) {
parts.push(
iterateObj(
'enumerable',
enumerableKeys,
self || obj,
options
)
);
}
if (unenumerable) {
var unenumerableKeys = difference(
allKeys(obj, {
prototype: false,
unenumerable: true
}),
enumerableKeys
);
if (unenumerableKeys.length) {
parts.push(
iterateObj(
'unenumerable',
unenumerableKeys,
self || obj,
options
)
);
}
}
if (symbol) {
var symbolKeys = filter(
allKeys(obj, {
prototype: false,
symbol: true
}),
function(key) {
return typeof key === 'symbol';
}
);
if (symbolKeys.length) {
parts.push(
iterateObj('symbol', symbolKeys, self || obj, options)
);
}
}
var prototype = getProto(obj);
if (prototype && !contain(ignore, prototype)) {
var proto = '"proto":'.concat(
exports(
prototype,
extend(options, {
self: self || obj
})
)
);
parts.push(proto);
}
}
json += parts.join(',') + '}';
}
return json;
};
function iterateObj(name, keys, obj, options) {
var parts = [];
each(keys, function(key) {
var val;
var descriptor = Object.getOwnPropertyDescriptor(obj, key);
var hasGetter = descriptor && descriptor.get;
var hasSetter = descriptor && descriptor.set;
if (!options.accessGetter && hasGetter) {
val = '(...)';
} else {
try {
val = obj[key];
if (contain(options.ignore, val)) {
return;
}
if (isPromise(val)) {
val.catch(function() {});
}
} catch (e) {
val = e.message;
}
}
parts.push(''.concat(wrapKey(key), ':').concat(exports(val, options)));
if (hasGetter) {
parts.push(
''
.concat(wrapKey('get ' + toStr(key)), ':')
.concat(exports(descriptor.get, options))
);
}
if (hasSetter) {
parts.push(
''
.concat(wrapKey('set ' + toStr(key)), ':')
.concat(exports(descriptor.set, options))
);
}
});
return '"'.concat(name, '":{') + parts.join(',') + '}';
}
function wrapKey(key) {
return '"'.concat(escapeJsonStr(key), '"');
}
function wrapStr(str) {
return '"'.concat(escapeJsonStr(toStr(str)), '"');
}
function escapeJsonStr(str) {
return escapeJsStr(str)
.replace(/\\'/g, "'")
.replace(/\t/g, '\\t');
}
var Visitor = Class({
initialize: function() {
this.id = 1;
this.visited = [];
},
set: function(val) {
var visited = this.visited,
id = this.id;
var obj = {
id: id,
val: val
};
visited.push(obj);
this.id++;
return id;
},
get: function(val) {
var visited = this.visited;
for (var i = 0, len = visited.length; i < len; i++) {
var obj = visited[i];
if (val === obj.val) return obj;
}
return false;
}
});
exports.parse = function(str) {
var map = {};
var obj = parse(JSON.parse(str), {
map: map
});
correctReference(map);
return obj;
};
function correctReference(map) {
each(map, function(obj) {
var enumerableKeys = keys(obj);
for (var i = 0, len = enumerableKeys.length; i < len; i++) {
var key = enumerableKeys[i];
if (isObj(obj[key])) {
var reference = obj[key].reference;
if (reference && map[reference]) {
obj[key] = map[reference];
}
}
}
var proto = getProto(obj);
if (proto && proto.reference) {
if (map[proto.reference]) {
Object.setPrototypeOf(obj, map[proto.reference]);
}
}
});
}
function parse(obj, options) {
var map = options.map;
if (!isObj(obj)) {
return obj;
}
var id = obj.id,
type = obj.type,
value = obj.value,
proto = obj.proto,
reference = obj.reference;
var enumerable = obj.enumerable,
unenumerable = obj.unenumerable;
if (reference) {
return obj;
}
if (type === 'Number') {
if (value === 'Infinity') {
return Number.POSITIVE_INFINITY;
} else if (value === '-Infinity') {
return Number.NEGATIVE_INFINITY;
}
return NaN;
} else if (type === 'Undefined') {
return undefined;
}
var newObj;
if (type === 'Function') {
newObj = function() {};
newObj.toString = function() {
return value;
};
if (proto) {
Object.setPrototypeOf(newObj, parse(proto, options));
}
} else if (type === 'RegExp') {
newObj = strToRegExp(value);
} else {
if (type !== 'Object') {
var Fn;
if (!isMiniProgram) {
Fn = new Function(type, '');
} else {
Fn = function() {};
}
if (proto) {
Fn.prototype = parse(proto, options);
}
newObj = new Fn();
} else {
if (proto) {
newObj = create(parse(proto, options));
} else {
newObj = create(null);
}
}
}
var defineProps = {};
if (enumerable) {
var len;
if (isArrLike(enumerable)) {
len = enumerable.length;
delete enumerable.length;
}
enumerable = pick(enumerable, function(value, key) {
return !handleGetterSetter(enumerable, value, key);
});
each(enumerable, function(value, key) {
var defineProp = defineProps[key] || {};
if (!defineProp.get) {
newObj[key] = parse(value, options);
}
});
if (len) {
newObj.length = len;
}
}
if (unenumerable) {
unenumerable = pick(unenumerable, function(value, key) {
return !handleGetterSetter(unenumerable, value, key);
});
each(unenumerable, function(value, key) {
var defineProp = defineProps[key] || {};
if (!defineProp.get) {
value = parse(value, options);
if (isObj(value) && value.reference) {
var _reference = value.reference;
value = function() {
return map[_reference];
};
defineProp.get = value;
} else {
defineProp.value = value;
}
}
defineProp.enumerable = false;
defineProps[key] = defineProp;
});
}
defineProp(newObj, defineProps);
function handleGetterSetter(obj, val, key) {
key = toStr(key);
var isGetterAndSetter = false;
each(['get', 'set'], function(type) {
if (startWith(key, type + ' ')) {
var realKey = key.replace(type + ' ', '');
if (obj[realKey]) {
val = parse(val, options);
if (val === 'Timeout') {
val = retTimeout;
}
safeSet(defineProps, [realKey, type], val);
isGetterAndSetter = true;
}
}
});
return isGetterAndSetter;
}
map[id] = newObj;
return newObj;
}
function retTimeout() {
return 'Timeout';
}
function strToRegExp(str) {
var lastSlash = str.lastIndexOf('/');
return new RegExp(str.slice(1, lastSlash), str.slice(lastSlash + 1));
}
module.exports = exports;