diff --git a/src/getESLint.js b/src/getESLint.js index f90ae80..faa1b9c 100644 --- a/src/getESLint.js +++ b/src/getESLint.js @@ -23,13 +23,19 @@ export function loadESLint(options) { // Filter out loader options before passing the options to ESLint. const eslint = new ESLint(getESLintOptions(options)); - const lintFiles = eslint.lintFiles.bind(eslint); return { threads: 1, ESLint, eslint, - lintFiles, + lintFiles: async (files) => { + const results = await eslint.lintFiles(files); + // istanbul ignore else + if (options.fix) { + await ESLint.outputFixes(results); + } + return results; + }, // no-op for non-threaded cleanup: async () => {}, }; diff --git a/src/linter.js b/src/linter.js index ac6a986..07b6c93 100644 --- a/src/linter.js +++ b/src/linter.js @@ -26,9 +26,6 @@ const resultStorage = new WeakMap(); * @returns {{lint: Linter, report: Reporter}} */ export default function linter(options, compilation) { - /** @type {ESLint} */ - let ESLint; - /** @type {ESLint} */ let eslint; @@ -44,7 +41,7 @@ export default function linter(options, compilation) { const crossRunResultStorage = getResultStorage(compilation); try { - ({ ESLint, eslint, lintFiles, cleanup } = getESLint(options)); + ({ eslint, lintFiles, cleanup } = getESLint(options)); } catch (e) { throw new ESLintError(e.message); } @@ -84,12 +81,6 @@ export default function linter(options, compilation) { return {}; } - // if enabled, use eslint autofixing where possible - if (options.fix) { - // @ts-ignore - await ESLint.outputFixes(results); - } - for (const result of results) { crossRunResultStorage[result.filePath] = result; } diff --git a/src/worker.js b/src/worker.js index 8aba7cf..6e5f842 100644 --- a/src/worker.js +++ b/src/worker.js @@ -6,9 +6,15 @@ Object.assign(module.exports, { setup, }); +/** @type {{ new (arg0: import("eslint").ESLint.Options): import("eslint").ESLint; outputFixes: (arg0: import("eslint").ESLint.LintResult[]) => any; }} */ +let ESLint; + /** @type {ESLint} */ let eslint; +/** @type {boolean} */ +let fix; + /** * @typedef {object} setupOptions * @property {string=} eslintPath - import path of eslint @@ -16,8 +22,9 @@ let eslint; * * @param {setupOptions} arg0 - setup worker */ -function setup({ eslintPath, eslintOptions }) { - const { ESLint } = require(eslintPath || 'eslint'); +function setup({ eslintPath, eslintOptions = {} }) { + fix = !!(eslintOptions && eslintOptions.fix); + ({ ESLint } = require(eslintPath || 'eslint')); eslint = new ESLint(eslintOptions); } @@ -25,5 +32,10 @@ function setup({ eslintPath, eslintOptions }) { * @param {string | string[]} files */ async function lintFiles(files) { - return eslint.lintFiles(files); + const result = await eslint.lintFiles(files); + // if enabled, use eslint autofixing where possible + if (fix) { + await ESLint.outputFixes(result); + } + return result; } diff --git a/test/autofix.test.js b/test/autofix.test.js index 6b286f1..8d4c45d 100644 --- a/test/autofix.test.js +++ b/test/autofix.test.js @@ -1,6 +1,6 @@ import { join } from 'path'; -import { copySync, removeSync } from 'fs-extra'; +import { copySync, removeSync, readFileSync } from 'fs-extra'; import pack from './utils/pack'; @@ -15,20 +15,32 @@ describe('autofix stop', () => { removeSync(entry); }); - it('should not throw error if file ok after auto-fixing', (done) => { - const compiler = pack('fixable-clone', { - fix: true, - extensions: ['js', 'cjs', 'mjs'], - overrideConfig: { - rules: { semi: ['error', 'always'] }, - }, - }); - - compiler.run((err, stats) => { - expect(err).toBeNull(); - expect(stats.hasWarnings()).toBe(false); - expect(stats.hasErrors()).toBe(false); - done(); - }); - }); + test.each([[{}], [{ threads: false }]])( + 'should not throw error if file ok after auto-fixing', + (cfg, done) => { + const compiler = pack('fixable-clone', { + ...cfg, + fix: true, + extensions: ['js', 'cjs', 'mjs'], + overrideConfig: { + rules: { semi: ['error', 'always'] }, + }, + }); + + compiler.run((err, stats) => { + expect(err).toBeNull(); + expect(stats.hasWarnings()).toBe(false); + expect(stats.hasErrors()).toBe(false); + expect(readFileSync(entry).toString('utf8')).toMatchInlineSnapshot(` + "function foo() { + return true; + } + + foo(); + " + `); + done(); + }); + } + ); }); diff --git a/test/threads.test.js b/test/threads.test.js index 83f0fa7..820ec34 100644 --- a/test/threads.test.js +++ b/test/threads.test.js @@ -45,9 +45,14 @@ describe('Threading', () => { const mockThread = { parentPort: { on: jest.fn() }, workerData: {} }; const mockLintFiles = jest.fn(); jest.mock('eslint', () => ({ - ESLint: function ESLint() { - this.lintFiles = mockLintFiles; - }, + ESLint: Object.assign( + function ESLint() { + this.lintFiles = mockLintFiles; + }, + { + outputFixes: jest.fn(), + } + ), })); jest.mock('worker_threads', () => mockThread); const { setup, lintFiles } = require('../src/worker'); @@ -55,6 +60,8 @@ describe('Threading', () => { await setup({}); await lintFiles('foo'); expect(mockLintFiles).toHaveBeenCalledWith('foo'); + await setup({ eslintOptions: { fix: true } }); + await lintFiles('foo'); }); }); });