Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom eslint formatter #2138

Merged
merged 5 commits into from
May 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/react-dev-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,36 @@ clearConsole();
console.log('Just cleared the screen!');
```

#### `eslintFormatter(results: Object): string`

This is our custom ESLint formatter that integrates well with Create React App console output.
You can use the default one instead if you prefer so.

```js
const eslintFormatter = require('react-dev-utils/eslintFormatter');

// In your webpack config:
// ...
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: paths.appSrc,
enforce: 'pre',
use: [
{
loader: 'eslint-loader',
options: {
// Pass the formatter:
formatter: eslintFormatter,
},
},
],
}
]
}
```

#### `FileSizeReporter`

##### `measureFileSizesBeforeBuild(buildFolder: string): Promise<OpaqueFileSizes>`
Expand Down
71 changes: 71 additions & 0 deletions packages/react-dev-utils/eslintFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

const chalk = require('chalk');
const table = require('text-table');

function isError(message) {
if (message.fatal || message.severity === 2) {
return true;
}
return false;
}

function formatter(results) {
let output = '\n';

let hasErrors = false;
let hasWarnings = false;

results.forEach(result => {
let messages = result.messages;
if (messages.length === 0) {
return;
}

let hasErrors = false;
messages = messages.map(message => {
let messageType;
if (isError(message)) {
messageType = 'error';
hasErrors = true;
} else {
messageType = 'warn';
hasWarnings = true;
}

let line = message.line || 0;
let column = message.column || 0;
let position = chalk.dim(`${line}:${column}`);
return [
'',
position,
messageType,
message.message.replace(/\.$/, ''),
chalk.dim(message.ruleId || ''),
];
});

// if there are error messages, we want to show only errors
if (hasErrors) {
messages = messages.filter(m => m[2] === 'error');
}

// add color to messageTypes
messages.forEach(m => {
m[2] = m[2] === 'error' ? chalk.red(m[2]) : chalk.yellow(m[2]);
});

let outputTable = table(messages, {
align: ['l', 'l', 'l'],
stringLength(str) {
return chalk.stripColor(str).length;
},
});

output += `${outputTable}\n\n`;
});

return output;
}

module.exports = formatter;
60 changes: 2 additions & 58 deletions packages/react-dev-utils/formatWebpackMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// This is quite hacky and hopefully won't be needed when Webpack fixes this.
// https://github.com/webpack/webpack/issues/2878

var chalk = require('chalk');
var friendlySyntaxErrorLabel = 'Syntax error:';

function isLikelyASyntaxError(message) {
Expand Down Expand Up @@ -85,65 +86,8 @@ function formatMessage(message, isError) {
);
}

// TODO: Ideally we should write a custom ESLint formatter instead.

// If the second line already includes a filename, and it's a warning,
// this is likely coming from ESLint. Skip it because Webpack also prints it.
// Let's omit that in this case.
var BEGIN_ESLINT_FILENAME = String.fromCharCode(27) + '[4m';
// Also filter out ESLint summaries for each file
var BEGIN_ESLINT_WARNING_SUMMARY = String.fromCharCode(27) +
'[33m' +
String.fromCharCode(27) +
'[1m' +
String.fromCharCode(10006);
var BEGIN_ESLINT_ERROR_SUMMARY = String.fromCharCode(27) +
'[31m' +
String.fromCharCode(27) +
'[1m' +
String.fromCharCode(10006);
// ESLint puts separators like this between groups. We don't need them:
var ESLINT_EMPTY_SEPARATOR = String.fromCharCode(27) +
'[22m' +
String.fromCharCode(27) +
'[39m';
// Go!
lines = lines.filter(function(line) {
if (line === ESLINT_EMPTY_SEPARATOR) {
return false;
}
if (
line.indexOf(BEGIN_ESLINT_FILENAME) === 0 ||
line.indexOf(BEGIN_ESLINT_WARNING_SUMMARY) === 0 ||
line.indexOf(BEGIN_ESLINT_ERROR_SUMMARY) === 0
) {
return false;
}
return true;
});

var ESLINT_WARNING_LABEL = String.fromCharCode(27) +
'[33m' +
'warning' +
String.fromCharCode(27) +
'[39m';
// If there were errors, omit any warnings.
if (isError) {
lines = lines.filter(function(line) {
return line.indexOf(ESLINT_WARNING_LABEL) === -1;
});
}

// Prepend filename with an explanation.
lines[0] =
// Underline
String.fromCharCode(27) +
'[4m' +
// Filename
lines[0] +
// End underline
String.fromCharCode(27) +
'[24m' +
lines[0] = chalk.underline(lines[0]) +
(isError ? ' contains errors.' : ' contains warnings.');

// Reassemble the message.
Expand Down
1 change: 1 addition & 0 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"checkRequiredFiles.js",
"clearConsole.js",
"crashOverlay.js",
"eslintFormatter.js",
"FileSizeReporter.js",
"formatWebpackMessages.js",
"getProcessForPort.js",
Expand Down
7 changes: 4 additions & 3 deletions packages/react-scripts/config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const getClientEnvironment = require('./env');
const paths = require('./paths');

Expand Down Expand Up @@ -120,16 +121,16 @@ module.exports = {
enforce: 'pre',
use: [
{
// @remove-on-eject-begin
// Point ESLint to our predefined config.
options: {
formatter: eslintFormatter,
// @remove-on-eject-begin
baseConfig: {
extends: ['react-app'],
},
ignore: false,
useEslintrc: false,
// @remove-on-eject-end
},
// @remove-on-eject-end
loader: 'eslint-loader',
},
],
Expand Down
8 changes: 5 additions & 3 deletions packages/react-scripts/config/webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const paths = require('./paths');
const getClientEnvironment = require('./env');

Expand Down Expand Up @@ -117,17 +118,18 @@ module.exports = {
enforce: 'pre',
use: [
{
// @remove-on-eject-begin
// Point ESLint to our predefined config.
options: {
formatter: eslintFormatter,
// @remove-on-eject-begin
// TODO: consider separate config for production,
// e.g. to enable no-console and no-debugger only in production.
baseConfig: {
extends: ['react-app'],
},
ignore: false,
useEslintrc: false,
// @remove-on-eject-end
},
// @remove-on-eject-end
loader: 'eslint-loader',
},
],
Expand Down
14 changes: 7 additions & 7 deletions packages/react-scripts/scripts/utils/createWebpackCompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,17 @@ module.exports = function createWebpackCompiler(config, onReadyCallback) {
console.log(message);
console.log();
});

// Teach some ESLint tricks.
console.log('You may use special comments to disable some warnings.');
console.log(
'Use ' +
chalk.yellow('// eslint-disable-next-line') +
' to ignore the next line.'
'Search the ' +
chalk.dim('keywords') +
' from the right column to learn more.'
);
console.log(
'Use ' +
chalk.yellow('/* eslint-disable */') +
' to ignore all warnings in a file.'
'To ignore, add ' +
chalk.yellow('// eslint-disable-next-line') +
' to the line before.'
);
}
});
Expand Down