diff --git a/lib/caches.js b/lib/caches.js new file mode 100644 index 0000000..f5dc37c --- /dev/null +++ b/lib/caches.js @@ -0,0 +1,62 @@ +'use strict'; + +const path = require('path'); +const LRU = require('nanolru'); +const resolver = require('./resolver'); +const eslint_path = require('./eslint-path'); +const files_hash = require('./files-hash'); + +const lru_cache = new LRU(10); +const check_files = [ + 'package.json', + 'package-lock.json', + 'npm-shrinkwrap.json', + 'yarn.lock', + 'pnpm-lock.yaml' +]; + +exports.lru_cache = lru_cache; + +exports.getCache = getCache; + +async function getCache(cwd, eslint_path_arg) { + let cache = lru_cache.get(cwd); + if (!cache) { + cache = createCache(cwd, eslint_path_arg); + if (cache) { + cache.filesChanged = await files_hash.filesHash(cwd, check_files); + } + return cache; + } + const { filesChanged } = cache; + if (filesChanged && await filesChanged()) { + clearRequireCache(cwd); + cache = createCache(cwd, eslint_path_arg); + cache.filesChanged = filesChanged; + } + return cache; +} + +function createCache(cwd, eslint_path_arg) { + const absolute_eslint_path = eslint_path.resolve(cwd, eslint_path_arg); + + if (!absolute_eslint_path) { + return null; + } + + return lru_cache.set(cwd, { + eslint: require(absolute_eslint_path), + // use chalk from eslint + chalk: require(resolver.resolve('chalk', { + paths: [path.dirname(absolute_eslint_path)] + })) + }); +} + +function clearRequireCache(cwd) { + Object.keys(require.cache) + .filter(key => key.startsWith(cwd)) + .forEach((key) => { + delete require.cache[key]; + }); +} diff --git a/lib/linter.js b/lib/linter.js index fbdedca..8935684 100644 --- a/lib/linter.js +++ b/lib/linter.js @@ -3,11 +3,9 @@ const fs = require('fs'); const path = require('path'); -const LRU = require('nanolru'); -const resolver = require('./resolver'); -const eslint_path = require('./eslint-path'); const options_cliengine = require('./options-cliengine'); const options_eslint = require('./options-eslint'); +const caches = require('./caches'); function translateOptionsCLIEngine(cliOptions, cwd) { return { @@ -82,32 +80,6 @@ function translateOptionsESLint(cliOptions, cwd) { }; } -const eslintCache = new LRU(10); - -function createCache(cwd, eslint_path_arg) { - const absolute_eslint_path = eslint_path.resolve(cwd, eslint_path_arg); - - if (!absolute_eslint_path) { - return false; - } - - return eslintCache.set(cwd, { - eslint: require(absolute_eslint_path), - // use chalk from eslint - chalk: require(resolver.resolve('chalk', { - paths: [path.dirname(absolute_eslint_path)] - })) - }); -} - -function clearRequireCache(cwd) { - Object.keys(require.cache) - .filter(key => key.startsWith(cwd)) - .forEach((key) => { - delete require.cache[key]; - }); -} - function countErrors(results) { let errorCount = 0; let warningCount = 0; @@ -280,7 +252,7 @@ function executeWithCLIEngine(CLIEngine, cwd, opts, text, callback) { /* * The core_d service entry point. */ -exports.invoke = async function (cwd, args, text, hash, callback) { +exports.invoke = async function (cwd, args, text, callback) { process.chdir(cwd); let eslint_path_arg; @@ -297,18 +269,11 @@ exports.invoke = async function (cwd, args, text, hash, callback) { } } - let cache = eslintCache.get(cwd); - if (!cache) { - cache = createCache(cwd, eslint_path_arg); - } else if (hash !== cache.hash) { - clearRequireCache(cwd); - cache = createCache(cwd, eslint_path_arg); - } + const cache = await caches.getCache(cwd, eslint_path_arg); if (!cache) { callback(null); return; } - cache.hash = hash; const options = cache.eslint.ESLint ? options_eslint @@ -351,13 +316,11 @@ exports.invoke = async function (cwd, args, text, hash, callback) { } }; -exports.cache = eslintCache; - /* * The core_d status hook. */ exports.getStatus = function () { - const { keys } = eslintCache; + const { keys } = caches.lru_cache; if (keys.length === 0) { return 'No instances cached.'; } diff --git a/package-lock.json b/package-lock.json index d0ede50..c9b1900 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "12.1.0", "license": "MIT", "dependencies": { - "core_d": "^4.0.0", + "core_d": "^5.0.1", "eslint": "^8.12.0", "nanolru": "^1.0.0", "optionator": "^0.9.1" @@ -431,9 +431,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "node_modules/core_d": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/core_d/-/core_d-4.0.0.tgz", - "integrity": "sha512-dBxd0Ocxj3D3K+rJxutTAZ9LQHkuMZoc9HPWYwYRYK7swou5wuIRXxgJ39YLNDvFHfHyV3JbxVYluF/AOhcRnw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/core_d/-/core_d-5.0.1.tgz", + "integrity": "sha512-37lZyhJY1hzgFbfU4LzY4zL09QPwPfV2W/3YBOtN7mkdvVaeP1OVnDZI6zxggtlPwG/BuE5wIr0xptlVJk5EPA==", "dependencies": { "supports-color": "^8.1.0" } @@ -2644,9 +2644,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "core_d": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/core_d/-/core_d-4.0.0.tgz", - "integrity": "sha512-dBxd0Ocxj3D3K+rJxutTAZ9LQHkuMZoc9HPWYwYRYK7swou5wuIRXxgJ39YLNDvFHfHyV3JbxVYluF/AOhcRnw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/core_d/-/core_d-5.0.1.tgz", + "integrity": "sha512-37lZyhJY1hzgFbfU4LzY4zL09QPwPfV2W/3YBOtN7mkdvVaeP1OVnDZI6zxggtlPwG/BuE5wIr0xptlVJk5EPA==", "requires": { "supports-color": "^8.1.0" }, diff --git a/package.json b/package.json index a470644..d92864d 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "url": "https://github.com/mantoni/eslint_d.js.git" }, "dependencies": { - "core_d": "^4.0.0", + "core_d": "^5.0.1", "eslint": "^8.12.0", "nanolru": "^1.0.0", "optionator": "^0.9.1" diff --git a/test/caches-test.js b/test/caches-test.js new file mode 100644 index 0000000..102625d --- /dev/null +++ b/test/caches-test.js @@ -0,0 +1,110 @@ +/*eslint-env mocha*/ +'use strict'; + +const { assert, refute, sinon } = require('@sinonjs/referee-sinon'); +const eslint_path = require('../lib/eslint-path'); +const files_hash = require('../lib/files-hash'); +const { getCache, lru_cache } = require('../lib/caches'); + +describe('test/caches', () => { + const cwd = process.cwd(); + + afterEach(() => { + lru_cache.clear(); + sinon.restore(); + }); + + it('calls eslint_path.resolve with cwd and eslint_path_arg', async () => { + sinon.replace(eslint_path, 'resolve', sinon.fake.returns(null)); + + await getCache(cwd, 'something'); + + assert.calledOnceWith(eslint_path.resolve, cwd, 'something'); + }); + + it('calls filesHash with cwd and common package manager files', async () => { + sinon.replace(files_hash, 'filesHash', sinon.fake.resolves(() => {})); + + await getCache(cwd); + + assert.calledOnceWith(files_hash.filesHash, cwd, [ + 'package.json', + 'package-lock.json', + 'npm-shrinkwrap.json', + 'yarn.lock', + 'pnpm-lock.yaml' + ]); + }); + + it('creates a new cache with filesChanged', async () => { + const filesChanged = sinon.fake(); + sinon.replace(files_hash, 'filesHash', sinon.fake.resolves(filesChanged)); + + const cache = await getCache(cwd); + + refute.isNull(cache); + assert.same(lru_cache.get(cwd), cache); + assert.same(cache.filesChanged, filesChanged); + }); + + it('returns null if absolute eslint path cannot be resolved', async () => { + sinon.replace(files_hash, 'filesHash', sinon.fake()); + sinon.replace(eslint_path, 'resolve', sinon.fake.returns(null)); + + const cache = await getCache('./some/path'); + + assert.isNull(cache); + refute.called(files_hash.filesHash); + }); + + it('returns same cache on second call if filesChanged is null', async () => { + sinon.replace(files_hash, 'filesHash', sinon.fake.resolves(null)); + + const cache_1 = await getCache(cwd); + const cache_2 = await getCache(cwd); + + assert.same(cache_1, cache_2); + }); + + it('returns same cache on second call if filesChanged returns false', + async () => { + const filesChanged = sinon.fake.resolves(false); + sinon.replace(files_hash, 'filesHash', sinon.fake.resolves(filesChanged)); + + const cache_1 = await getCache(cwd); + const cache_2 = await getCache(cwd); + + assert.calledOnce(filesChanged); + assert.same(cache_1, cache_2); + }); + + it('returns new cache on second call if filesChanged returns true', + async () => { + const filesChanged = sinon.fake.resolves(true); + sinon.replace(files_hash, 'filesHash', sinon.fake.resolves(filesChanged)); + + const cache_1 = await getCache(cwd); + const cache_2 = await getCache(cwd); + + assert.calledOnce(filesChanged); + refute.same(cache_1, cache_2); + assert.same(cache_1.filesChanged, cache_2.filesChanged); + }); + + it('returns new cache on second call if cwd is different', + async () => { + sinon.replace(files_hash, 'filesHash', + sinon.fake(() => Promise.resolve(sinon.fake()))); + + const cache_1 = await getCache(cwd); + const cache_2 = await getCache('./other/path'); + + refute.same(cache_1, cache_2); + assert.calledTwice(files_hash.filesHash); + assert.calledWith(files_hash.filesHash, cwd); + assert.calledWith(files_hash.filesHash, './other/path'); + refute.same(cache_1.filesChanged, cache_2.filesChanged); + refute.called(cache_1.filesChanged); + refute.called(cache_2.filesChanged); + }); +}); diff --git a/test/linter-test.js b/test/linter-test.js index 01a10d5..35c0ca2 100644 --- a/test/linter-test.js +++ b/test/linter-test.js @@ -6,6 +6,8 @@ const path = require('path'); const resolver = require('../lib/resolver'); const semver = require('semver'); const { assert, refute, sinon, match } = require('@sinonjs/referee-sinon'); +const files_hash = require('../lib/files-hash'); +const caches = require('../lib/caches'); const linter = require('../lib/linter'); describe('linter', () => { @@ -17,7 +19,7 @@ describe('linter', () => { afterEach(() => { sinon.restore(); - linter.cache.clear(); + caches.lru_cache.clear(); }); describe('instance caching', () => { @@ -26,13 +28,30 @@ describe('linter', () => { sinon.spy(resolver, 'resolve'); }); - it('reuses instance from cache', async () => { - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); - const cache1 = linter.cache.get(cwd); - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); - const cache2 = linter.cache.get(cwd); + it('checks hash of common package manager files', async () => { + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(false))); + + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); - assert.equals(linter.cache.length, 1); + assert.calledOnceWith(files_hash.filesHash, cwd, [ + 'package.json', + 'package-lock.json', + 'npm-shrinkwrap.json', + 'yarn.lock', + 'pnpm-lock.yaml' + ]); + }); + + it('reuses instance from cache', async () => { + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(false))); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); + const cache1 = caches.lru_cache.get(cwd); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); + const cache2 = caches.lru_cache.get(cwd); + + assert.equals(caches.lru_cache.length, 1); assert.same(cache1, cache2, 'Cache recreated'); assert.same(cache1.eslint, cache2.eslint); assert.calledTwice(resolver.resolve); @@ -41,24 +60,28 @@ describe('linter', () => { }); it('uses new instance for different directory', async () => { + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(false))); const cwd2 = path.join(cwd, 'test'); - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); - await linter.invoke(cwd2, ['--stdin'], '\'use strict\';', 'a', () => {}); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); + await linter.invoke(cwd2, ['--stdin'], '\'use strict\';', () => {}); - assert.equals(linter.cache.length, 2); + assert.equals(caches.lru_cache.length, 2); assert.callCount(resolver.resolve, 4); assert.calledWithMatch(resolver.resolve, 'eslint', { paths: [cwd] }); assert.calledWithMatch(resolver.resolve, 'eslint', { paths: [cwd2] }); }); it('creates new instance if hash differs from first call', async () => { - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); - const cache1 = linter.cache.get(cwd); + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(true))); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); + const cache1 = caches.lru_cache.get(cwd); - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'b', () => {}); - const cache2 = linter.cache.get(cwd); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); + const cache2 = caches.lru_cache.get(cwd); - assert.equals(linter.cache.length, 1); + assert.equals(caches.lru_cache.length, 1); refute.same(cache1, cache2); refute.same(cache1.eslint, cache2.eslint, 'require.cache cleared'); assert.callCount(resolver.resolve, 4); @@ -66,25 +89,32 @@ describe('linter', () => { it('does not create cache and exits when not resolving eslint', async () => { + sinon.replace(files_hash, 'filesHash', sinon.fake()); const callback = sinon.fake(); sinon.replace(resolver, 'resolve', sinon.fake.returns(undefined)); - await linter.invoke( - cwd, - ['--stdin'], - '\'use strict\';', 1234, callback - ); - const cache = linter.cache.get(cwd); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', callback); + const cache = caches.lru_cache.get(cwd); assert.calledOnce(callback); - assert.equals(linter.cache.length, 0); + assert.equals(caches.lru_cache.length, 0); assert.isUndefined(cache); + refute.called(files_hash.filesHash); } ); }); describe('getStatus', () => { + beforeEach(() => { + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(false))); + }); + + afterEach(() => { + sinon.restore(); + }); + it('has no instances', () => { const status = linter.getStatus(); @@ -92,7 +122,7 @@ describe('linter', () => { }); it('has one instance', async () => { - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); const status = linter.getStatus(); @@ -100,9 +130,9 @@ describe('linter', () => { }); it('has two instances', async () => { - await linter.invoke(cwd, ['--stdin'], '\'use strict\';', 'a', () => {}); + await linter.invoke(cwd, ['--stdin'], '\'use strict\';', () => {}); await linter.invoke(path.join(cwd, 'test'), ['--stdin'], - '\'use strict\';', 'a', () => {}); + '\'use strict\';', () => {}); const status = linter.getStatus(); @@ -127,6 +157,12 @@ describe('linter', () => { beforeEach(() => { callback = sinon.fake(); + sinon.replace(files_hash, 'filesHash', + sinon.fake.resolves(() => Promise.resolve(false))); + }); + + afterEach(() => { + sinon.restore(); }); it('has expected eslint version', () => { @@ -150,7 +186,7 @@ describe('linter', () => { if (semver.gte(semver.coerce(eslint_version), '6.0.0')) { it('fails when linting nonexistent file and sets exit code to 2', async () => { - await linter.invoke(dir, ['bad-filename'], '', 'a', callback); + await linter.invoke(dir, ['bad-filename'], '', callback); assert.calledOnceWith(callback, match({ exitCode: 2 @@ -163,7 +199,7 @@ describe('linter', () => { '--resolve-plugins-relative-to', plugin_folder, '-c', plugin_eslintrc, fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, match({ exitCode: 2 @@ -177,14 +213,13 @@ describe('linter', () => { describe('single file', () => { it('succeeds on lib/linter.js', async () => { - await linter.invoke(dir, [lib_linter], '', 'a', callback); + await linter.invoke(dir, [lib_linter], '', callback); assert.calledOnceWith(callback, null, ''); }); it('fails on test/fixture/fail.txt', async () => { - await linter.invoke(dir, [fixture_fail, '-f', 'unix'], '', 'a', - callback); + await linter.invoke(dir, [fixture_fail, '-f', 'unix'], '', callback); assert.calledWithMatch(callback, '/fail.txt:3:13:'); assert.calledWithMatch(callback, @@ -197,7 +232,7 @@ describe('linter', () => { it('runs on --stdin text', async () => { await linter.invoke(dir, ['--stdin', '-f', 'unix'], - 'console.log();', 'a', callback); + 'console.log();', callback); assert.calledWithMatch(callback, ':1:1: Use the global ' + 'form of \'use strict\'. [Error/strict]'); @@ -209,20 +244,20 @@ describe('linter', () => { it('returns fixed script', async () => { await linter.invoke(dir, ['--stdin', '--fix-to-stdout'], - 'console.log( "!" )\n', 'a', callback); + 'console.log( "!" )\n', callback); assert.calledOnceWith(callback, null, 'console.log(\'!\');\n'); }); it('returns fixed script also with --quiet', async () => { await linter.invoke(dir, ['--stdin', '--fix-to-stdout', '--quiet'], - 'console.log( "!" )\n', 'a', callback); + 'console.log( "!" )\n', callback); assert.calledOnceWith(callback, null, 'console.log(\'!\');\n'); }); it('fails if --stdin is not given', async () => { - await linter.invoke(dir, ['--fix-to-stdout', '.'], '', 'a', callback); + await linter.invoke(dir, ['--fix-to-stdout', '.'], '', callback); assert.calledOnceWith(callback, 'The --fix-to-stdout option must be used with --stdin.'); @@ -230,7 +265,7 @@ describe('linter', () => { it('returns input if nothing to fix', async () => { await linter.invoke(dir, ['--stdin', '--fix-to-stdout'], - 'console.log(\'!\');\n', 'a', callback); + 'console.log(\'!\');\n', callback); assert.calledOnceWith(callback, null, 'console.log(\'!\');\n'); }); @@ -245,7 +280,7 @@ describe('linter', () => { it('does not fail and does not return fixed script', async () => { await linter.invoke(dir, ['--fix-dry-run', '--stdin', '--fix-to-stdout'], - 'console.log( "!" )\n', 'a', callback); + 'console.log( "!" )\n', callback); assert.calledOnceWith(callback, null, 'console.log( "!" )\n'); }); @@ -257,7 +292,7 @@ describe('linter', () => { it('fails with --stdin', async () => { await linter.invoke(dir, ['--stdin', '--print-config'], - 'console.log( "!" )\n', 'a', callback); + 'console.log( "!" )\n', callback); const expected = semver.gte(semver.coerce(eslint_version), '7.0.0') ? 'The --print-config option must be used with exactly one ' @@ -270,7 +305,7 @@ describe('linter', () => { it('fails with --stdin and positional argument', async () => { await linter.invoke(dir, ['--stdin', '--print-config', '.'], - 'console.log( "!" )\n', 'a', callback); + 'console.log( "!" )\n', callback); assert.calledOnceWith(callback, 'The --print-config option is ' + 'not available for piped-in code.'); @@ -279,7 +314,7 @@ describe('linter', () => { it('does not fail with --print-config and a filename', async () => { const args = ['--print-config', fixture_warn]; - await linter.invoke(dir, args, '', 'a', callback); + await linter.invoke(dir, args, '', callback); assert.matchJson(callback.firstCall.args[1], { rules: match.defined @@ -291,9 +326,8 @@ describe('linter', () => { describe('--config', () => { it('lints file based on rules in specified config file', async () => { - await linter.invoke(dir, [fixture_fail, '-f', 'unix', - '--config', no_semi_eslintrc], '', 'a', - callback); + await linter.invoke(dir, [fixture_fail, '-f', 'unix', '--config', + no_semi_eslintrc], '', callback); assert.calledWithMatch(callback, '/fail.txt:3:13:'); assert.calledWithMatch(callback, @@ -305,15 +339,13 @@ describe('linter', () => { describe('--quiet', () => { it('prints warnings by default', async () => { - await linter.invoke(dir, [fixture_warn, '-f', 'unix'], '', 'a', - callback); + await linter.invoke(dir, [fixture_warn, '-f', 'unix'], '', callback); assert.calledOnceWith(callback, null, match('Warning')); }); it('does not print warnings', async () => { - await linter.invoke(dir, ['--quiet', fixture_warn], '', 'a', - callback); + await linter.invoke(dir, ['--quiet', fixture_warn], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -323,15 +355,15 @@ describe('linter', () => { describe('--max-warnings', () => { it('returns output as error on failure', async () => { - await linter.invoke(dir, - [fixture_warn, '--max-warnings', '0'], '', 'a', callback); + await linter.invoke(dir, [fixture_warn, '--max-warnings', '0'], '', + callback); assert.calledOnceWith(callback, match.string); }); it('does not return output as error if not exceeded', async () => { await linter.invoke(dir, [fixture_warn, '--max-warnings', '1'], '', - 'a', callback); + callback); assert.calledOnceWith(callback, null, match.string); }); @@ -341,21 +373,20 @@ describe('linter', () => { describe('--color', () => { it('enables color by default', async () => { - await linter.invoke(dir, ['--stdin'], '\'use strict\';', 'a', - () => {}); + await linter.invoke(dir, ['--stdin'], '\'use strict\';', () => {}); assert.isTrue( - linter.cache.get(dir).chalk.enabled - && linter.cache.get(dir).chalk.level !== 0); + caches.lru_cache.get(dir).chalk.enabled + && caches.lru_cache.get(dir).chalk.level !== 0); }); it('disables color if --no-color is passed', async () => { await linter.invoke(dir, ['--stdin', '--no-color'], - '\'use strict\';', 'a', () => {}); + '\'use strict\';', () => {}); assert.isFalse( - linter.cache.get(dir).chalk.enabled - && linter.cache.get(dir).chalk.level !== 0); + caches.lru_cache.get(dir).chalk.enabled + && caches.lru_cache.get(dir).chalk.level !== 0); }); }); @@ -370,7 +401,7 @@ describe('linter', () => { it('fails with parse error on test/fixture/es6.txt', async () => { await linter.invoke(dir, [ '--parser-options=ecmaVersion:5', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnce(callback); const out = callback.firstCall.args[0]; @@ -384,9 +415,9 @@ describe('linter', () => { }); it('pass on test/fixture/es6.txt', async () => { - linter.invoke(dir, [ + await linter.invoke(dir, [ '--parser-options=ecmaVersion:6', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -400,7 +431,7 @@ describe('linter', () => { await linter.invoke(dir, [ '-c', plugin_eslintrc, fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, match({ message: match('Failed to load plugin'), @@ -415,7 +446,7 @@ describe('linter', () => { '--resolve-plugins-relative-to', plugin_folder, '-c', plugin_eslintrc, fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -425,7 +456,7 @@ describe('linter', () => { '--resolve-plugins-relative-to', plugin_folder, '-c', plugin_eslintrc, fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, match({ message: match('Failed to load plugin'), @@ -443,7 +474,7 @@ describe('linter', () => { await linter.invoke(dir, [ '--report-unused-disable-directives', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWithMatch(callback, '/es6.txt:10:1:'); assert.calledOnceWithMatch(callback, 'Unused eslint-disable ' @@ -455,7 +486,7 @@ describe('linter', () => { await linter.invoke(dir, [ '--report-unused-disable-directives', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -467,7 +498,7 @@ describe('linter', () => { await linter.invoke(dir, [ '--eslint-path', './node_modules/eslint', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -476,7 +507,7 @@ describe('linter', () => { await linter.invoke(dir, [ '--eslint-path="./node_modules/eslint"', fixture_es6, '-f', 'unix' - ], '', 'a', callback); + ], '', callback); assert.calledOnceWith(callback, null, ''); }); @@ -502,7 +533,7 @@ describe('linter', () => { const callback = sinon.fake(); await linter.invoke(cwd, ['test/fixture/fail.txt', '-f', 'unknown'], '', - 'a', callback); + callback); assert.calledOnceWithMatch(callback, 'There was a problem loading formatter:');