UNPKG

vscode-chrome-debug-core

Version:

A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol

232 lines (230 loc) 8.85 kB
"use strict"; /*--------------------------------------------------------- * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); const Color = require("color"); const variables = require("./variables"); function formatExceptionDetails(e) { if (!e.exception) { return `${e.text || 'Uncaught Error'}\n${stackTraceToString(e.stackTrace)}`; } return (e.exception.className && e.exception.className.endsWith('Error') && e.exception.description) || (`Error: ${variables.getRemoteObjectPreview(e.exception)}\n${stackTraceToString(e.stackTrace)}`); } exports.formatExceptionDetails = formatExceptionDetails; exports.clearConsoleCode = '\u001b[2J'; function formatConsoleArguments(type, args, stackTrace) { switch (type) { case 'log': case 'debug': case 'info': case 'error': case 'warning': case 'dir': case 'timeEnd': case 'count': args = resolveParams(args); break; case 'assert': const formattedParams = args.length ? // 'assert' doesn't support format specifiers resolveParams(args, /*skipFormatSpecifiers=*/ true) : []; const assertMsg = (formattedParams[0] && formattedParams[0].type === 'string') ? formattedParams.shift().value : ''; let outputText = `Assertion failed: ${assertMsg}\n` + stackTraceToString(stackTrace); args = [{ type: 'string', value: outputText }, ...formattedParams]; break; case 'startGroup': case 'startGroupCollapsed': let startMsg = '‹Start group›'; const formattedGroupParams = resolveParams(args); const previewMessage = formattedGroupParams.find(x => x && x.type === 'string'); if (previewMessage) { startMsg += ': ' + previewMessage.value; } args = [{ type: 'string', value: startMsg }, ...formattedGroupParams]; break; case 'endGroup': args = [{ type: 'string', value: '‹End group›' }]; break; case 'trace': args = [{ type: 'string', value: 'console.trace()\n' + stackTraceToString(stackTrace) }]; break; case 'clear': args = [{ type: 'string', value: exports.clearConsoleCode }]; break; default: // Some types we have to ignore return null; } const isError = type === 'assert' || type === 'error'; return { args, isError }; } exports.formatConsoleArguments = formatConsoleArguments; /** * Collapse non-object arguments, and apply format specifiers (%s, %d, etc). Return a reduced a formatted list of RemoteObjects. */ function resolveParams(args, skipFormatSpecifiers) { if (!args.length || args[0].objectId) { // If the first arg is not text, nothing is going to happen here return args; } // Find all %s, %i, etc in the first argument, which is always the main text. Strip % let formatSpecifiers; const firstTextArg = args.shift(); // currentCollapsedStringArg is the accumulated text let currentCollapsedStringArg = variables.getRemoteObjectPreview(firstTextArg, /*stringify=*/ false) + ''; if (firstTextArg.type === 'string' && !skipFormatSpecifiers) { formatSpecifiers = (currentCollapsedStringArg.match(/\%[sidfoOc]/g) || []) .map(spec => spec[1]); } else { formatSpecifiers = []; } const processedArgs = []; const pushStringArg = (strArg) => { if (typeof strArg === 'string') { processedArgs.push({ type: 'string', value: strArg }); } }; // Collapse all text parameters, formatting properly if there's a format specifier for (let argIdx = 0; argIdx < args.length; argIdx++) { const arg = args[argIdx]; const formatSpec = formatSpecifiers.shift(); const formatted = formatArg(formatSpec, arg); currentCollapsedStringArg = currentCollapsedStringArg || ''; if (typeof formatted === 'string') { if (formatSpec) { // If this param had a format specifier, search and replace it with the formatted param. currentCollapsedStringArg = currentCollapsedStringArg.replace('%' + formatSpec, formatted); } else { currentCollapsedStringArg += (currentCollapsedStringArg ? ' ' + formatted : formatted); } } else if (formatSpec) { // `formatted` is an object - split currentCollapsedStringArg around the current formatSpec and add the object const curSpecIdx = currentCollapsedStringArg.indexOf('%' + formatSpec); const processedPart = currentCollapsedStringArg.slice(0, curSpecIdx); if (processedPart) { pushStringArg(processedPart); } currentCollapsedStringArg = currentCollapsedStringArg.slice(curSpecIdx + 2); processedArgs.push(formatted); } else { pushStringArg(currentCollapsedStringArg); currentCollapsedStringArg = null; processedArgs.push(formatted); } } pushStringArg(currentCollapsedStringArg); return processedArgs; } function formatArg(formatSpec, arg) { const paramValue = String(typeof arg.value !== 'undefined' ? arg.value : arg.description); if (formatSpec === 's') { return paramValue; } else if (['i', 'd'].indexOf(formatSpec) >= 0) { return Math.floor(+paramValue) + ''; } else if (formatSpec === 'f') { return +paramValue + ''; } else if (formatSpec === 'c') { return formatColorArg(arg); } else if (formatSpec === 'O') { if (arg.objectId) { return arg; } else { return paramValue; } } else { // No formatSpec, or unsupported formatSpec: // %o - expandable DOM element if (arg.objectId) { return arg; } else { return paramValue; } } } function formatColorArg(arg) { const cssRegex = /\s*(.*?)\s*:\s*(.*?)\s*(?:;|$)/g; let escapedSequence; let match = cssRegex.exec(arg.value); while (match != null) { if (match.length === 3) { if (escapedSequence === undefined) { // Some valid pattern appeared, initialize escapedSequence. // If the pattern has no value like `color:`, then this should remain an empty string. escapedSequence = ''; } if (match[2]) { switch (match[1]) { case 'color': const color = getAnsi16Color(match[2]); if (color) { escapedSequence += `;${color}`; } break; case 'background': const background = getAnsi16Color(match[2]); if (background) { escapedSequence += `;${background + 10}`; } break; case 'font-weight': if (match[2] === 'bold') { escapedSequence += ';1'; } break; case 'text-decoration': if (match[2] === 'underline') { escapedSequence += ';4'; } break; default: } } } match = cssRegex.exec(arg.value); } if (typeof escapedSequence === 'string') { escapedSequence = `\x1b[0${escapedSequence}m`; } return escapedSequence; } function stackTraceToString(stackTrace) { if (!stackTrace) { return ''; } return stackTrace.callFrames .map(frame => { const fnName = frame.functionName || (frame.url ? '(anonymous)' : '(eval)'); const fileName = frame.url ? frame.url : 'eval'; return ` at ${fnName} (${fileName}:${frame.lineNumber + 1}:${frame.columnNumber})`; }) .join('\n'); } function getAnsi16Color(colorString) { try { // Color can parse hex and color names const color = new Color(colorString); return color.ansi16().object().ansi16; } catch (ex) { // Unable to parse Color // For instance, "inherit" color will throw } return undefined; } //# sourceMappingURL=consoleHelper.js.map