diff --git a/docs/user-guide/command-line-interface.md b/docs/user-guide/command-line-interface.md index 3a7e17650c1e..631a7203b91a 100644 --- a/docs/user-guide/command-line-interface.md +++ b/docs/user-guide/command-line-interface.md @@ -333,6 +333,17 @@ Example: eslint -f ./customformat.js file.js +An npm-installed formatter is resolved with or without `eslint-formatter-` prefix. + +Example: + + npm install eslint-formatter-pretty + + eslint -f pretty file.js + + // equivalent: + eslint -f eslint-formatter-pretty file.js + When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so: eslint -f compact file.js > results.txt diff --git a/lib/cli-engine.js b/lib/cli-engine.js index 38c49cb31d84..f8443a105873 100644 --- a/lib/cli-engine.js +++ b/lib/cli-engine.js @@ -26,10 +26,13 @@ const fs = require("fs"), validator = require("./config/config-validator"), stringify = require("json-stable-stringify"), hash = require("./util/hash"), + ModuleResolver = require("./util/module-resolver"), pkg = require("../package.json"); const debug = require("debug")("eslint:cli-engine"); +const resolver = new ModuleResolver(); + //------------------------------------------------------------------------------ // Typedefs //------------------------------------------------------------------------------ @@ -670,15 +673,21 @@ class CLIEngine { // replace \ with / for Windows compatibility format = format.replace(/\\/g, "/"); + const cwd = this.options ? this.options.cwd : process.cwd(); + let formatterPath; // if there's a slash, then it's a file if (format.indexOf("/") > -1) { - const cwd = this.options ? this.options.cwd : process.cwd(); - formatterPath = path.resolve(cwd, format); } else { - formatterPath = `./formatters/${format}`; + const npmFormat = /^eslint-formatter-/.test(format) ? format : `eslint-formatter-${format}`; + + try { + formatterPath = resolver.resolve(npmFormat, cwd); + } catch (_) { + formatterPath = `./formatters/${format}`; + } } try { diff --git a/tests/fixtures/cli-engine/eslint-formatter-bar/index.js b/tests/fixtures/cli-engine/eslint-formatter-bar/index.js new file mode 100644 index 000000000000..0a55f349ae71 --- /dev/null +++ b/tests/fixtures/cli-engine/eslint-formatter-bar/index.js @@ -0,0 +1 @@ +module.exports = function() {}; diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js index 5026d4b197e7..67c38d397f90 100644 --- a/tests/lib/cli-engine.js +++ b/tests/lib/cli-engine.js @@ -2685,6 +2685,24 @@ describe("CLIEngine", () => { assert.isFunction(formatter); }); + it("should return a function when a formatter prefixed with eslint-formatter is requested", () => { + const engine = new CLIEngine({ + cwd: getFixturePath("cli-engine") + }), + formatter = engine.getFormatter("bar"); + + assert.isFunction(formatter); + }); + + it("should return a function when a formatter is requested, also when the eslint-formatter prefix is included in the format argument", () => { + const engine = new CLIEngine({ + cwd: getFixturePath("cli-engine") + }), + formatter = engine.getFormatter("eslint-formatter-bar"); + + assert.isFunction(formatter); + }); + it("should return null when a customer formatter doesn't exist", () => { const engine = new CLIEngine(), formatterPath = getFixturePath("formatters", "doesntexist.js");