mirror of
https://github.com/liriliri/eruda.git
synced 2026-03-20 09:38:37 +08:00
Dev: Basic string substitution support
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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}));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<li>
|
||||
{{#if hasHeader}}
|
||||
{{#if displayHeader}}
|
||||
<div class="eruda-header">
|
||||
{{time}} {{from}}
|
||||
</div>
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -99,6 +99,13 @@ function createEl(key, val, firstLevel)
|
||||
<span class="eruda-function">${val.length > 250 ? encode(val) : highlight(val, 'js')}</span>
|
||||
</li>`
|
||||
}
|
||||
if (val === '(...)' || val === '[circular]')
|
||||
{
|
||||
return `<li>
|
||||
<span class="eruda-key">${encode(key)}: </span>
|
||||
<span class="eruda-special">${val}</span>
|
||||
</li>`
|
||||
}
|
||||
|
||||
return `<li>
|
||||
<span class="eruda-key">${encode(key)}: </span>
|
||||
|
||||
@@ -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 = '<span style="color: #a71d5d;">';
|
||||
numWrapper = '<span style="color: #0086b3;">';
|
||||
nullWrapper = '<span style="color: #0086b3;">';
|
||||
strWrapper = '<span style="color: #183691;">';
|
||||
wrapperEnd = '</span>'
|
||||
}
|
||||
|
||||
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}"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
@@ -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 <script></script>');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user