UNPKG

gulp-eslint

Version:

A gulp plugin for processing files with ESLint

209 lines (182 loc) 5.64 kB
'use strict'; const PluginError = require('plugin-error'); const {CLIEngine} = require('eslint'); const { createIgnoreResult, filterResult, firstResultMessage, handleCallback, isErrorMessage, migrateOptions, resolveFormatter, resolveWritable, transform, tryResultAction, writeResults } = require('./util'); const {relative} = require('path'); /** * Append ESLint result to each file * * @param {(Object|String)} [options] - Configure rules, env, global, and other options for running ESLint * @returns {stream} gulp file stream */ function gulpEslint(options) { options = migrateOptions(options) || {}; const linter = new CLIEngine(options); return transform((file, enc, cb) => { const filePath = relative(process.cwd(), file.path); if (file.isNull()) { cb(null, file); return; } if (file.isStream()) { cb(new PluginError('gulp-eslint', 'gulp-eslint doesn\'t support vinyl files with Stream contents.')); return; } if (linter.isPathIgnored(filePath)) { // Note: // Vinyl files can have an independently defined cwd, but ESLint works relative to `process.cwd()`. // (https://github.com/gulpjs/gulp/blob/master/docs/recipes/specifying-a-cwd.md) // Also, ESLint doesn't adjust file paths relative to an ancestory .eslintignore path. // E.g., If ../.eslintignore has "foo/*.js", ESLint will ignore ./foo/*.js, instead of ../foo/*.js. // Eslint rolls this into `CLIEngine.executeOnText`. So, gulp-eslint must account for this limitation. if (linter.isPathIgnored(filePath) && options.warnFileIgnored) { // Warn that gulp.src is needlessly reading files that ESLint ignores file.eslint = createIgnoreResult(file); } cb(null, file); return; } let result; try { result = linter.executeOnText(file.contents.toString(), filePath).results[0]; } catch (e) { cb(new PluginError('gulp-eslint', e)); return; } // Note: Fixes are applied as part of "executeOnText". // Any applied fix messages have been removed from the result. if (options.quiet) { // ignore warnings file.eslint = filterResult(result, options.quiet); } else { file.eslint = result; } // Update the fixed output; otherwise, fixable messages are simply ignored. if (file.eslint.hasOwnProperty('output')) { file.contents = Buffer.from(file.eslint.output); file.eslint.fixed = true; } cb(null, file); }); } /** * Handle each ESLint result as it passes through the stream. * * @param {Function} action - A function to handle each ESLint result * @returns {stream} gulp file stream */ gulpEslint.result = action => { if (typeof action !== 'function') { throw new Error('Expected callable argument'); } return transform((file, enc, done) => { if (file.eslint) { tryResultAction(action, file.eslint, handleCallback(done, file)); } else { done(null, file); } }); }; /** * Handle all ESLint results at the end of the stream. * * @param {Function} action - A function to handle all ESLint results * @returns {stream} gulp file stream */ gulpEslint.results = function(action) { if (typeof action !== 'function') { throw new Error('Expected callable argument'); } const results = []; results.errorCount = 0; results.warningCount = 0; return transform((file, enc, done) => { if (file.eslint) { results.push(file.eslint); // collect total error/warning count results.errorCount += file.eslint.errorCount; results.warningCount += file.eslint.warningCount; } done(null, file); }, done => { tryResultAction(action, results, handleCallback(done)); }); }; /** * Fail when an ESLint error is found in ESLint results. * * @returns {stream} gulp file stream */ gulpEslint.failOnError = () => { return gulpEslint.result(result => { const error = firstResultMessage(result, isErrorMessage); if (!error) { return; } throw new PluginError('gulp-eslint', { name: 'ESLintError', fileName: result.filePath, message: error.message, lineNumber: error.line }); }); }; /** * Fail when the stream ends if any ESLint error(s) occurred * * @returns {stream} gulp file stream */ gulpEslint.failAfterError = () => { return gulpEslint.results(results => { const count = results.errorCount; if (!count) { return; } throw new PluginError('gulp-eslint', { name: 'ESLintError', message: 'Failed with ' + count + (count === 1 ? ' error' : ' errors') }); }); }; /** * Format the results of each file individually. * * @param {(String|Function)} [formatter=stylish] - The name or function for a ESLint result formatter * @param {(Function|Stream)} [writable=fancy-log] - A funtion or stream to write the formatted ESLint results. * @returns {stream} gulp file stream */ gulpEslint.formatEach = (formatter, writable) => { formatter = resolveFormatter(formatter); writable = resolveWritable(writable); return gulpEslint.result(result => writeResults([result], formatter, writable)); }; /** * Wait until all files have been linted and format all results at once. * * @param {(String|Function)} [formatter=stylish] - The name or function for a ESLint result formatter * @param {(Function|stream)} [writable=fancy-log] - A funtion or stream to write the formatted ESLint results. * @returns {stream} gulp file stream */ gulpEslint.format = (formatter, writable) => { formatter = resolveFormatter(formatter); writable = resolveWritable(writable); return gulpEslint.results(results => { // Only format results if files has been lint'd if (results.length) { writeResults(results, formatter, writable); } }); }; module.exports = gulpEslint;