diff --git a/lib/index.js b/lib/index.js index b39da98..938a198 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,10 +12,11 @@ const isString = require('./is-string'); const getResultSeverity = require('./get-result-severity'); const testGenerators = require('./test-generators'); const testGeneratorNames = Object.keys(testGenerators); +const nodeIncludesOverrides = require('./node-includes-overrides'); const FACTORY_METHOD_USED = Symbol('create() factory method was used'); -function resolveInputDirectory(inputNode) { +function resolveInputDirectory(inputNode, eslintIncludesOverrides) { if (typeof inputNode === 'string') { return inputNode; } @@ -27,12 +28,14 @@ function resolveInputDirectory(inputNode) { return nodeInfo.sourceDirectory; } - if (nodeInfo.inputNodes.length > 1) { + if (nodeInfo.inputNodes.length > 1 && !eslintIncludesOverrides) { // eslint-disable-next-line max-len - throw new Error('EslintValidationFilter can only handle one:* broccoli nodes, but part of the given input pipeline is a many:* node. (broccoli-merge-trees is an example of a many:* node) Please perform many:* operations after linting.'); + throw new Error( + 'EslintValidationFilter can only handle one:* broccoli nodes, but part of the given input pipeline is a many:* node. (broccoli-merge-trees is an example of a many:* node) Please perform many:* operations after linting.' + ); } - return resolveInputDirectory(nodeInfo.inputNodes[0]); + return resolveInputDirectory(nodeInfo.inputNodes[0], eslintIncludesOverrides); } /** @@ -80,7 +83,10 @@ function EslintValidationFilter(inputNode, options) { this.cli = new CLIEngine(options.options); - this.eslintrc = resolveInputDirectory(inputNode); + this.eslintrc = resolveInputDirectory( + inputNode, + nodeIncludesOverrides(inputNode, this.cli) + ); if (isString(this.internalOptions.testGenerator)) { this.testGenerator = testGenerators[this.internalOptions.testGenerator]; diff --git a/lib/node-includes-overrides.js b/lib/node-includes-overrides.js new file mode 100644 index 0000000..e8caa0a --- /dev/null +++ b/lib/node-includes-overrides.js @@ -0,0 +1,36 @@ +/** + * Uses eslint (private) api to see if eslint config includes a `overrides` flag. + * + * inputNode type is a bit tricky here. We are expecting three different cases: + * if it's string, we will use it as a directory and let eslint do the work. + * + * if it's a source node, use the `sourceDirectory` property. + * + * if it's a transform node, recursively call same function with all of its + * inputNodes. if any of the input directories contain `overrides` eslint + * config, return true + * + * While it's not ideal we iterate through all the `inputNodes` of a transform node, + * the input size should be very small. + */ +const nodeIncludesOverrides = (inputNode, eslintCli) => { + if (typeof inputNode === 'string') { + return eslintCli.config + .getConfigHierarchy(inputNode) + .some(node => node.overrides); + } + + const nodeInfo = inputNode.__broccoliGetInfo__(); + const nodeType = nodeInfo.nodeType; + const sourceDirectory = nodeInfo.sourceDirectory; + if (nodeType === 'transform') { + const nodesIncludesOverrides = inputNode._inputNodes.map(node => + nodeIncludesOverrides(node, eslintCli) + ); + return nodesIncludesOverrides.some(Boolean); + } + + return nodeIncludesOverrides(sourceDirectory, eslintCli); +}; + +module.exports = nodeIncludesOverrides; diff --git a/package.json b/package.json index c864159..759a54a 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "4.2.1", "description": "broccoli filter that runs eslint", "main": "lib/index.js", + "engines": { + "node": ">=4" + }, "scripts": { "lint": "eslint .", "test": "mocha test/*test.js test/**/*test.js" diff --git a/test/eslint-test.js b/test/eslint-test.js index b51174b..2458883 100644 --- a/test/eslint-test.js +++ b/test/eslint-test.js @@ -61,6 +61,39 @@ describe('broccoli-lint-eslint', function() { .to.contain(`DEPRECATION: Please use the create() factory method`); })); + it('accept many:* node if eslintrc specifies overrides', co.wrap(function*() { + // we need to create two temp folders with eslintrc files in it + const firstDirectory = yield createTempDir(); + const secondDirectory = yield createTempDir(); + + firstDirectory.write({ + '.eslintrc.js': `module.exports = { rules: { 'no-console': 'error'}, overrides: [ { files: 'a.js', rules: { 'no-console': 'disable' } }] }`, + 'a.js': `console.log('foo');\n`, + }); + + secondDirectory.write({ + '.eslintrc.js': `module.exports = { }`, + 'a.js': `console.log('foo');\n`, + }); + + let messages = []; + let console = { + log(message) { + messages.push(message); + }, + }; + + const mergedDirectories = new MergeTrees([ + firstDirectory.path(), + secondDirectory.path(), + ]); + + expect(() => new ESLint(mergedDirectories, { console })).to.not.throw(); + + yield firstDirectory.dispose(); + yield secondDirectory.dispose(); + })); + it('logs errors to the console (using new)', co.wrap(function *() { input.write({ '.eslintrc.js': `module.exports = { rules: { 'no-console': 'error', 'no-unused-vars': 'warn' } };\n`,