UNPKG

peek42

Version:

Touch based browser console

1,206 lines (983 loc) 30.5 kB
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\">&#x25b8;</div>\n <div class=\"peek42-bar1-control peek42-entries-expand\">&#x25be;</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 = '&#x25be;'; elBody.style.display = ''; } function _logEntryCollapse(elToggle, elBody) { elToggle.innerHTML = '&#x25b8;'; 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">&#x25be;</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); } export default peek42; export { pretty, p, pp }; //# sourceMappingURL=peek42.browser.mjs.map