chrome-unmirror
Version:
Transform mirror objects from a remote Chrome debugger into local values
152 lines (122 loc) • 4.18 kB
JavaScript
;
var ERROR_CONSTRUCTORS = { 'Error': Error,
'EvalError': EvalError,
'InternalError': Error,
'RangeError': RangeError,
'ReferenceError': ReferenceError,
'SyntaxError': SyntaxError,
'TypeError': TypeError,
'URIError': URIError };
var classes = {};
function unmirror(remoteObj) {
var type = remoteObj.type;
var subtype = remoteObj.subtype;
var className = remoteObj.className;
var value = remoteObj.value;
var preview = remoteObj.preview;
var description = remoteObj.description;
var props = preview && preview.properties || [];
if (type === 'string') return value;
if (type === 'function') return function () {};
if (type === 'undefined') return undefined;
if (type === 'boolean') return value === 'true' || value === true;
if (type === 'symbol') {
if (typeof Symbol === 'undefined') return;
var match = (description || '').match(/Symbol\((.*)\)/);
return Symbol(match && match[1] || undefined);
}
if (type === 'number') {
// If message came from Console domain
if (typeof value === 'number') return value;
switch (value) {
case 'NaN':
return NaN;
case '-Infinity':
return -Infinity;
case 'Infinity':
return Infinity;
case '-0':
return -0;
default:
return maybeJSON(value);
}
}
if (subtype === 'null') return null;
if (subtype === 'date') return new Date(description);
if (subtype === 'node') return className;
if (subtype === 'regexp') {
var source = undefined,
lastIndex = undefined,
flags = '';
// If message came from Runtime or Debugger domain
props.forEach(function (prop) {
if (prop.name === 'source') source = prop.value;
if (prop.name === 'global' && unmirror(prop)) flags += 'g';
if (prop.name === 'ignoreCase' && unmirror(prop)) flags += 'i';
if (prop.name === 'multiline' && unmirror(prop)) flags += 'm';
if (prop.name === 'lastIndex') lastIndex = unmirror(prop);
});
// If message came from Console domain
if (source === undefined) {
var i = description.lastIndexOf(description[0]);
source = description.slice(1, i);
flags = description.slice(i + 1);
}
var re = new RegExp(source, flags);
re.lastIndex = lastIndex;
return re;
}
if (subtype === 'error') {
var _ret = (function () {
var Constructor = ERROR_CONSTRUCTORS[className] || Error;
var lines = (description || '').split('\n'),
msg = lines[0];
if (className && msg.slice(0, className.length) === className) {
msg = msg.slice(className.length + 1).trim();
}
var stack = lines.slice(1).join('\n'),
err = new Constructor(msg);
if (stack) Object.defineProperty(err, 'stack', {
enumerable: false, value: stack
});
props.forEach(function (p) {
Object.defineProperty(err, p.name, {
enumerable: false,
value: unmirror(p)
});
});
return {
v: err
};
})();
if (typeof _ret === 'object') return _ret.v;
}
// Mirror objects for Maps and Sets do not include elements,
// you'll need to fetch them through the Runtime domain. A
// module for that (also to unmirror lossy previews) is in the works.
if (subtype === 'map') return typeof Map !== 'undefined' ? new Map() : undefined;
if (subtype === 'set') return typeof Set !== 'undefined' ? new Set() : undefined;
if (subtype === 'array') return props.map(unmirror);
var o = typeof value === 'object' ? value : makeInstance(className);
props.forEach(function (prop) {
return o[prop.name] = unmirror(prop);
});
return o;
}
function maybeJSON(value, notSetValue) {
if (value === undefined) return notSetValue;
try {
return JSON.parse(value);
} catch (_) {
return value;
}
}
function makeInstance(className) {
if (!className || className === 'Object') return {};
if (!classes[className]) {
var namedFunction = new Function('return function ' + className + '() {}');
classes[className] = namedFunction();
}
return new classes[className]();
}
module.exports = unmirror;