peek42
Version:
Touch based browser console
1,213 lines (988 loc) • 32.7 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.peek42 = factory());
}(this, function () { 'use strict';
const name = "peek42";
const version = "5.9.2";
function _isNullProtoObject(val) {
return typeof val === 'object' && val !== null && val.__proto__ === undefined;
}
function _string(val) {
return _isNullProtoObject(val) ? '[object Object(proto:Null)]' : String(val);
}
function _comment(comment, val, note = undefined) {
if (comment !== undefined && comment !== '') {
return comment;
}
let str = _string(val).replace(/\s+/gm, ' ');
let max = 69;
if (str.length > max) {
str = `${str.substr(0, max)}...`;
}
return note === undefined ? str : `(${note}) ${str}`;
}
const _outputOptsDefaults = {
level: 'log',
collapsed: false
};
function _prettyMakesSense(val) {
return val instanceof Object && !(val instanceof Function) || _isNullProtoObject(val);
}
function pretty(val) {
let objs = [];
let keys = [];
return JSON.stringify(val, (k, v) => {
if (v instanceof Object || _isNullProtoObject(v)) {
let seen = objs.indexOf(v);
if (seen === -1) {
objs.push(v);
keys.push(k || 'ROOT');
return v;
}
return `${_string(v)} (ref to ${keys[seen]})`;
}
return v;
}, 2);
}
function p(val, comment = undefined, opts = undefined) {
peek42._output(val, _comment(comment, val, 'value'), opts);
}
p.pretty = function (val, comment = undefined, opts = undefined) {
peek42._output(_prettyMakesSense(val) ? pretty(val) : val, _comment(comment, val, 'pretty'), opts);
};
function pp(...args) {
(p.inspect ? p.inspect : p.pretty)(...args);
}
function use(lib) {
Object.assign(p, lib.peek42(p, _comment));
return peek42;
}
const peek42 = {
get [Symbol.toStringTag]() {
return name;
},
version: version,
pretty,
p,
pp,
use
};
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
var consoleHTML = "<div class=\"peek42-bar\">\n <span class=\"peek42-control peek42-title\">Peek42</span>\n\n <input class=\"peek42-control peek42-eval\" autocorrect=\"off\" placeholder=\"JS to evaluate\">\n\n <span class=\"peek42-control peek42-clear\">Clear</span>\n <span class=\"peek42-control peek42-resize\">Resize</span>\n <label class=\"peek42-control peek42-quietl\">Quiet\n <input type=\"checkbox\" class=\"peek42-control peek42-quiet\">\n </label>\n <span class=\"peek42-control peek42-toggle\">Minimize</span>\n</div>\n\n<div class=\"peek42-view\">\n <pre class=\"peek42-log\">\n </pre>\n\n <div class=\"peek42-bar1\">\n <div class=\"peek42-bar1-control peek42-entries-collapse\">▸</div>\n <div class=\"peek42-bar1-control peek42-entries-expand\">▾</div>\n\n <div class=\"peek42-bar1-control peek42-entries-info peek42-entries-info-active\">0</div>\n <div class=\"peek42-bar1-control peek42-entries-log peek42-entries-log-active\">0</div>\n <div class=\"peek42-bar1-control peek42-entries-warn peek42-entries-warn-active\">0</div>\n <div class=\"peek42-bar1-control peek42-entries-error peek42-entries-error-active\">0</div>\n </div>\n</div>\n";
function flash1(el, className) {
el.classList.add(className);
setTimeout(() => el.classList.remove(className), 300);
}
function flash2(el, className) {
el.classList.add(className);
setTimeout(() => {
el.classList.remove(className);
setTimeout(() => {
el.classList.add(className);
setTimeout(() => el.classList.remove(className), 300);
}, 200);
}, 300);
}
function flashSizeLimit(el) {
flash1(el, 'peek42-flash-size-limit');
}
function flashNotice(el) {
flash1(el, 'peek42-flash-notice');
}
function flashSuccess(el) {
flash1(el, 'peek42-flash-success');
}
function flashWarning(el) {
flash2(el, 'peek42-flash-warning');
}
function flashError(el) {
flash2(el, 'peek42-flash-error');
}
function flashOutput(el, level) {
switch (level) {
case 'info':
flashNotice(el);
break;
case 'warn':
flashWarning(el);
break;
case 'error':
flashError(el);
break;
case 'log':
default:
flashSuccess(el);
break;
}
}
class Resizer {
constructor(elResizee, {
elFlashSizeLimit = elResizee,
elsMakeSameHeight = [],
ratio = 0.42,
minRatio = 0.05,
maxRatio = 0.85
} = {}) {
this._elResizee = elResizee;
this._elFlashSizeLimit = elFlashSizeLimit;
this._elsMakeSameHeight = elsMakeSameHeight;
this._ratio = ratio;
this._minRatio = minRatio;
this._maxRatio = maxRatio;
this._height = window.innerHeight * this._ratio;
this._resizeY = 0;
this._resizeYDelta = 0;
this._isResizing = false;
this._syncHeights();
}
get ratio() {
return this._ratio;
}
get height() {
return this._height;
}
set height(v) {
if (typeof v !== 'number') {
throw new TypeError(`Expected number, got ${typeof v}`);
}
this._height = v;
this._syncHeights();
}
_syncHeights() {
let styleHeight = `${this._height}px`;
this._elResizee.style.height = styleHeight;
this._elsMakeSameHeight.forEach(el => el.style.height = styleHeight);
}
get isResizing() {
return this._isResizing;
}
resizeStart(clientY) {
this._resizeY = clientY;
this._resizeYDelta = 0;
this._isResizing = true;
}
resize(clientY) {
let minHeight = window.innerHeight * this._minRatio;
let maxHeight = window.innerHeight * this._maxRatio;
this._resizeYDelta = this._resizeY - clientY;
this._height += this._resizeYDelta;
if (this._height > minHeight && this._height < maxHeight) {
this._resizeY = clientY;
this._syncHeights();
} else {
this._height = Math.min(Math.max(this._height, minHeight), maxHeight);
this._syncHeights();
flashSizeLimit(this._elFlashSizeLimit);
this.resizeEnd();
}
}
resizeEnd() {
this._ratio = this._height / window.innerHeight;
this._resizeY = 0;
this._resizeYDelta = 0;
this._isResizing = false;
}
}
function _logEntryToggleAndBody(elHead) {
return [elHead.firstElementChild, elHead.nextElementSibling];
}
function _logEntryExpand(elToggle, elBody) {
elToggle.innerHTML = '▾';
elBody.style.display = '';
}
function _logEntryCollapse(elToggle, elBody) {
elToggle.innerHTML = '▸';
elBody.style.display = 'none';
}
function _logEntryToggle(elToggle, elBody) {
if (elBody.style.display === 'none') {
_logEntryExpand(elToggle, elBody);
} else {
_logEntryCollapse(elToggle, elBody);
}
}
function _onLogEntryHeadClick(ev) {
_logEntryToggle(..._logEntryToggleAndBody(ev.currentTarget));
}
function addLogEntry({
elLog,
entrySimpleText,
entryDesc,
entryText,
entryHtml,
hidden = false,
level = 'log',
collapsed = false
} = {}) {
let elEntry = document.createElement('div');
elEntry.classList.add(`peek42-log-entry-${level}`);
if (hidden) {
elEntry.style.display = 'none';
}
if (entrySimpleText) {
elEntry.classList.add('peek42-log-entry-simple');
elEntry.textContent = entrySimpleText;
} else {
elEntry.classList.add('peek42-log-entry');
elEntry.innerHTML = `<div class="peek42-log-entry-head">\
<span class="peek42-log-entry-toggle">▾</span>\
<span class="peek42-log-entry-desc"></span>\
</div>\
<div class="peek42-log-entry-body"></div>`;
let elHead = elEntry.firstElementChild;
let [elToggle, elBody] = _logEntryToggleAndBody(elHead);
let elDesc = elToggle.nextElementSibling;
elDesc.textContent = entryDesc;
if (entryHtml) {
elBody.appendChild(entryHtml);
} else {
elBody.textContent = entryText;
}
elHead.addEventListener('click', _onLogEntryHeadClick);
if (collapsed) {
_logEntryCollapse(elToggle, elBody);
}
}
elLog.insertBefore(elEntry, elLog.firstChild);
elLog.scrollTop = 0;
}
class Console {
static get instance() {
return new Promise((resolve, reject) => {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
resolve(this._instance = this._instance || new this());
});
} else {
resolve(this._instance = this._instance || new this());
}
});
}
constructor() {
if (document.readyState === 'loading') {
throw new Error(`Cannot create ${new.target.name} before DOM ready`);
}
if (document.querySelector('.peek42-console')) {
throw new Error(`${new.target.name} already created`);
}
this._container = document.createElement('div');
this._container.setAttribute('class', 'peek42-console');
this._container.innerHTML = new.target._html;
document.body.appendChild(this._container); //this._container.classList.add('peek42-dev');
['bar', 'title', 'eval', 'clear', 'resize', 'quietl', 'quiet', 'toggle', 'view', 'log', 'bar1', 'entries-expand', 'entries-collapse', 'entries-info', 'entries-log', 'entries-warn', 'entries-error'].forEach(name => {
this[`_${name}`] = this._container.querySelector(`.peek42-${name}`);
});
this._resizer = new Resizer(this._log, {
elFlashSizeLimit: this._container,
elsMakeSameHeight: [this._bar1]
});
this._isMinimized = false;
this._countsByLevel = {
info: 0,
log: 0,
warn: 0,
error: 0
};
this._title.addEventListener('click', ev => {
this._onTitleClick(ev);
});
this._eval.addEventListener('keypress', ev => {
this._onEvalKeyPress(ev);
});
this._clear.addEventListener('click', ev => {
this._onClearClick(ev);
});
this._resize.addEventListener('touchstart', ev => {
this._onResizeTouchStart(ev);
});
document.body.addEventListener('touchmove', ev => {
this._onBodyTouchMove(ev);
});
document.body.addEventListener('touchend', ev => {
this._onBodyTouchEnd(ev);
});
window.addEventListener('resize', ev => {
this._onWindowResize(ev);
});
this._quietl.addEventListener('click', ev => {
this._onQuietClick(ev);
});
this._toggle.addEventListener('click', ev => {
this._onToggleClick(ev);
});
['entries-expand', 'entries-collapse'].forEach(name => {
this[`_${name}`].addEventListener('click', ev => {
this[`_on-${name}`](ev);
});
});
['entries-info', 'entries-log', 'entries-warn', 'entries-error'].forEach(name => {
this[`_${name}`].addEventListener('click', ev => {
this[`_${name}`].classList.toggle(`peek42-${name}-active`);
this[`_on-toggle-${name}`](ev);
});
});
this.minimize();
}
_isLevelActive(level) {
return this[`_entries-${level}`].classList.contains(`peek42-entries-${level}-active`);
}
_output(val, comment, opts = {}) {
opts = _objectSpread({}, _outputOptsDefaults, opts);
let active = this._isLevelActive(opts.level);
if (this.isMinimized && active && !this.isQuiet) {
this.show();
}
if (val instanceof HTMLElement && val.dataset.peek42HtmlEntry) {
addLogEntry(_objectSpread({
elLog: this._log,
entryDesc: String(comment),
entryHtml: val,
hidden: !active
}, opts));
} else {
if (comment === null) {
addLogEntry(_objectSpread({
elLog: this._log,
entrySimpleText: _string(val),
hidden: !active
}, opts));
} else {
addLogEntry(_objectSpread({
elLog: this._log,
entryDesc: String(comment),
entryText: _string(val),
hidden: !active
}, opts));
}
}
this._countsByLevel[opts.level] += 1;
this[`_entries-${opts.level}`].textContent = this._countsByLevel[opts.level];
flashOutput(this._container, opts.level);
}
_onTitleClick(ev) {
ev.preventDefault();
ev.stopPropagation();
this.toggleLogPos();
}
_onEvalKeyPress(ev) {
let crCode = '\r'.charCodeAt(0);
let lfCode = '\n'.charCodeAt(0);
if (ev.charCode === crCode || ev.charCode === lfCode) {
this.evalJS();
}
}
_onClearClick(ev) {
ev.preventDefault();
ev.stopPropagation();
this.clear();
}
_onResizeTouchStart(ev) {
ev.preventDefault();
ev.stopPropagation();
this._resizer.resizeStart(ev.touches[0].clientY);
}
_onBodyTouchMove(ev) {
if (this._resizer.isResizing) {
ev.preventDefault();
ev.stopPropagation();
this._resizer.resize(ev.touches[0].clientY);
}
}
_onBodyTouchEnd(ev) {
if (this._resizer.isResizing) {
this._resizer.resizeEnd();
}
}
_onWindowResize(ev) {
this._resizer.height = window.innerHeight * this._resizer.ratio;
}
_onQuietClick(ev) {
ev.preventDefault();
ev.stopPropagation();
this.toggleQuiet();
}
_onToggleClick(ev) {
ev.preventDefault();
ev.stopPropagation();
this.toggleDisplay();
}
['_on-entries-expand'](ev) {
this._log.querySelectorAll('.peek42-log-entry-head').forEach(elHead => _logEntryExpand(..._logEntryToggleAndBody(elHead)));
}
['_on-entries-collapse'](ev) {
this._log.querySelectorAll('.peek42-log-entry-head').forEach(elHead => _logEntryCollapse(..._logEntryToggleAndBody(elHead)));
}
_toggleEntriesDisplay(elCtrl, level) {
let activeClass = `peek42-entries-${level}-active`;
let entriesClass = `.peek42-log-entry-${level}`;
let display = elCtrl.classList.contains(activeClass) ? '' : 'none';
this._log.querySelectorAll(entriesClass).forEach(elEntry => elEntry.style.display = display);
}
['_on-toggle-entries-info'](ev) {
this._toggleEntriesDisplay(ev.currentTarget, 'info');
}
['_on-toggle-entries-log'](ev) {
this._toggleEntriesDisplay(ev.currentTarget, 'log');
}
['_on-toggle-entries-warn'](ev) {
this._toggleEntriesDisplay(ev.currentTarget, 'warn');
}
['_on-toggle-entries-error'](ev) {
this._toggleEntriesDisplay(ev.currentTarget, 'error');
}
get logIsAtTop() {
return this._log.scrollTop === 0;
}
toggleLogPos() {
this.logIsAtTop ? this.logPosBottom() : this.logPosTop();
}
logPosBottom() {
this._log.scrollTop = this._log.scrollHeight;
}
logPosTop() {
this._log.scrollTop = 0;
}
get jsToEval() {
return this._eval.value;
}
set jsToEval(v) {
this._eval.value = v;
}
evalJS() {
let val = this._eval.value;
if (val.match(/^\s*$/gm)) {
return;
}
let str = val.replace(/'/gm, '"');
let keys = Object.keys(this.constructor._printFnMap);
let pattern = `^(${keys.join('|')})\\s+(.+)`;
let parts = str.match(new RegExp(pattern));
let dummy, k, expr, fn, note, js;
if (parts) {
[dummy, k, expr] = parts;
[fn, note] = this.constructor._printFnMap[k];
} else {
expr = str;
[fn, note] = this.constructor._printFnMap['v'];
}
js = `'use strict';
${fn}(${expr}, '(${note}) ${expr}');
`;
try {
new Function(js)();
} catch (err) {
if (!err.sourceURL) {
err.sourceText = js;
err.line = (err.line || 4) - 1;
}
throw err;
}
}
clear() {
this._log.textContent = '';
['info', 'log', 'warn', 'error'].forEach(level => {
this._countsByLevel[level] = 0;
this[`_entries-${level}`].textContent = 0;
});
flashNotice(this._container);
}
get isQuiet() {
return this._quiet.checked;
}
toggleQuiet() {
this._quiet.checked = !this._quiet.checked;
}
quiet() {
this._quiet.checked = true;
}
unquiet() {
this._quiet.checked = false;
}
get isMinimized() {
return this._isMinimized;
}
toggleDisplay() {
this.isMinimized ? this.show() : this.minimize();
}
show() {
this._eval.style.display = '';
this._resize.style.display = '';
this._quietl.style.display = 'none';
this._quiet.style.display = 'none';
this._toggle.innerHTML = 'Minimize';
this._view.style.display = '';
this._isMinimized = false;
}
minimize() {
this._eval.style.display = 'none';
this._resize.style.display = 'none';
this._quietl.style.display = '';
this._quiet.style.display = '';
this._toggle.innerHTML = 'Restore';
this._view.style.display = 'none';
this._isMinimized = true;
}
get content() {
return this._log.textContent;
}
}
_defineProperty(Console, "_html", consoleHTML);
_defineProperty(Console, "_instance", null);
_defineProperty(Console, "_printFnMap", {
v: ['peek42.p', 'value'],
value: ['peek42.p', 'value'],
p: ['peek42.p.pretty', 'pretty'],
pretty: ['peek42.p.pretty', 'pretty'],
t: ['peek42.p.type', 'type'],
type: ['peek42.p.type', 'type'],
d: ['peek42.p.desc', 'desc'],
desc: ['peek42.p.desc', 'desc'],
M: ['peek42.p.member', 'member'],
member: ['peek42.p.member', 'member'],
m: ['peek42.p.members', 'members'],
members: ['peek42.p.members', 'members'],
i: ['peek42.p.inspect', 'inspect'],
inspect: ['peek42.p.inspect', 'inspect'],
c: ['peek42.p.chain', 'chain'],
chain: ['peek42.p.chain', 'chain'],
a: ['peek42.p.api', 'api'],
api: ['peek42.p.api', 'api'],
x: ['peek42.p.dom', 'dom'],
dom: ['peek42.p.dom', 'dom']
});
const reTestTranspiledScriptStack = /\nrun\S+babel/m;
const reCaptureSourceMappingURL = // match[1] - sourceMappingURL
/\/\/# sourceMappingURL=(.+)\s*$/m;
const reCaptureEmbeddedSourceMap = // match[1] - embeddedSourceMap (base64)
/^data:application\/json;(?:charset=[^;]+;)?base64,(.+)$/;
const reTestAbsoluteURL = /^(?:[a-z]+:)?\/\//i;
const reCapturePathAndName = // match[1] - path (includes trailing slash)
// match[2] - name (includes extension)
/^(.+\/)?([^\/]+)$/;
function isInlineScriptError(err) {
return !!(err.sourceURL && err.sourceURL === window.location.href);
}
function isTranspiledScriptError(err) {
return !!(err.stack && reTestTranspiledScriptStack.test(err.stack));
}
function inlineScripts() {
return Array.from(document.scripts).filter(script => !script.getAttribute('src')).map(script => ({
source: script.textContent,
sourceMap: null,
originalErrorInfo: null
}));
}
function transpiledInlineScripts(_inlineScripts) {
return _inlineScripts.map(scriptInfo => {
scriptInfo.sourceMap = embeddedSourceMap(sourceMappingURL(scriptInfo.source));
return scriptInfo;
}).filter(scriptInfo => !!scriptInfo.sourceMap);
}
async function transpiledInlineScriptsWithOriginalErrorInfoAsync(_transpiledInlineScripts, err) {
return Promise.all(_transpiledInlineScripts.map(async scriptInfo => {
scriptInfo.originalErrorInfo = await originalErrorInfoAsync(scriptInfo.sourceMap, err);
return scriptInfo;
}));
}
async function transpiledInlineScriptsSourceTracesAsync(err) {
let scripts = transpiledInlineScripts(inlineScripts());
try {
return (await transpiledInlineScriptsWithOriginalErrorInfoAsync(scripts, err)).map(scriptInfo => sourceTrace(...sourceTraceArgs(scriptInfo.originalErrorInfo)));
} catch (err1) {
console.warn(`sourceMap library support missing/incomplete or error retrieving source information\n${err1}`);
return scripts.map((scriptInfo, i) => sourceTrace(scriptInfo.source, `Transpiled inline script #${i + 1}`, err.line, err.column));
}
}
async function errorSourceAsync(err) {
if (err.sourceText) {
return err.sourceText;
}
if (!err.sourceURL) {
throw new Error('sourceURL unavailable');
}
let url = err.sourceURL;
let res = null;
try {
res = await fetch(url);
} catch (err) {
throw new Error(`Cannot retrieve ${url}`);
}
if (!res.ok) {
throw new Error(`${res.status} (${res.statusText}) ${url}`);
}
return res.text();
}
function sourceMappingURL(source) {
return (source.match(reCaptureSourceMappingURL) || [])[1];
}
function embeddedSourceMap(_sourceMappingURL) {
let base64 = ((_sourceMappingURL || '').match(reCaptureEmbeddedSourceMap) || [])[1];
return base64 ? JSON.parse(atob(base64)) : null;
}
function isAbsoluteURL(url) {
return reTestAbsoluteURL.test(url);
}
function pathAndName(url) {
let [, path, name] = (url || '').match(reCapturePathAndName) || [];
return [path, name];
}
async function tryFetchAsync(url, {
as = 'text'
} = {}) {
try {
let res = await fetch(url);
return res.ok ? res[as]() : null;
} catch (err) {
return null;
}
}
async function sourceMapAsync(source, sourceURL) {
let url = sourceMappingURL(source);
let map = null;
if (!url) {
return null;
}
if (map = embeddedSourceMap(url)) {
return map;
}
if (isAbsoluteURL(url)) {
return tryFetchAsync(url, {
as: 'json'
});
}
let [path, name] = pathAndName(sourceURL);
if (map = await tryFetchAsync(`${path}${url}`, {
as: 'json'
})) {
return map;
}
return tryFetchAsync(`${path}${name}.map`, {
as: 'json'
});
}
async function originalErrorInfoAsync(_sourceMap, err) {
const {
SourceMapConsumer
} = sourceMap;
return SourceMapConsumer.with(_sourceMap, null, consumer => {
let position = consumer.originalPositionFor({
line: err.line || 1,
// The sourceMap lib expects 0-based columns
column: (err.column || 1) - 1
}) || {};
let source = consumer.sourceContentFor(position.source, true) || '';
return {
position,
source
};
});
}
function sourceTraceArgs(_originalErrorInfo) {
let {
source,
position
} = _originalErrorInfo;
return [source, position.source || '', position.line || 1, // The sourceTrace func expects 1-based columns
// position.name is the erroneous token
// Place the error marker after it for consistency with runtime errors
(position.column || 0) + 1 + (position.name || '').length];
}
function sourceTrace(source, url, line1, column1, {
indent = '',
peekLines = 2
} = {}) {
let lines = (source || '').split('\n');
let [path = 'path n/a', name = 'code'] = pathAndName(url);
let iLine = (line1 || 1) - 1;
let iColumn = (column1 || 1) - 1;
let traceLines = [];
let iTraceLineMax = Math.max(0, lines.length - 1);
let iTraceLineBeg = Math.max(0, iLine - peekLines);
let iTraceLineEnd = Math.min(iTraceLineMax, iLine + peekLines);
let padMax = `${lines.length}`.length;
let margin = '|';
let linePointer = ' ';
let columnFill = '~';
let columnPointer = `${columnFill.repeat(iColumn)}^`;
for (let i = iTraceLineBeg; i <= iTraceLineEnd; i++) {
let pad = ' '.repeat(padMax - `${i + 1}`.length);
let lineMarker = i == iLine ? linePointer : ' '.repeat(linePointer.length);
let columnMarker = i == iLine ? `\n${indent}${' '.repeat(linePointer.length)}${columnFill.repeat(padMax + margin.length)}${columnPointer}` : '';
traceLines.push(`${indent}${lineMarker}${pad}${i + 1}${margin}${lines[i]}${columnMarker}`);
}
return `${indent}${name}:${line1 || 'n/a'}:${column1 || 'n/a'} (${path})\n${traceLines.join('\n')}`;
}
async function formatErrorAsync(err, {
includeStack = true
} = {}) {
let trace;
try {
if (isInlineScriptError(err)) {
if (isTranspiledScriptError(err)) {
trace = (await transpiledInlineScriptsSourceTracesAsync(err)).join('\n');
} else {
trace = sourceTrace((await errorSourceAsync(err)), err.sourceURL, err.line, err.column);
}
} else {
let source = await errorSourceAsync(err);
let map = await sourceMapAsync(source, err.sourceURL);
if (map) {
try {
trace = sourceTrace(...sourceTraceArgs((await originalErrorInfoAsync(map, err))));
} catch (err1) {
console.warn(`sourceMap library support missing/incomplete or error retrieving source information\n${err1}`);
}
}
if (!trace) {
trace = sourceTrace(source, err.sourceURL, err.line, err.column);
}
}
} catch (err1) {
err.sourceTraceNA = `${err1}`;
trace = pretty(err);
}
return includeStack ? `${trace}\nstack:\n ${err && err.stack && err.stack.replace(/\n/gm, '\n ') || 'n/a'}` : `${trace}`;
}
function reportError(err, {
includeStack = true,
note = 'error'
} = {}) {
formatErrorAsync(err, {
includeStack
}).then(str => {
p(str, `(${note}) ${err}`, {
level: 'error'
});
});
}
const _configDefaults = {
interceptConsole: true,
addGlobals: true,
autoUse: true
};
const _config = _objectSpread({}, _configDefaults, window.PEEK42_CONFIG);
window.console = window.console || {};
const _fnOrig = {};
function _interceptNativeConsoleFn(name) {
_fnOrig[name] = window.console[name];
const {
map
} = Array.prototype;
window.console[name] = function () {
let str = map.call(arguments, arg => _string(arg)).join(' ');
let stack = (new Error().stack || '\n').split('\n');
let loc = (stack.shift(), stack.shift() || '[source location n/a]');
p(str, _comment('', '', `console.${name}@${loc}`), {
level: name
});
try {
_fnOrig[name] && _fnOrig[name].apply(window.console, arguments);
} catch (err) {
formatErrorAsync(err).then(str => {
p(str, _comment('', err, `console.${name}@${loc}`), {
level: 'error',
collapsed: true
});
});
}
};
}
class WS {
constructor(url = `${location.origin.replace(/^http/, 'ws')}/peek42`) {
this._url = url;
this._ws = new WebSocket(this._url);
this._ws.addEventListener('open', ev => {
p(`peek42 WebSocket open (url: ${this._url})`, null, {
level: 'info'
});
});
this._ws.addEventListener('close', ev => {
p(`peek42 WebSocket close (url: ${this._url}, code: ${ev.code})`, null, {
level: 'warn'
});
});
this._ws.addEventListener('error', ev => {
throw new Error(`peek42 WebSocket error (url: ${this._url})`);
});
this._ws.addEventListener('message', ev => {
let serverWireData = ev.data;
let serverData = JSON.parse(serverWireData);
this.onmessage(serverData);
});
}
onmessage(serverData) {
let {
val,
comment,
opts
} = serverData;
if (comment === null) {
val = `(server) ${val}`;
} else {
comment = `(server) ${comment}`;
}
p(val, comment, opts);
}
}
const cable = {
init(url) {
this._websocket = new WS(url);
}
};
function _output(...args) {
// Allow peek42.console.content to be used without
// Console.instance.then wait (or the setTimeout 0 trick)
// after console has been created and assigned
if (peek42.console) {
return peek42.console._output(...args);
}
Console.instance.then(console => {
Object.assign(peek42, {
console
});
console._output(...args);
});
}
Console.instance.then(console => {
Object.assign(peek42, {
console
});
});
p.trace = (comment = undefined, opts = undefined) => {
let stack = (new Error().stack || '\n').split('\n');
let trace = (stack.shift(), stack);
let loc = trace[0];
_output(trace.join('\n'), _comment(comment, loc, `trace`), opts);
};
function walk(elem, fnVisit, {
level = 0
} = {}) {
fnVisit(elem, level);
for (let node = elem.firstChild; node; node = node.nextSibling) {
walk(node, fnVisit, {
level: level + 1
});
}
return elem;
}
const nodeTypeNames = Object.keys(Node).filter(k => k.match(/_NODE$/)).reduce((obj, k) => (obj[Node[k]] = k.slice(0, -5).toLowerCase(), obj), {
__proto__: null
});
function formatAttrs(attrs) {
return Array.from(attrs, // TODO: Handle quotes within attribute value
attr => `${attr.name}="${attr.value}"`);
}
function formatNode(types, node, level) {
let tag = node.tagName && node.tagName.toLowerCase() || nodeTypeNames[node.nodeType];
switch (node.nodeType) {
case Node.ELEMENT_NODE:
{
let attrs = types.has(Node.ATTRIBUTE_NODE) ? formatAttrs(node.attributes) : [];
return attrs.length > 0 ? `${tag}(${attrs.join(', ')})` : tag;
}
case Node.COMMENT_NODE:
{
let text = node.textContent.trim();
return `//${JSON.stringify(text)}`;
}
case Node.TEXT_NODE:
{
let text = node.textContent.trim();
return text ? JSON.stringify(text) : '';
}
default:
return tag;
}
}
function domStr(elemOrSel = document, {
nodeTypes = [Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE, Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE, Node.COMMENT_NODE, Node.TEXT_NODE],
include = [],
exclude = [],
level = 0
} = {}) {
elemOrSel = typeof elemOrSel === 'string' ? document.querySelector(elemOrSel) : elemOrSel;
let types = new Set(nodeTypes.concat(include).filter(k => !exclude.includes(k)));
let str = '';
walk(elemOrSel, (node, level) => {
if (types.has(node.nodeType)) {
let pad = ' '.repeat(level);
let sn = formatNode(types, node, level);
if (sn) {
str += `${pad}${sn}\n`;
}
}
}, {
level
});
return str;
}
p.domStr = (elemOrSel, comment = undefined, opts = undefined) => {
_output(domStr(elemOrSel, (opts || {}).dom), _comment(comment, elemOrSel || document, `dom`), opts);
};
p.dom = p.domStr;
Object.assign(peek42, {
_output,
Console,
sourceTrace,
formatErrorAsync,
reportError,
cable
});
function _onError(ev) {
reportError(ev.error, {
note: 'uncaught exception'
});
}
function _onUnhandledRejection(ev) {
reportError(ev.reason, {
note: 'unhandled rejection'
});
}
window.addEventListener('error', _onError);
window.addEventListener('unhandledrejection', _onUnhandledRejection);
if (_config.interceptConsole) {
_interceptNativeConsoleFn('log');
_interceptNativeConsoleFn('info');
_interceptNativeConsoleFn('warn');
_interceptNativeConsoleFn('error');
}
if (_config.addGlobals) {
Object.assign(window, {
p,
pp
});
}
if (_config.autoUse) {
window.apivis && use(apivis);
}
return peek42;
}));
//# sourceMappingURL=peek42.browser.js.map