| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- 'use strict'
- var supported = require('supports-color').stderr.hasBasic
- var width = require('string-width')
- var stringify = require('unist-util-stringify-position')
- var repeat = require('repeat-string')
- var statistics = require('vfile-statistics')
- var sort = require('vfile-sort')
- module.exports = reporter
- // Check which characters should be used.
- var windows = process.platform === 'win32'
- // `log-symbols` without chalk:
- /* istanbul ignore next - Windows. */
- var chars = windows ? {error: '×', warning: '‼'} : {error: '✖', warning: '⚠'}
- // Match trailing white-space.
- var trailing = /\s*$/
- // Default filename.
- var defaultName = '<stdin>'
- var noop = {open: '', close: ''}
- var colors = {
- underline: {open: '\u001B[4m', close: '\u001B[24m'},
- red: {open: '\u001B[31m', close: '\u001B[39m'},
- yellow: {open: '\u001B[33m', close: '\u001B[39m'},
- green: {open: '\u001B[32m', close: '\u001B[39m'}
- }
- var noops = {
- underline: noop,
- red: noop,
- yellow: noop,
- green: noop
- }
- var labels = {
- true: 'error',
- false: 'warning',
- null: 'info',
- undefined: 'info'
- }
- // Report a file’s messages.
- function reporter(files, options) {
- var settings = options || {}
- var one
- if (!files) {
- return ''
- }
- // Error.
- if ('name' in files && 'message' in files) {
- return String(files.stack || files)
- }
- // One file.
- if (!('length' in files)) {
- one = true
- files = [files]
- }
- return compile(parse(filter(files, settings), settings), one, settings)
- }
- function filter(files, options) {
- var result = []
- var length = files.length
- var index = -1
- var file
- if (!options.quiet && !options.silent) {
- return files.concat()
- }
- while (++index < length) {
- file = files[index]
- if (applicable(file, options).length !== 0) {
- result.push(file)
- }
- }
- return result
- }
- function parse(files, options) {
- var length = files.length
- var index = -1
- var rows = []
- var all = []
- var locationSize = 0
- var labelSize = 0
- var reasonSize = 0
- var ruleIdSize = 0
- var file
- var destination
- var origin
- var messages
- var offset
- var count
- var message
- var loc
- var reason
- var label
- var id
- while (++index < length) {
- file = files[index]
- destination = file.path
- origin = file.history[0] || destination
- messages = sort({messages: applicable(file, options)}).messages
- if (rows.length !== 0 && rows[rows.length - 1].type !== 'header') {
- rows.push({type: 'separator'})
- }
- rows.push({
- type: 'header',
- origin: origin,
- destination: destination,
- name: origin || options.defaultName || defaultName,
- stored: Boolean(file.stored),
- moved: Boolean(file.stored && destination !== origin),
- stats: statistics(messages)
- })
- offset = -1
- count = messages.length
- while (++offset < count) {
- message = messages[offset]
- id = message.ruleId || ''
- reason = message.stack || message.message
- loc = message.location
- loc = stringify(loc.end.line && loc.end.column ? loc : loc.start)
- if (options.verbose && message.note) {
- reason += '\n' + message.note
- }
- label = labels[message.fatal]
- rows.push({
- location: loc,
- label: label,
- reason: reason,
- ruleId: id,
- source: message.source
- })
- locationSize = Math.max(realLength(loc), locationSize)
- labelSize = Math.max(realLength(label), labelSize)
- reasonSize = Math.max(realLength(reason), reasonSize)
- ruleIdSize = Math.max(realLength(id), ruleIdSize)
- }
- all = all.concat(messages)
- }
- return {
- rows: rows,
- statistics: statistics(all),
- location: locationSize,
- label: labelSize,
- reason: reasonSize,
- ruleId: ruleIdSize
- }
- }
- // eslint-disable-next-line complexity
- function compile(map, one, options) {
- var enabled = options.color
- var all = map.statistics
- var rows = map.rows
- var length = rows.length
- var index = -1
- var lines = []
- var row
- var line
- var style
- var color
- var reason
- var rest
- var position
- if (enabled === null || enabled === undefined) {
- enabled = supported
- }
- style = enabled ? colors : noops
- while (++index < length) {
- row = rows[index]
- if (row.type === 'separator') {
- lines.push('')
- } else if (row.type === 'header') {
- if (one && !options.defaultName && !row.origin) {
- line = ''
- } else {
- color =
- style[row.stats.fatal ? 'red' : row.stats.total ? 'yellow' : 'green']
- line =
- style.underline.open +
- color.open +
- row.name +
- color.close +
- style.underline.close
- line += row.moved ? ' > ' + row.destination : ''
- }
- if (!row.stats.total) {
- line += line ? ': ' : ''
- if (row.stored) {
- line += style.yellow.open + 'written' + style.yellow.close
- } else {
- line += 'no issues found'
- }
- }
- if (line) {
- lines.push(line)
- }
- } else {
- color = style[row.label === 'error' ? 'red' : 'yellow']
- reason = row.reason
- rest = ''
- position = reason.indexOf('\n')
- if (position !== -1) {
- rest = reason.slice(position)
- reason = reason.slice(0, position)
- }
- lines.push(
- [
- '',
- padLeft(row.location, map.location),
- padRight(color.open + row.label + color.close, map.label),
- padRight(reason, map.reason),
- padRight(row.ruleId, map.ruleId),
- row.source || ''
- ]
- .join(' ')
- .replace(trailing, '') + rest
- )
- }
- }
- if (all.fatal || all.warn) {
- line = []
- if (all.fatal) {
- line.push(
- [
- style.red.open + chars.error + style.red.close,
- all.fatal,
- plural(labels.true, all.fatal)
- ].join(' ')
- )
- }
- if (all.warn) {
- line.push(
- [
- style.yellow.open + chars.warning + style.yellow.close,
- all.warn,
- plural(labels.false, all.warn)
- ].join(' ')
- )
- }
- line = line.join(', ')
- if (all.total !== all.fatal && all.total !== all.warn) {
- line = all.total + ' messages (' + line + ')'
- }
- lines.push('', line)
- }
- return lines.join('\n')
- }
- function applicable(file, options) {
- var messages = file.messages
- var length = messages.length
- var index = -1
- var result = []
- if (options.silent) {
- while (++index < length) {
- if (messages[index].fatal) {
- result.push(messages[index])
- }
- }
- } else {
- result = messages.concat()
- }
- return result
- }
- // Get the length of `value`, ignoring ANSI sequences.
- function realLength(value) {
- var length = value.indexOf('\n')
- return width(length === -1 ? value : value.slice(0, length))
- }
- // Pad `value` on the left.
- function padLeft(value, minimum) {
- return repeat(' ', minimum - realLength(value)) + value
- }
- // Pad `value` on the right.
- function padRight(value, minimum) {
- return value + repeat(' ', minimum - realLength(value))
- }
- function plural(value, count) {
- return count === 1 ? value : value + 's'
- }
|