ESLint’s variability management

In this last post, we will assess and analyze one of the features that ESLint takes pride in and differentiates itself with compared to competitors, namely the large variability in the system realized through configurations. We will go into what is variable, what benefits this has and how this complex configuration can be managed by users in a sane manner. Lastly, we will look at how this is implemented and finish off with an assessment done by ourselves.

Variability Modeling

In this section we will delve into the variabilities of the system, that is, features and settings that can be changed in the ESLint package. We will additionally look at incompatibilities and provide a feature model.

Variabilities

While ESLint is the perfect example of a tool that has one goal and does it well, it is also designed to be fully configurable from the start so it can be used in any project.

Project Configuration

  • Specify code parser
  • Specify project environment

The code parser can be configured and swapped out completely. By default it accepts ECMAScript 5 code, so developers who use different dialects e.g. Typescript will want to use @typescript-eslint/parser instead. Depending on the code in the project, users will also want to specify a project environment such as browser or node to load the correct initial global variables.

Linting Rule Configuration

  • Specify rules
  • Disable rules using comments in code
  • Specify ignored files and directories
  • Specify plugins

Before running, the user can specify which rules are enabled and which are not. This can be done by defining them in configuration files or using inline comments to disable specific lines or code sections. ESLint also allows the user to ignore files or complete directories and exclude them from the results and linting.

ESLint provides the user with a large set of rules which are very extensive and useful for developers. However, if a user decides that he wants to add more rules, plugins can be installed by specifying plugin repositories in the configuration file. This allows for easy extension of the base ruleset.

Auto Fixing Features

  • Specify the use of auto-fixing code

The auto fixing feature can be turned on to automatically fix types of linting problems, which can be errors, suggestion or layout problems. Developers benefit from enabling this because they will spend less time on manually fixing problems.

Output Variability

  • Specify the output method of the result of linting (& warnings etc.)
  • Specify caching processed files
  • Debug information

How ESLint outputs the results can be specified before executing. The output file and format of the results can be adjusted. Debug information can also be included. This benefits users since the user can specify the output to their needs. Debug logs are also helpful for maintainers to solve bugs in reported in issues. On top of that, integrating ESLint can be made easier by using a more ‘machine-readable’ format like JSON.

Variabilities Incompatibilities

  • Linting-rule configuration and auto fix

ESLint has the feature of automatically fixing your code, however the auto-fix feature might introduce new linting errors. Some rule configurations might thus end up not working well with the auto-fix feature. ESLint tries to solve this problem by repeatedly executing the fixes up to a maximum of 10 times until or no more linting errors are found. 1

  • Plugin incompatibilities

A user configuring external plugins should make sure that the rules are compatible. For example, having a rule that marks semi-columns as errors and another rule that marks them as required, will always lead to linting errors being reported.

  • Good configuration

An example of an allowed configuration of variabilities is laid out in the getting started guide, which consists of the default ESLint rules with the Node platform with a version of 8.10.0 or higher. The linter is then run without any special options, so no use of auto-fix.

Feature model

Additionally, we have created a feature model that describes the features laid out in the previous sections. It is used to visualize features and the relationships between them:

In software development, a feature model is a compact representation of all the products of the Software Product Line (SPL) in terms of “features”. 2

Feature model of ESLint

Variability management

ESLint is a system that is used and built by developers. In our blogpost ‘The vision behind ESLint’s success’, we identified 10 stakeholders. All stakeholders that interact with ESLint are developers, either for their project or for ESLint. This is an important fact for our analysis of the variability management of ESLint. The main division that we assume between the stakeholders is that the developer can be a client or ESLint developer. First, we discuss the software variability.

Software variability

The variability management for software is restricted to JavaScript or similar languages like TypeScript or ECMAScript since those are the languages for which ESLint provides linting. ESLint provides configuration with clear documentation for software variability management3. Additionally, different versions of ESLint can be downloaded. We will explore this and platform variability in the next section: platform variability.

Platform variability

ESLint uses two distribution platforms: NodeJS4 and Yarn5. First, we focus on clients of ESLint. Remember that those clients are developers themselves. Developers need NodeJS or Yarn to download ESLint. The download process is very familiar to developers since NodeJS is a frequently used tool for JavaScript and TypeScript development environments. ESLint is a tool that provides linting for those environments, so it is reasonable to assume that developers are already familiar with NodeJS. Apart from NodeJS, Yarn is also a well-known package manager. If a developer has NodeJS, ESLint can be downloaded on any operating system using the command:

npm install ESLint

or

yarn add ESLint

A specific ESLint version x.xx can be downloaded using the following command:

npm install ESLint@x.xx

As a side note, ESLint can be updated using the same package managers.

We can conclude that developers need NodeJS or Yarn to download ESLint, which shifts the variability aspect to those systems. If NodeJS or Yarn can be installed, ESLint can be installed as well. After some research, we found that both Yarn and NodeJS support a wide range of operating systems67. NodeJS supports 7 platforms with pre-built installers6. If the developer uses another platform or operating system, it is still possible to install NodeJS manually6. On the other hand, Yarn offers pre-built installers for 8 operating systems. Other operating systems can be used if NodeJS is installed, which is interesting.

To conclude this section, the installation procedure of ESLint developers is different than the client or user stakeholder group. The source code needs to be downloaded from the ESLint GitHub8. The developer can download all required packages by running the following commands in the (downloaded) ESLint folder:

cd eslint
npm install

Some additional steps can be read in the developer setup documentation of ESLint9. The point is that npm is used in this installation procedure as well. From this, we can derive that the software and platform variability is very similar for the two important stakeholder groups, client developers and ESLint developers!

Variability implementation mechanism and binding time

In order to understand the design choices made by the developers, we first need to have a look at the implementation mechanisms and binding times of the features. To do this we will have a look at two variable features: specifying the code parser and specifying plugins. With this, we will look at the mechanisms and binding time from 2 different variabilities. From this, we will derive a conclusion to understand the design choices of the developers.

Specifying code parser

Eslint uses by default Espree10 as its parser. However, it is possible to set up a different parser as long as it meets the following requirements:

  • It must be a Node module loadable from the config file where it appears.
  • It must conform to the parser interface11

The following parsers are compatible with ESLint:

  • Esprima12
  • Babel-ESLint13 - A wrapper around the Babel parser that makes it compatible with ESLint.
  • @typescript-eslint/parser14 - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint.

In order to add the custom parser in the configuration, the user has to add the parser option in his .eslintrc file. This rule has to be added with the other rules in the parserOptions property.

In the parser options the user is allowed to specify the JavaSript language options that need to be supported. By default, ESLint expects ECMAScript 5 syntax but this can be changed to other versions as well JSX options. The parser options are set in the .eslintrc.* file by using the parserOptions property. The available options are:

  • ecmaVersion - to specify the version of ECMAScript syntax that the user wants to use.
  • sourceType - set to “script”, default, or “module” if the code is in ECMAScript modules.
  • ecmaFeatures - an object indicating with additional language features that can be used:
    • globalReturn - allow return statements in the global scope
    • impliedStrict - enable global strict mode15
    • jsx - enable JSX16

An example of .eslintrc.json file:

{
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": true
        }
    },
    "rules": {
        "semi": "error"
    }
}

Specifying plugins

ESLint supports the use of third-party plugins. Before using the plugin, you have to install it using npm. To configure the plugins a list of plugins have to be stored in the property plugins. In this list the eslint-plugin- can also be stored. An example follows:

{
    "plugins": [
        "plugin1",
        "eslint-plugin-plugin2"
    ]
}

The naming differs based on the scope. For example, giving as a name of a plugin jquery would look for a non-scoped package with the name eslint-plugin-jquery. Whereas if you want to look for a scoped plugin you will have to type @jquery, which will look for the plugin @jquery/eslint-plugin. When using rules, environments or configs defined by plugins, they must be referenced following the necessary conventions3.

By looking at the implementations, we can see that the underlying mechanism is Parameters and Configuration Files. The parameters are fixed and the user can select out of an array of it, by which ESlint will compile. If a change occurs in the configuration file then a reboot is required. As such the mechanism uses a load-time binding. This leads to flexibility in reconfiguration, which is great since ESLint focuses on the freedom of the user and a wide variety of coding styles. The conditions are checked at load time, which is also important as ESLint is run thus making sure that the conditions work at load time is sufficient. This allows for a fast and flexible system, which is exactly what meets ESLints requirements. The system also becomes scalable, as adding new rules/plugins/parsers can be done easily with new constraints and properties in the configuration files. From this, we can conclude that the developers chose the correct implementation mechanisms needed for ESLint.

  1. Applying rule fixes, https://eslint.org/docs/developer-guide/working-with-rules#applying-fixes 

  2. Feature model, retrieved 7 April, https://en.wikipedia.org/wiki/Feature_model 

  3. ESLint configuration documentation, retrieved 7 April, https://eslint.org/docs/user-guide/configuring  2

  4. Node.JS, retrieved 7 April, https://eslint.org/ 

  5. Yarn, retrieved 7 April, https://yarnpkg.com 

  6. Node.JS download page, retrieved 7 April, https://nodejs.org/en/download/  2 3

  7. Yarn download page, https://classic.yarnpkg.com/en/docs/install#mac-stable 

  8. ESLint GitHub, retrieved 7 April, https://github.com/eslint/eslint 

  9. ESLint developer setup, retrieved 7 April, https://eslint.org/docs/developer-guide/development-environment 

  10. Espree repository, https://github.com/eslint/espree 

  11. ESLint plugins, https://eslint.org/docs/developer-guide/working-with-plugins#working-with-custom-parsers 

  12. Esprima, https://www.npmjs.com/package/esprima 

  13. Babel, https://www.npmjs.com/package/babel-eslint 

  14. typescript, https://www.npmjs.com/package/@typescript-eslint/parser 

  15. strict mode, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode 

  16. JSX, https://facebook.github.io/jsx/ 

ESLint
Authors
Paul van der Laan
Brian Planje
Mika Kuijpers
Kabilan Gnanavarothayan