diff --git a/doc/Util_Api.md b/doc/Util_Api.md
index 0f6bb12..ad13f32 100644
--- a/doc/Util_Api.md
+++ b/doc/Util_Api.md
@@ -846,6 +846,19 @@ Check if keys and values in src are contained in obj.
isMatch({a: 1, b: 2}, {a: 1}); // -> true
```
+## isNull
+
+Check if value is an Null.
+
+|Name |Type |Desc |
+|------|-------|-----------------------|
+|value |* |Value to check |
+|return|boolean|True if value is an Null|
+
+```javascript
+isNull(null); // -> true
+```
+
## isNum
Checks if value is classified as a Number primitive or object.
@@ -1222,6 +1235,19 @@ toArr(1); // -> []
toArr(null); // -> []
```
+## toInt
+
+Convert value to an integer.
+
+|Name |Type |Desc |
+|------|------|-----------------|
+|val |* |Value to convert |
+|return|number|Converted integer|
+
+```javascript
+toInt(1.1); // -> 1
+```
+
## toNum
Convert value to a number.
diff --git a/src/Console/Console.es6 b/src/Console/Console.es6
index 6b077fa..d6bc5e6 100644
--- a/src/Console/Console.es6
+++ b/src/Console/Console.es6
@@ -195,7 +195,7 @@ export default class Console extends Tool
if (cfg.get('catchGlobalErr')) this.catchGlobalErr();
if (cfg.get('overrideConsole')) this.overrideConsole();
- if (cfg.get('displayExtraInfo')) logger.displayExtraInfo(true);
+ if (cfg.get('displayExtraInfo')) logger.displayHeader(true);
logger.maxNum(maxLogNum);
cfg.on('change', (key, val) =>
@@ -205,7 +205,7 @@ export default class Console extends Tool
case 'catchGlobalErr': return val ? this.catchGlobalErr() : this.ignoreGlobalErr();
case 'overrideConsole': return val ? this.overrideConsole() : this.restoreConsole();
case 'maxLogNum': return logger.maxNum(val === 'infinite' ? val : +val);
- case 'displayExtraInfo': return logger.displayExtraInfo(val);
+ case 'displayExtraInfo': return logger.displayHeader(val);
}
});
diff --git a/src/Console/Log.es6 b/src/Console/Log.es6
index 3f6163b..504c4cd 100644
--- a/src/Console/Log.es6
+++ b/src/Console/Log.es6
@@ -5,15 +5,24 @@ import beautify from 'js-beautify'
export default class Log
{
- constructor({type, args, idx, header})
+ constructor({
+ type = 'log',
+ args = [],
+ idx = 0,
+ displayHeader = false,
+ ignoreFilter = false})
{
- this._type = type;
- this._args = args;
- this._idx = idx;
- this._header = header;
- this._ignoreFilter = false;
+ this.type = type;
+ this.args = args;
+ this.idx = idx;
+ this.displayHeader = displayHeader;
+ this.ignoreFilter = false;
- this._preProcess();
+ if (displayHeader)
+ {
+ this.time = getCurTime();
+ this.from = getFrom();
+ }
}
get formattedMsg()
{
@@ -21,38 +30,30 @@ export default class Log
return this._formattedMsg;
}
- get ignoreFilter()
+ _needSrc()
{
- return this._ignoreFilter;
- }
- get type()
- {
- return this._type;
- }
- _preProcess()
- {
- switch (this._type)
+ let {type, args} = this;
+
+ if (type === 'html') return false;
+
+ if (args.length === 1)
{
- case 'input':
- case 'output':
- this._ignoreFilter = true;
- break;
+ let arg = args[0];
+ if (util.isStr(arg)) return false;
+ if (util.isBool(arg)) return false;
+ if (util.isNum(arg)) return false;
}
- if (this._header)
- {
- this._time = getCurTime();
- this._from = getFrom();
- }
+ return true;
}
_formatMsg()
{
- let type = this._type,
- idx = this._idx,
- hasHeader = this._header,
- time = this._time,
- from = this._from,
- args = this._args;
+ let {type, idx, displayHeader, time, from, args} = this;
+
+ if (this._needSrc())
+ {
+ this.src = extractObj(args.length === 1 && util.isObj(args[0]) ? args[0] : args, false);
+ }
let msg = '', icon;
@@ -85,10 +86,9 @@ export default class Log
break;
}
- msg = render({msg, type, icon, idx, hasHeader, time, from});
- this.src = stringify(this._args);
+ msg = render({msg, type, icon, idx, displayHeader, time, from});
- delete this._args;
+ delete this.args;
this._formattedMsg = msg;
}
}
@@ -142,7 +142,9 @@ function formatMsg(args)
args[i] = 'null';
} else
{
- args[i] = util.escape(util.toStr(val));
+ val = util.toStr(val);
+ if (i !== 0) val = util.escape(val);
+ args[i] = val;
}
}
@@ -151,7 +153,7 @@ function formatMsg(args)
function substituteStr(args)
{
- var str = args[0],
+ var str = util.escape(args[0]),
newStr = '';
args.shift();
@@ -166,16 +168,30 @@ function substituteStr(args)
let arg = args.shift();
switch (str[i])
{
+ case 'i':
case 'd':
+ newStr += util.toInt(arg);
+ break;
+ case 'f':
newStr += util.toNum(arg);
break;
case 's':
newStr += util.toStr(arg);
break;
+ case 'O':
+ if (util.isObj(arg))
+ {
+ newStr += stringify(arg, {simple: true, keyQuotes: false, highlight: true});
+ }
+ break;
case 'o':
- try {
- newStr += JSON.stringify(arg);
- } catch (e) {}
+ if (util.isEl(arg))
+ {
+ newStr += formatEl(arg);
+ } else if (util.isObj(arg))
+ {
+ newStr += stringify(arg, {simple: true, keyQuotes: false, highlight: true});
+ }
break;
default:
i--;
@@ -195,7 +211,7 @@ function substituteStr(args)
function formatObj(val)
{
- return `${util.upperFirst(typeof val)} ${JSON.stringify(extractObj(val, true))}`;
+ return `${getObjType(val)} ${stringify(val, {keyQuotes: false, simple: true, highlight: true})}`;
}
function formatFn(val)
@@ -234,9 +250,16 @@ function getFrom()
return ret;
}
+function getObjType(obj)
+{
+ if (obj.constructor) return obj.constructor.name;
+
+ return util.upperFirst(({}).toString.call(obj).replace(/(\[object )|]/g, ''));
+}
+
var padZero = (num) => util.lpad(util.toStr(num), 2, '0');
var tpl = require('./Log.hbs');
var render = data => tpl(data);
-var extractObj = (obj, simple) => JSON.parse(stringify(obj, null, obj, simple));
+var extractObj = (obj, simple) => JSON.parse(stringify(obj, {simple}));
diff --git a/src/Console/Log.hbs b/src/Console/Log.hbs
index baac40b..f8fc653 100644
--- a/src/Console/Log.hbs
+++ b/src/Console/Log.hbs
@@ -1,5 +1,5 @@
- {{#if hasHeader}}
+ {{#if displayHeader}}
diff --git a/src/Console/Logger.es6 b/src/Console/Logger.es6
index a5ef0ad..c927fe5 100644
--- a/src/Console/Logger.es6
+++ b/src/Console/Logger.es6
@@ -17,13 +17,13 @@ export default class Logger extends util.Emitter
this._timer = {};
this._filter = 'all';
this._maxNum = 'infinite';
- this._displayExtraInfo = false;
+ this._displayHeader = false;
this._bindEvent();
}
- displayExtraInfo(flag)
+ displayHeader(flag)
{
- this._displayExtraInfo = flag;
+ this._displayHeader = flag;
}
maxNum(val)
{
@@ -106,20 +106,32 @@ export default class Logger extends util.Emitter
return this.filter(new RegExp(util.escapeRegExp(jsCode.slice(1))));
}
- this.insert('input', [jsCode]);
+ this.insert({
+ type: 'input',
+ args: [jsCode],
+ ignoreFilter: true
+ });
try {
this.output(evalJs(jsCode));
} catch (e)
{
- this.error(e);
+ this.insert({
+ type: 'error',
+ ignoreFilter: true,
+ args: [e]
+ });
}
return this;
}
output(val)
{
- return this.insert('output', [val]);
+ return this.insert({
+ type: 'output',
+ args: [val],
+ ignoreFilter: true
+ });
}
html(...args)
{
@@ -150,11 +162,13 @@ export default class Logger extends util.Emitter
{
let logs = this._logs;
- let log = new Log({
- type, args,
+ let options = util.isStr(type) ? {type, args} : type;
+ util.extend(options, {
idx: logs.length,
- header: this._displayExtraInfo
+ displayHeader: this._displayHeader
});
+
+ let log = new Log(options);
logs.push(log);
this.render();
diff --git a/src/Elements/Elements.es6 b/src/Elements/Elements.es6
index d3f4512..5f323d6 100644
--- a/src/Elements/Elements.es6
+++ b/src/Elements/Elements.es6
@@ -128,7 +128,7 @@ export default class Elements extends Tool
}
}).on('click', '.eruda-breadcrumb', () =>
{
- let data = this._elData || JSON.parse(stringify(this._curEl, null, this._curEl, false)),
+ let data = this._elData || JSON.parse(stringify(this._curEl)),
sources = parent.get('sources');
this._elData = data;
diff --git a/src/Sources/JsonViewer.es6 b/src/Sources/JsonViewer.es6
index f5af4b3..721097a 100644
--- a/src/Sources/JsonViewer.es6
+++ b/src/Sources/JsonViewer.es6
@@ -99,6 +99,13 @@ function createEl(key, val, firstLevel)
${val.length > 250 ? encode(val) : highlight(val, 'js')}
`
}
+ if (val === '(...)' || val === '[circular]')
+ {
+ return `
+ ${encode(key)}:
+ ${val}
+ `
+ }
return `
${encode(key)}:
diff --git a/src/lib/stringify.es6 b/src/lib/stringify.es6
index 7261405..b975135 100644
--- a/src/lib/stringify.es6
+++ b/src/lib/stringify.es6
@@ -1,7 +1,14 @@
import util from './util'
// Modified from: https://jsconsole.com/
-export default function stringify(obj, visited, topObj, simple)
+export default function stringify(obj, {
+ visited = [],
+ topObj,
+ simple = false,
+ keyQuotes = true,
+ getterVal = false,
+ highlight = false
+} = {})
{
let json = '',
type = '',
@@ -10,8 +17,28 @@ export default function stringify(obj, visited, topObj, simple)
proto,
circular = false;
- visited = visited || [];
topObj = topObj || obj;
+ let dbQuotes = keyQuotes ? '"' : '';
+
+ let keyWrapper = '',
+ numWrapper = '',
+ strWrapper = '',
+ nullWrapper = '',
+ wrapperEnd = '';
+
+ if (highlight)
+ {
+ keyWrapper = '';
+ numWrapper = '';
+ nullWrapper = '';
+ strWrapper = '';
+ wrapperEnd = ''
+ }
+
+ let wrapKey = key => keyWrapper + dbQuotes + key + dbQuotes + wrapperEnd,
+ wrapNum = num => numWrapper + num + wrapperEnd,
+ wrapStr = str => strWrapper + str + wrapperEnd,
+ wrapNull = str => nullWrapper + str + wrapperEnd;
try {
type = ({}).toString.call(obj);
@@ -39,16 +66,16 @@ export default function stringify(obj, visited, topObj, simple)
if (circular)
{
- json = '"[circular]"';
+ json = wrapStr('"[circular]"');
} else if (isStr)
{
- json = `"${escapeJsonStr(obj)}"`;
+ json = wrapStr(`"${escapeJsonStr(obj)}"`);
} else if (isArr)
{
visited.push(obj);
json = '[';
- util.each(obj, val => parts.push(`${stringify(val, visited, null, simple)}`));
+ util.each(obj, val => parts.push(`${stringify(val, {visited, simple, getterVal, keyQuotes, highlight})}`));
json += parts.join(', ') + ']';
} else if (isObj || isFn)
{
@@ -57,16 +84,16 @@ export default function stringify(obj, visited, topObj, simple)
names = Object.getOwnPropertyNames(obj);
proto = Object.getPrototypeOf(obj);
if (proto === Object.prototype || isFn || simple) proto = null;
- if (proto) proto = `"erudaProto": ${stringify(proto, visited, topObj)}`;
+ if (proto) proto = `${wrapKey('erudaProto')}: ${stringify(proto, {visited, getterVal, topObj, keyQuotes, highlight})}`;
names.sort(sortObjName);
if (isFn)
{
- // We don't these properties to be display for functions.
+ // We don't need these properties to display for functions.
names = names.filter(val => ['arguments', 'caller', 'name', 'length', 'prototype'].indexOf(val) < 0);
}
if (names.length === 0 && isFn)
{
- json = `"${escapeJsonStr(obj.toString())}"`;
+ json = wrapStr(`"${escapeJsonStr(obj.toString())}"`);
} else
{
json = '{';
@@ -75,11 +102,21 @@ export default function stringify(obj, visited, topObj, simple)
// Function length is restricted to 500 for performance reason.
var fnStr = obj.toString();
if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...';
- parts.push(`"erudaObjAbstract": "${escapeJsonStr(fnStr)}"`);
+ parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr('"' + escapeJsonStr(fnStr) + '"')}`);
}
util.each(names, name =>
{
- parts.push(`"${escapeJsonStr(name)}": ${stringify(topObj[name], visited, null, simple)}`);
+ let key = wrapKey(escapeJsonStr(name));
+
+ if (!getterVal)
+ {
+ let descriptor = Object.getOwnPropertyDescriptor(obj, name);
+ if (descriptor.get)
+ {
+ return parts.push(`${key}: "(...)"`);
+ }
+ }
+ parts.push(`${key}: ${stringify(topObj[name], {visited, getterVal, simple, keyQuotes, highlight})}`);
});
if (proto) parts.push(proto);
json += parts.join(', ') + '}';
@@ -87,19 +124,25 @@ export default function stringify(obj, visited, topObj, simple)
} else if (isNum)
{
json = obj + '';
- if (util.endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"`;
+ if (util.endWith(json, 'Infinity') || json === 'NaN')
+ {
+ json = `"${json}"`;
+ } else
+ {
+ json = wrapNum(json);
+ }
} else if (isBool)
{
json = obj ? 'true' : 'false';
} else if (obj === null)
{
- json = 'null';
+ json = wrapNull('null');
} else if (isSymbol)
{
- json = '"Symbol"';
+ json = wrapStr('"Symbol"');
} else if (obj === undefined)
{
- json = '"undefined"';
+ json = wrapStr('"undefined"');
} else if (type === '[object HTMLAllCollection]')
{
// https://docs.webplatform.org/wiki/dom/HTMLAllCollection
@@ -112,7 +155,7 @@ export default function stringify(obj, visited, topObj, simple)
visited.push(obj);
json = '{\n';
- if (!simple) parts.push(`"erudaObjAbstract": "${type.replace(/(\[object )|]/g, '')}"`);
+ if (!simple) parts.push(`${wrapKey('erudaObjAbstract')}: "${type.replace(/(\[object )|]/g, '')}"`);
names = Object.getOwnPropertyNames(obj);
proto = Object.getPrototypeOf(obj);
if (proto === Object.prototype || simple) proto = null;
@@ -120,21 +163,31 @@ export default function stringify(obj, visited, topObj, simple)
{
try
{
- proto = `"erudaProto": ${stringify(proto, visited, topObj)}`;
+ proto = `${wrapKey('erudaProto')}: ${stringify(proto, {visited, topObj, getterVal, keyQuotes, highlight})}`;
} catch(e)
{
- proto = `"erudaProto": "${escapeJsonStr(e.message)}"`;
+ proto = `${wrapKey('erudaProto')}: ${wrapStr('"' + escapeJsonStr(e.message) + '"')}`;
}
}
names.sort(sortObjName);
util.each(names, name =>
{
- parts.push(`"${escapeJsonStr(name)}": ${stringify(topObj[name], visited, null, simple)}`);
+ let key = wrapKey(escapeJsonStr(name));
+
+ if (!getterVal)
+ {
+ let descriptor = Object.getOwnPropertyDescriptor(obj, name);
+ if (descriptor.get)
+ {
+ return parts.push(`${key}: "(...)"`);
+ }
+ }
+ parts.push(`${key}: ${stringify(topObj[name], {visited, getterVal, simple, keyQuotes, highlight})}`);
});
if (proto) parts.push(proto);
json += parts.join(',\n') + '\n}';
} catch (e) {
- json = `"${obj}"`;
+ json = wrapStr(`"${obj}"`);
}
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 52987d9..b3fd94d 100644
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -3345,6 +3345,34 @@ module.exports = (function ()
return exports;
})();
+ /* ------------------------------ toInt ------------------------------ */
+
+ var toInt = _.toInt = (function ()
+ {
+ /* Convert value to an integer.
+ *
+ * |Name |Type |Desc |
+ * |------|------|-----------------|
+ * |val |* |Value to convert |
+ * |return|number|Converted integer|
+ *
+ * ```javascript
+ * toInt(1.1); // -> 1
+ * ```
+ */
+
+ function exports(val)
+ {
+ if (!val) return val === 0 ? val : 0;
+
+ val = toNum(val);
+
+ return val - val % 1;
+ }
+
+ return exports;
+ })();
+
/* ------------------------------ toStr ------------------------------ */
var toStr = _.toStr = (function ()
diff --git a/test/console.js b/test/console.js
index 330462a..ab11d15 100644
--- a/test/console.js
+++ b/test/console.js
@@ -11,12 +11,18 @@ describe('log', function ()
expect($tool.find('.eruda-log')).toContainText(text);
});
+ it('clear', function ()
+ {
+ tool.clear();
+ expect($tool.find('.eruda-log')).toHaveLength(0);
+ });
+
it('basic object', function ()
{
var obj = {a: 1};
tool.clear().log(obj);
- expect($tool.find('.eruda-log')).toContainText('Object {"a":1}');
+ expect($tool.find('.eruda-log')).toContainText('Object {a: 1}');
});
it('html', function ()
@@ -37,8 +43,14 @@ describe('substitution', function ()
{
it('number', function ()
{
- tool.clear().log('Eruda is %d', 1, 'year old');
+ tool.clear().log('Eruda is %d', 1.2, 'year old');
expect($tool.find('.eruda-log')).toContainText('Eruda is 1 year old');
+
+ tool.clear().log('%i', 1.2, 'year old');
+ expect($tool.find('.eruda-log')).toContainText('1 year old');
+
+ tool.clear().log('%f', 1.2, 'year old');
+ expect($tool.find('.eruda-log')).toContainText('1.2 year old');
});
it('string', function ()
@@ -49,8 +61,11 @@ describe('substitution', function ()
it('object', function ()
{
- tool.clear().log('Object is %o', {a: 1});
- expect($tool.find('.eruda-log')).toContainText('Object is {"a":1}');
+ tool.clear().log('Object is %O', {a: 1});
+ expect($tool.find('.eruda-log')).toContainText('Object is {a: 1}');
+
+ tool.clear().log('Dom is %o', document.createElement('script'));
+ expect($tool.find('.eruda-log')).toContainText('Dom is ');
});
});