File size: 4,963 Bytes
369fac9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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}`
}