const ansiColors = { bold: ['1', '22'], dim: ['2', '22'], italic: ['3', '23'], underline: ['4', '24'], // 5 & 6 are blinking inverse: ['7', '27'], hidden: ['8', '28'], strike: ['9', '29'], // 10-20 are fonts // 21-29 are resets for 1-9 black: ['30', '39'], red: ['31', '39'], green: ['32', '39'], yellow: ['33', '39'], blue: ['34', '39'], magenta: ['35', '39'], cyan: ['36', '39'], white: ['37', '39'], brightblack: ['30;1', '39'], brightred: ['31;1', '39'], brightgreen: ['32;1', '39'], brightyellow: ['33;1', '39'], brightblue: ['34;1', '39'], brightmagenta: ['35;1', '39'], brightcyan: ['36;1', '39'], brightwhite: ['37;1', '39'], grey: ['90', '39'], } const styles = { special: 'cyan', number: 'yellow', bigint: 'yellow', boolean: 'yellow', undefined: 'grey', null: 'bold', string: 'green', symbol: 'green', date: 'magenta', regexp: 'red', } export const truncator = '…' function colorise(value, styleType) { const color = ansiColors[styles[styleType]] || ansiColors[styleType] if (!color) { return String(value) } return `\u001b[${color[0]}m${String(value)}\u001b[${color[1]}m` } export function normaliseOptions({ showHidden = false, depth = 2, colors = false, customInspect = true, showProxy = false, maxArrayLength = Infinity, breakLength = Infinity, seen = [], // eslint-disable-next-line no-shadow truncate = Infinity, stylize = String, } = {}) { const options = { showHidden: Boolean(showHidden), depth: Number(depth), colors: Boolean(colors), customInspect: Boolean(customInspect), showProxy: Boolean(showProxy), maxArrayLength: Number(maxArrayLength), breakLength: Number(breakLength), truncate: Number(truncate), seen, stylize, } if (options.colors) { options.stylize = colorise } return options } export function truncate(string, length, tail = truncator) { string = String(string) const tailLength = tail.length const stringLength = string.length if (tailLength > length && stringLength > tailLength) { return tail } if (stringLength > length && stringLength > tailLength) { return `${string.slice(0, length - tailLength)}${tail}` } return string } // eslint-disable-next-line complexity export function inspectList(list, options, inspectItem, separator = ', ') { inspectItem = inspectItem || options.inspect const size = list.length if (size === 0) return '' const originalLength = options.truncate let output = '' let peek = '' let truncated = '' for (let i = 0; i < size; i += 1) { const last = i + 1 === list.length const secondToLast = i + 2 === list.length truncated = `${truncator}(${list.length - i})` const value = list[i] // If there is more than one remaining we need to account for a separator of `, ` options.truncate = originalLength - output.length - (last ? 0 : separator.length) const string = peek || inspectItem(value, options) + (last ? '' : separator) const nextLength = output.length + string.length const truncatedLength = nextLength + truncated.length // If this is the last element, and adding it would // take us over length, but adding the truncator wouldn't - then break now if (last && nextLength > originalLength && output.length + truncated.length <= originalLength) { break } // If this isn't the last or second to last element to scan, // but the string is already over length then break here if (!last && !secondToLast && truncatedLength > originalLength) { break } // Peek at the next string to determine if we should // break early before adding this item to the output peek = last ? '' : inspectItem(list[i + 1], options) + (secondToLast ? '' : separator) // If we have one element left, but this element and // the next takes over length, the break early if (!last && secondToLast && truncatedLength > originalLength && nextLength + peek.length > originalLength) { break } output += string // If the next element takes us to length - // but there are more after that, then we should truncate now if (!last && !secondToLast && nextLength + peek.length >= originalLength) { truncated = `${truncator}(${list.length - i - 1})` break } truncated = '' } return `${output}${truncated}` } function quoteComplexKey(key) { if (key.match(/^[a-zA-Z_][a-zA-Z_0-9]*$/)) { return key } return JSON.stringify(key) .replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'") } export function inspectProperty([key, value], options) { options.truncate -= 2 if (typeof key === 'string') { key = quoteComplexKey(key) } else if (typeof key !== 'number') { key = `[${options.inspect(key, options)}]` } options.truncate -= key.length value = options.inspect(value, options) return `${key}: ${value}` }