UNPKG

eslint-formatter-mo

Version:

Good-lookin' ESLint formatter for delightful readability

153 lines (122 loc) 3.94 kB
import chalk from 'chalk' function locate( source, locations, highlight ) { let lines = source.split( '\n' ) const frameStart = 0 let frameEnd = lines.length while ( !/\S/.test( lines[ lines.length - 1 ] ) ) { lines.pop() frameEnd = frameEnd - 1 } const digits = String( frameEnd ).length + 1 const formattedLines = highlight(source).split('\n') return lines .map( ( str, i ) => { let lineNum = String( i + frameStart + 1 ) while ( lineNum.length < digits ) { lineNum = ` ${ lineNum }` } if ( isErrorLine( frameStart + i + 1, locations ) ) { const ls = getErrorLocations( frameStart + i + 1, locations ) let indicators = ls.map( l => { return { spaceLen: digits + 2 + tabsToSpaces( str.slice( 0, l.column - 1 ) ).length, content: spaces( digits + 2 + tabsToSpaces( str.slice( 0, l.column - 1 ) ).length ) + '└─ ', severity: l.severity, message: l.message, fixable: l.fixable, ruleId: l.ruleId, } } ).sort( ( a, b ) => { return a.spaceLen - b.spaceLen } ) indicators = indicators.reduce( ( memo, indicator, index ) => { let char = '│' if ( index === indicators.length - 1 ) { char = '↑' } const sep = { ignore: true, content: spaces( indicator.content.length ) } const insertIndexes = [] memo.forEach( m => { if ( m.ignore ) { return } indicator.content = replaceAt( indicator.content, m.spaceLen, '│' ) insertIndexes.push( m.spaceLen ) } ) insertIndexes.push( indicator.spaceLen ) sep.content = sep.content.split( '' ) insertIndexes.forEach( i => { sep.content[ i ] = char } ) sep.content = sep.content.join( '' ) sep.content = sep.content.replace( /\s+$/, '' ) memo.push( indicator ) memo.push( sep ) return memo }, [] ) indicators.reverse() indicators.push( { content: '' } ) const lineNo = chalk.dim( lineNum + ':' ) const indentation = tabsToSpaces( formattedLines[ i ] ) const display = i => { if ( i.severity ) { const fixableMessage = i.fixable === true ? chalk.dim( ' ( auto-fixable )' ) : '' const ruleId = i.ruleId ? chalk.dim( ` [ ${ i.ruleId } ]` ) : '' return chalk.dim( i.content ) + `${ i.severity === 'warning' ? chalk.yellow.dim( '⚠' ) : chalk.red( '✖' ) } ` + chalk.dim( i.message ) + ruleId + fixableMessage } return chalk.dim( i.content ) } return `${ lineNo } ${ indentation } ` + `\n${ indicators.map( display ).join( '\n' ) }` } return '' } ) .reduce( ( memo, line ) => { if ( line !== '' ) { memo.push( line ) } else if ( memo[ memo.length - 1 ] !== '' ) { memo.push( line ) } return memo }, [] ) .join( '\n' ) } function spaces( i ) { let result = '' while ( i-- ) { result = result + ' ' } return result } function tabsToSpaces( str ) { return str.replace( /^\t+/, match => match.split( '\t' ).join( ' ' ) ) } function replaceAt( string, index, replacement ) { const array = string.split( '' ) if ( array[ index ] === ' ' ) { // only replace for space array[ index ] = replacement } return array.join( '' ) } function isErrorLine( line, locations = [] ) { return locations.some( l => l.line === line ) } function getErrorLocations( line, locations ) { return locations.filter( l => l.line === line ) } export { locate }