Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sindresorhus/eslint-formatter-pretty
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v5.0.0
Choose a base ref
...
head repository: sindresorhus/eslint-formatter-pretty
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.0.0
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Mar 20, 2023

  1. Fix CI

    sindresorhus committed Mar 20, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    yorickvP Yorick
    Copy the full SHA
    7289acd View commit details

Commits on Oct 28, 2023

  1. Require Node.js 18

    sindresorhus committed Oct 28, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    yorickvP Yorick
    Copy the full SHA
    13383af View commit details
  2. 6.0.0

    sindresorhus committed Oct 28, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    vcunat Vladimír Čunát
    Copy the full SHA
    f31bb17 View commit details
Showing with 171 additions and 164 deletions.
  1. +0 −1 .github/workflows/main.yml
  2. +8 −23 index.d.ts
  3. +74 −76 index.js
  4. +31 −31 index.test-d.ts
  5. +24 −14 package.json
  6. +34 −19 test/test.js
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@ jobs:
fail-fast: false
matrix:
node-version:
- 20
- 18
- 16
- 14
31 changes: 8 additions & 23 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,20 @@
import type {ESLint, Linter} from 'eslint';

export = formatterPretty;

/**
Pretty formatter for [ESLint](https://eslint.org).
@param results - Lint result for the individual files.
@param data - Extended information related to the analysis results.
@returns The formatted output.
*/
declare function formatterPretty(
results: readonly formatterPretty.LintResult[],
data?: ESLint.LintResultData
export default function eslintFormatterPretty(
results: LintResult[],
data?: LintResultData
): string;

declare namespace formatterPretty {
interface LintResult {
readonly filePath: string;
readonly errorCount: number;
readonly warningCount: number;
readonly messages: readonly LintMessage[];
}

type Severity = Linter.Severity | 'warning' | 'error';
export type LintResult = ESLint.LintResult;
export type LintResultData = ESLint.LintResultData;
export type Severity = Linter.Severity;
export type LintMessage = Linter.LintMessage;

interface LintMessage {
readonly severity: Severity;
readonly fatal?: boolean;
readonly line?: number;
readonly column?: number;
readonly message: string;
readonly ruleId?: string | null;
}
}
export {Linter} from 'eslint';
150 changes: 74 additions & 76 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
'use strict';
const path = require('path');
const chalk = require('chalk');
const logSymbols = require('log-symbols');
const plur = require('plur');
const stringWidth = require('string-width');
const ansiEscapes = require('ansi-escapes');
const {supportsHyperlink} = require('supports-hyperlinks');
const getRuleDocs = require('eslint-rule-docs');

module.exports = (results, data) => {
import process from 'node:process';
import path from 'node:path';
import chalk from 'chalk';
import logSymbols from 'log-symbols';
import plur from 'plur';
import stringWidth from 'string-width';
import ansiEscapes from 'ansi-escapes';
import {supportsHyperlink} from 'supports-hyperlinks';
import getRuleDocs from 'eslint-rule-docs';

export default function eslintFormatterPretty(results, data) {
const lines = [];
let errorCount = 0;
let warningCount = 0;
@@ -17,7 +17,7 @@ module.exports = (results, data) => {
let maxMessageWidth = 0;
let showLineNumbers = false;

results
for (const result of results
.sort((a, b) => {
if (a.errorCount === b.errorCount) {
return b.warningCount - a.warningCount;
@@ -32,76 +32,74 @@ module.exports = (results, data) => {
}

return b.errorCount - a.errorCount;
})
.forEach(result => {
const {messages, filePath} = result;
})) {
const {messages, filePath} = result;

if (messages.length === 0) {
return;
}
if (messages.length === 0) {
continue;
}

errorCount += result.errorCount;
warningCount += result.warningCount;
errorCount += result.errorCount;
warningCount += result.warningCount;

if (lines.length !== 0) {
lines.push({type: 'separator'});
}

const firstErrorOrWarning = messages.find(({severity}) => severity === 2) || messages[0];
if (lines.length > 0) {
lines.push({type: 'separator'});
}

lines.push({
type: 'header',
filePath,
relativeFilePath: path.relative('.', filePath),
firstLineCol: firstErrorOrWarning.line + ':' + firstErrorOrWarning.column
});
const firstErrorOrWarning = messages.find(({severity}) => severity === 2) ?? messages[0];

messages
.sort((a, b) => {
if (a.fatal === b.fatal && a.severity === b.severity) {
if (a.line === b.line) {
return a.column < b.column ? -1 : 1;
}
lines.push({
type: 'header',
filePath,
relativeFilePath: path.relative('.', filePath),
firstLineCol: firstErrorOrWarning.line + ':' + firstErrorOrWarning.column,
});

return a.line < b.line ? -1 : 1;
for (const x of messages
.sort((a, b) => {
if (a.fatal === b.fatal && a.severity === b.severity) {
if (a.line === b.line) {
return a.column < b.column ? -1 : 1;
}

if ((a.fatal || a.severity === 2) && (!b.fatal || b.severity !== 2)) {
return 1;
}
return a.line < b.line ? -1 : 1;
}

return -1;
})
.forEach(x => {
let {message} = x;

// Stylize inline code blocks
message = message.replace(/\B`(.*?)`\B|\B'(.*?)'\B/g, (m, p1, p2) => chalk.bold(p1 || p2));

const line = String(x.line || 0);
const column = String(x.column || 0);
const lineWidth = stringWidth(line);
const columnWidth = stringWidth(column);
const messageWidth = stringWidth(message);

maxLineWidth = Math.max(lineWidth, maxLineWidth);
maxColumnWidth = Math.max(columnWidth, maxColumnWidth);
maxMessageWidth = Math.max(messageWidth, maxMessageWidth);
showLineNumbers = showLineNumbers || x.line || x.column;

lines.push({
type: 'message',
severity: (x.fatal || x.severity === 2 || x.severity === 'error') ? 'error' : 'warning',
line,
lineWidth,
column,
columnWidth,
message,
messageWidth,
ruleId: x.ruleId || ''
});
});
});
if ((a.fatal || a.severity === 2) && (!b.fatal || b.severity !== 2)) {
return 1;
}

return -1;
})) {
let {message} = x;

// Stylize inline code blocks
message = message.replaceAll(/\B`(.*?)`\B|\B'(.*?)'\B/g, (m, p1, p2) => chalk.bold(p1 ?? p2));

const line = String(x.line ?? 0);
const column = String(x.column ?? 0);
const lineWidth = stringWidth(line);
const columnWidth = stringWidth(column);
const messageWidth = stringWidth(message);

maxLineWidth = Math.max(lineWidth, maxLineWidth);
maxColumnWidth = Math.max(columnWidth, maxColumnWidth);
maxMessageWidth = Math.max(messageWidth, maxMessageWidth);
showLineNumbers = showLineNumbers || x.line || x.column;

lines.push({
type: 'message',
severity: (x.fatal || x.severity === 2 || x.severity === 'error') ? 'error' : 'warning',
line,
lineWidth,
column,
columnWidth,
message,
messageWidth,
ruleId: x.ruleId ?? '',
});
}
}

let output = '\n';

@@ -135,8 +133,8 @@ module.exports = (results, data) => {
x.severity === 'warning' ? logSymbols.warning : logSymbols.error,
' '.repeat(maxLineWidth - x.lineWidth) + chalk.dim(x.line + chalk.gray(':') + x.column),
' '.repeat(maxColumnWidth - x.columnWidth) + x.message,
' '.repeat(maxMessageWidth - x.messageWidth) +
(ruleUrl && supportsHyperlink(process.stdout) ? ansiEscapes.link(chalk.dim(x.ruleId), ruleUrl) : chalk.dim(x.ruleId))
' '.repeat(maxMessageWidth - x.messageWidth)
+ (ruleUrl && supportsHyperlink(process.stdout) ? ansiEscapes.link(chalk.dim(x.ruleId), ruleUrl) : chalk.dim(x.ruleId)),
];

if (!showLineNumbers) {
@@ -158,4 +156,4 @@ module.exports = (results, data) => {
}

return (errorCount + warningCount) > 0 ? output : '';
};
}
62 changes: 31 additions & 31 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
import type {ESLint} from 'eslint';
import {expectType} from 'tsd';
import formatterPretty = require('.');

// Test type exports
type LintResult = formatterPretty.LintResult;
type LintMessage = formatterPretty.LintMessage;
type Severity = formatterPretty.Severity;
import eslintFormatterPretty, {
type LintResult,
type LintMessage,
type Severity,
} from './index.js';

// Test LintResult interface members
declare const lintResult: LintResult;
expectType<string>(lintResult.filePath);
expectType<number>(lintResult.errorCount);
expectType<number>(lintResult.warningCount);
expectType<readonly LintMessage[]>(lintResult.messages);
expectType<LintMessage[]>(lintResult.messages);

// Test LintMessage interface members
const lintMessage = lintResult.messages[0];
expectType<Severity>(lintMessage.severity);
expectType<string>(lintMessage.message);
expectType<boolean | undefined>(lintMessage.fatal);
expectType<number | undefined>(lintMessage.line);
expectType<number | undefined>(lintMessage.column);
expectType<string | null | undefined>(lintMessage.ruleId);
expectType<true | undefined>(lintMessage.fatal);
expectType<number>(lintMessage.line);
expectType<number>(lintMessage.column);
expectType<string | null >(lintMessage.ruleId); // eslint-disable-line @typescript-eslint/ban-types

// Test formatterPretty()
declare const lintResults: LintResult[];
declare const eslintLintResults: ESLint.LintResult[];
declare const lintResultData: ESLint.LintResultData;

expectType<string>(formatterPretty(lintResults));
expectType<string>(formatterPretty(eslintLintResults));
expectType<string>(formatterPretty(eslintLintResults, lintResultData));

interface PartialLintResult {
filePath: string;
errorCount: number;
warningCount: number;
messages: Array<{
fileName: string;
message: string;
severity: 'error' | 'warning';
line?: number;
column?: number;
}>;
}

declare const partialLintResults: PartialLintResult[];

expectType<string>(formatterPretty(partialLintResults));
expectType<string>(eslintFormatterPretty(lintResults));
expectType<string>(eslintFormatterPretty(eslintLintResults));
expectType<string>(eslintFormatterPretty(eslintLintResults, lintResultData));

// FIXME
// type PartialLintResult = {
// filePath: string;
// errorCount: number;
// warningCount: number;
// messages: Array<{
// fileName: string;
// message: string;
// severity: 0 | 1 | 2;
// line?: number;
// column?: number;
// }>;
// };

// declare const partialLintResults: PartialLintResult[];

// expectType<string>(eslintFormatterPretty(partialLintResults));
38 changes: 24 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-formatter-pretty",
"version": "5.0.0",
"version": "6.0.0",
"description": "Pretty ESLint formatter",
"license": "MIT",
"repository": "sindresorhus/eslint-formatter-pretty",
@@ -10,8 +10,13 @@
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": {
"types": "./index.d.ts",
"default": "./index.js"
},
"engines": {
"node": ">=14.16"
"node": ">=18"
},
"scripts": {
"test": "xo && ava && tsd"
@@ -29,23 +34,28 @@
"validate"
],
"dependencies": {
"@types/eslint": "^8.0.0",
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.0",
"@types/eslint": "^8.44.6",
"ansi-escapes": "^6.2.0",
"chalk": "^5.3.0",
"eslint-rule-docs": "^1.1.235",
"log-symbols": "^4.0.0",
"plur": "^4.0.0",
"string-width": "^4.2.0",
"supports-hyperlinks": "^2.0.0"
"log-symbols": "^6.0.0",
"plur": "^5.1.0",
"string-width": "^7.0.0",
"supports-hyperlinks": "^3.0.0"
},
"devDependencies": {
"ava": "^2.4.0",
"strip-ansi": "^6.0.0",
"tsd": "^0.17.0",
"typescript": "^4.3.2",
"xo": "^0.32.0"
"ava": "^5.3.1",
"strip-ansi": "^7.1.0",
"tsd": "^0.29.0",
"typescript": "^5.2.2",
"xo": "^0.56.0"
},
"ava": {
"serial": true
},
"xo": {
"rules": {
"import/no-extraneous-dependencies": "off"
}
}
}
Loading