Node.js API

While ESLint is designed to be run on the command line, it’s possible to use ESLint programmatically through the Node.js API. The purpose of the Node.js API is to allow plugin and tool authors to use the ESLint functionality directly, without going through the command line interface.

Note: Use undocumented parts of the API at your own risk. Only those parts that are specifically mentioned in this document are approved for use and will remain stable and reliable. Anything left undocumented is unstable and may change or be removed at any point.

Table of Contents

SourceCode

The SourceCode type represents the parsed source code that ESLint executes on. It’s used internally in ESLint and is also available so that already-parsed code can be used. You can create a new instance of SourceCode by passing in the text string representing the code and an abstract syntax tree (AST) in ESTree format (including location information, range information, comments, and tokens):

const SourceCode = require("eslint").SourceCode;

const code = new SourceCode("var foo = bar;", ast);

The SourceCode constructor throws an error if the AST is missing any of the required information.

The SourceCode constructor strips Unicode BOM. Please note the AST also should be parsed from stripped text.

const SourceCode = require("eslint").SourceCode;

const code = new SourceCode("\uFEFFvar foo = bar;", ast);

assert(code.hasBOM === true);
assert(code.text === "var foo = bar;");

SourceCode#splitLines()

This is a static function on SourceCode that is used to split the source code text into an array of lines.

const SourceCode = require("eslint").SourceCode;

const code = "var a = 1;\nvar b = 2;"

// split code into an array
const codeLines = SourceCode.splitLines(code);

/*
    Value of codeLines will be
    [
        "var a = 1;",
        "var b = 2;"
    ]
 */

Linter

The Linter object does the actual evaluation of the JavaScript code. It doesn’t do any filesystem operations, it simply parses and reports on the code. In particular, the Linter object does not process configuration objects or files. The Linter is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:

For example:

const Linter = require("eslint").Linter;
const linter1 = new Linter({ cwd: 'path/to/project' });
const linter2 = new Linter();

In this example, rules run on linter1 will get path/to/project when calling context.getCwd(). Those run on linter2 will get process.cwd() if the global process object is defined or undefined otherwise (e.g. on the browser https://eslint.org/demo).

Linter#verify

The most important method on Linter is verify(), which initiates linting of the given text. This method accepts three arguments:

If the third argument is a string, it is interpreted as the filename.

You can call verify() like this:

const Linter = require("eslint").Linter;
const linter = new Linter();

const messages = linter.verify("var foo;", {
    rules: {
        semi: 2
    }
}, { filename: "foo.js" });

// or using SourceCode

const Linter = require("eslint").Linter,
    linter = new Linter(),
    SourceCode = require("eslint").SourceCode;

const code = new SourceCode("var foo = bar;", ast);

const messages = linter.verify(code, {
    rules: {
        semi: 2
    }
}, { filename: "foo.js" });

The verify() method returns an array of objects containing information about the linting warnings and errors. Here’s an example:

{
    fatal: false,
    ruleId: "semi",
    severity: 2,
    line: 1,
    column: 23,
    message: "Expected a semicolon.",
    fix: {
        range: [1, 15],
        text: ";"
    }
}

The information available for each linting message is:

Linting message objects have a deprecated source property. This property will be removed from linting messages in an upcoming breaking release. If you depend on this property, you should now use the SourceCode instance provided by the linter.

You can also get an instance of the SourceCode object used inside of linter by using the getSourceCode() method:

const Linter = require("eslint").Linter;
const linter = new Linter();

const messages = linter.verify("var foo = bar;", {
    rules: {
        semi: 2
    }
}, { filename: "foo.js" });

const code = linter.getSourceCode();

console.log(code.text);     // "var foo = bar;"

In this way, you can retrieve the text and AST used for the last run of linter.verify().

Linter#verifyAndFix()

This method is similar to verify except that it also runs autofixing logic, similar to the --fix flag on the command line. The result object will contain the autofixed code, along with any remaining linting messages for the code that were not autofixed.

const Linter = require("eslint").Linter;
const linter = new Linter();

const messages = linter.verifyAndFix("var foo", {
    rules: {
        semi: 2
    }
});

Output object from this method:

{
    fixed: true,
    output: "var foo;",
    messages: []
}

The information available is:

Linter#defineRule

Each Linter instance holds a map of rule names to loaded rule objects. By default, all ESLint core rules are loaded. If you want to use Linter with custom rules, you should use the defineRule method to register your rules by ID.

const Linter = require("eslint").Linter;
const linter = new Linter();

linter.defineRule("my-custom-rule", {
    // (an ESLint rule)

    create(context) {
        // ...
    }
});

const results = linter.verify("// some source text", { rules: { "my-custom-rule": "error" } });

Linter#defineRules

This is a convenience method similar to Linter#defineRule, except that it allows you to define many rules at once using an object.

const Linter = require("eslint").Linter;
const linter = new Linter();

linter.defineRules({
    "my-custom-rule": { /* an ESLint rule */ create() {} },
    "another-custom-rule": { /* an ESLint rule */ create() {} }
});

const results = linter.verify("// some source text", {
    rules: {
        "my-custom-rule": "error",
        "another-custom-rule": "warn"
    }
});

Linter#getRules

This method returns a map of all loaded rules.

const Linter = require("eslint").Linter;
const linter = new Linter();

linter.getRules();

/*
Map {
  'accessor-pairs' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
  'array-bracket-newline' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
  ...
}
*/

Linter#defineParser

Each instance of Linter holds a map of custom parsers. If you want to define a parser programmatically, you can add this function with the name of the parser as first argument and the parser object as second argument. The default "espree" parser will already be loaded for every Linter instance.

const Linter = require("eslint").Linter;
const linter = new Linter();

linter.defineParser("my-custom-parser", {
    parse(code, options) {
        // ...
    }
});

const results = linter.verify("// some source text", { parser: "my-custom-parser" });

Linter#version/Linter.version

Each instance of Linter has a version property containing the semantic version number of ESLint that the Linter instance is from.

const Linter = require("eslint").Linter;
const linter = new Linter();

linter.version; // => '4.5.0'

There is also a Linter.version property that you can read without instantiating Linter:

const Linter = require("eslint").Linter;

Linter.version; // => '4.5.0'

linter

The eslint.linter object (deprecated) is an instance of the Linter class as defined above. eslint.linter exists for backwards compatibility, but we do not recommend using it because any mutations to it are shared among every module that uses eslint. Instead, please create your own instance of eslint.Linter.

const linter = require("eslint").linter;

const messages = linter.verify("var foo;", {
    rules: {
        semi: 2
    }
}, { filename: "foo.js" });

Note: This API is deprecated as of 4.0.0.

CLIEngine

The primary Node.js API is CLIEngine, which is the underlying utility that runs the ESLint command line interface. This object will read the filesystem for configuration and file information but will not output any results. Instead, it allows you direct access to the important information so you can deal with the output yourself.

You can get a reference to the CLIEngine by doing the following:

const CLIEngine = require("eslint").CLIEngine;

The CLIEngine is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:

To programmatically set .eslintrc.* options not supported above (such as extends, overrides and settings), define them in a config object passed to baseConfig instead.

For example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    baseConfig: {
        extends: ["eslint-config-shared"],
        settings: {
            sharedData: "Hello"
        }
    },
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

In this example, a new CLIEngine instance is created that extends a configuration called "eslint-config-shared", a setting named "sharedData" and two environments ("browser" and "mocha") are defined, loading of .eslintrc and package.json files are disabled, and the semi rule enabled as an error. You can then call methods on cli and these options will be used to perform the correct action.

Note: Currently CLIEngine does not validate options passed to it, but may start doing so in the future.

CLIEngine#executeOnFiles()

If you want to lint one or more files, use the executeOnFiles() method. This method accepts a single argument, which is an array of files and/or directories to traverse for files. You can pass the same values as you would using the ESLint command line interface, such as "." to search all JavaScript files in the current directory. Here’s an example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

// lint myfile.js and all files in lib/
const report = cli.executeOnFiles(["myfile.js", "lib/"]);

The return value is an object containing the results of the linting operation. Here’s an example of a report object:

{
    results: [
        {
            filePath: "/Users/eslint/project/myfile.js",
            messages: [{
                ruleId: "semi",
                severity: 2,
                message: "Missing semicolon.",
                line: 1,
                column: 13,
                nodeType: "ExpressionStatement",
                fix: { range: [12, 12], text: ";" }
            }],
            errorCount: 1,
            warningCount: 0,
            fixableErrorCount: 1,
            fixableWarningCount: 0,
            source: "\"use strict\"\n"
        }
    ],
    errorCount: 1,
    warningCount: 0,
    fixableErrorCount: 1,
    fixableWarningCount: 0,
    usedDeprecatedRules: []
}

You can also pass fix: true when instantiating the CLIEngine in order to have it figure out what fixes can be applied.

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    fix: true, // difference from last example
    useEslintrc: false,
    rules: {
        semi: 2,
        quotes: [2, "double"]
    }
});

// lint myfile.js and all files in lib/
const report = cli.executeOnFiles(["myfile.js", "lib/"]);
{
    results: [
        {
            filePath: "/Users/eslint/project/myfile.js",
            messages: [
                {
                    ruleId: "semi",
                    severity: 2,
                    message: "Missing semicolon.",
                    line: 1,
                    column: 13,
                    nodeType: "ExpressionStatement",
                    fix: { range: [12, 12], text: ";" }
                },
                {
                    ruleId: "func-name-matching",
                    severity: 2,
                    message: "Function name `bar` should match variable name `foo`",
                    line: 2,
                    column: 5,
                    nodeType: "VariableDeclarator"
                }
            ],
            errorCount: 2,
            warningCount: 0,
            fixableErrorCount: 1,
            fixableWarningCount: 0,
            output: "\"use strict\";\nvar foo = function bar() {};\nfoo();\n"
        }
    ],
    errorCount: 2,
    warningCount: 0,
    fixableErrorCount: 1,
    fixableWarningCount: 0,
    usedDeprecatedRules: []
}

If the operation ends with a parsing error, you will get a single message for this file, with fatal: true added as an extra property.

{
    results: [
        {
            filePath: "./myfile.js",
            messages: [
                {
                    ruleId: null,
                    fatal: true,
                    severity: 2,
                    message: "Parsing error: Unexpected token foo",
                    line: 1,
                    column: 10
                }
            ],
            errorCount: 1,
            warningCount: 0,
            fixableErrorCount: 0,
            fixableWarningCount: 0,
            source: "function foo() {}"
        }
    ],
    errorCount: 1,
    warningCount: 0,
    fixableErrorCount: 0,
    fixableWarningCount: 0,
    usedDeprecatedRules: []
}

The top-level report object has a results array containing all linting results for files that had warnings or errors (any files that did not produce a warning or error are omitted). Each file result includes:

The top-level report object also has errorCount and warningCount which give the exact number of errors and warnings respectively on all the files. Additionally, usedDeprecatedRules signals any deprecated rules used and their replacement (if available). Specifically, it is array of objects with properties like so:

Once you get a report object, it’s up to you to determine how to output the results. Fixes will not be automatically applied to the files, even if you set fix: true when constructing the CLIEngine instance. To apply fixes to the files, call outputFixes.

CLIEngine#resolveFileGlobPatterns()

You can pass filesystem-style or glob patterns to ESLint and have it function properly. In order to achieve this, ESLint must resolve non-glob patterns into glob patterns before determining which files to execute on. The resolveFileGlobPatterns() methods uses the current settings from CLIEngine to resolve non-glob patterns into glob patterns. Pass an array of patterns that might be passed to the ESLint CLI and it will return an array of glob patterns that mean the same thing. Here’s an example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
});

// pass an array of patterns
const globPatterns = cli.resolveFileGlobPatterns(["."]);
console.log(globPatterns[i]);       // ["**/*.js"]

CLIEngine#getConfigForFile()

If you want to retrieve a configuration object for a given file, use the getConfigForFile() method. This method accepts one argument, a file path, and returns an object represented the calculated configuration of the file. Here’s an example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

const config = cli.getConfigForFile("myfile.js");

Once you have the configuration information, you can pass it into the linter object:

const CLIEngine = require("eslint").CLIEngine,
    Linter = require("eslint").Linter;

const linter = new Linter();
const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

const config = cli.getConfigForFile("myfile.js");

const messages = linter.verify('var foo;', config);

CLIEngine#executeOnText()

If you already have some text to lint, then you can use the executeOnText() method to lint that text. The linter will assume that the text is a file in the current working directory, and so will still obey any .eslintrc and .eslintignore files that may be present. Here’s an example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

// Lint the supplied text and optionally set a filename that is displayed in the report
const report = cli.executeOnText("var foo = 'bar';", "foo.js");

// In addition to the above, warn if the resolved file name is ignored.
const reportAndWarnOnIgnoredFile = cli.executeOnText("var foo = 'bar';", "foo.js", true);

The report returned from executeOnText() is in the same format as from executeOnFiles(), but there is only ever one result in report.results.

If a filename in the optional second parameter matches a file that is configured to be ignored, then this function returns no errors or warnings. The method includes an additional optional boolean third parameter. When true, a resolved file name that is ignored will return a warning.

CLIEngine#addPlugin()

Loads a plugin from configuration object with specified name. Name can include plugin prefix (“eslint-plugin-“)

const CLIEngine = require("eslint").CLIEngine;
const cli = new CLIEngine({
    ignore: true
});
cli.addPlugin("eslint-plugin-processor", {
    processors: {
        ".txt": {
            preprocess: function(text) {
                return [text];
            },
            postprocess: function(messages) {
                return messages[0];
            }
        }
    }
});

CLIEngine#isPathIgnored()

Checks if a given path is ignored by ESLint.

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    ignore: true,
    ignorePath: ".customIgnoreFile"
});

const isIgnored = cli.isPathIgnored("foo/bar.js");

CLIEngine#getFormatter()

Retrieves a formatter, which you can then use to format a report object. The argument is either the name of a built-in formatter:

or the full path to a JavaScript file containing a custom formatter. You can also omit the argument to retrieve the default formatter.

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

// lint myfile.js and all files in lib/
const report = cli.executeOnFiles(["myfile.js", "lib/"]);

// get the default formatter
const formatter = cli.getFormatter();

// Also could do...
// const formatter = cli.getFormatter("compact");
// const formatter = cli.getFormatter("./my/formatter.js");

// output to console
console.log(formatter(report.results));

Note: Also available as a static function on CLIEngine.

// get the default formatter by calling the static function
const formatter = CLIEngine.getFormatter();

Important: You must pass in the results property of the report. Passing in report directly will result in an error.

CLIEngine#getErrorResults()

This is a static function on CLIEngine. It can be used to filter out all the non error messages from the report object.

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

// lint myfile.js and all files in lib/
const report = cli.executeOnFiles(["myfile.js", "lib/"]);

// only get the error messages
const errorReport = CLIEngine.getErrorResults(report.results)

Important: You must pass in the results property of the report. Passing in report directly will result in an error.

CLIEngine#outputFixes()

This is a static function on CLIEngine that is used to output fixes from report to disk. It does by looking for files that have an output property in their results. Here’s an example:

const CLIEngine = require("eslint").CLIEngine;

const cli = new CLIEngine({
    envs: ["browser", "mocha"],
    fix: true,
    useEslintrc: false,
    rules: {
        semi: 2
    }
});

// lint myfile.js and all files in lib/
const report = cli.executeOnFiles(["myfile.js", "lib/"]);

// output fixes to disk
CLIEngine.outputFixes(report);

CLIEngine#getRules()

This method returns a map of all loaded rules. Under the hood, it calls Linter#getRules.

const CLIEngine = require("eslint").CLIEngine;
const cli = new CLIEngine();

cli.getRules();

/*
Map {
  'accessor-pairs' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
  'array-bracket-newline' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
  ...
}
*/

CLIEngine.version

CLIEngine has a static version property containing the semantic version number of ESLint that it comes from.

require("eslint").CLIEngine.version; // '4.5.0'

RuleTester

eslint.RuleTester is a utility to write tests for ESLint rules. It is used internally for the bundled rules that come with ESLint, and it can also be used by plugins.

Example usage:

"use strict";

const rule = require("../../../lib/rules/my-rule"),
    RuleTester = require("eslint").RuleTester;

const ruleTester = new RuleTester();

ruleTester.run("my-rule", rule, {
    valid: [
        {
            code: "var foo = true",
            options: [{ allowFoo: true }]
        }
    ],

    invalid: [
        {
            code: "var invalidVariable = true",
            errors: [{ message: "Unexpected invalid variable." }]
        },
        {
            code: "var invalidVariable = true",
            errors: [{ message: /^Unexpected.+variable/ }]
        }
    ]
});

The RuleTester constructor accepts an optional object argument, which can be used to specify defaults for your test cases. For example, if all of your test cases use ES2015, you can set it as a default:

const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });

The RuleTester#run() method is used to run the tests. It should be passed the following arguments:

A test case is an object with the following properties:

In addition to the properties above, invalid test cases can also have the following properties:

Any additional properties of a test case will be passed directly to the linter as config options. For example, a test case can have a parserOptions property to configure parser behavior:

{
    code: "let foo;",
    parserOptions: { ecmaVersion: 2015 }
}

If a valid test case only uses the code property, it can optionally be provided as a string containing the code, rather than an object with a code key.

Customizing RuleTester

RuleTester depends on two functions to run tests: describe and it. These functions can come from various places:

  1. If RuleTester.describe and RuleTester.it have been set to function values, RuleTester will use RuleTester.describe and RuleTester.it to run tests. You can use this to customize the behavior of RuleTester to match a test framework that you’re using.
  2. Otherwise, if describe and it are present as globals, RuleTester will use global.describe and global.it to run tests. This allows RuleTester to work when using frameworks like Mocha without any additional configuration.
  3. Otherwise, RuleTester#run will simply execute all of the tests in sequence, and will throw an error if one of them fails. This means you can simply execute a test file that calls RuleTester.run using node, without needing a testing framework.

RuleTester#run calls the describe function with two arguments: a string describing the rule, and a callback function. The callback calls the it function with a string describing the test case, and a test function. The test function will return successfully if the test passes, and throw an error if the test fails. (Note that this is the standard behavior for test suites when using frameworks like Mocha; this information is only relevant if you plan to customize RuleTester.it and RuleTester.describe.)

Example of customizing RuleTester:

"use strict";

const RuleTester = require("eslint").RuleTester,
    test = require("my-test-runner"),
    myRule = require("../../../lib/rules/my-rule");

RuleTester.describe = function(text, method) {
    RuleTester.it.title = text;
    return method.call(this);
};

RuleTester.it = function(text, method) {
    test(RuleTester.it.title + ": " + text, method);
};

// then use RuleTester as documented

const ruleTester = new RuleTester();

ruleTester.run("my-rule", myRule, {
    valid: [
        // valid test cases
    ],
    invalid: [
        // invalid test cases
    ]
})

Deprecated APIs