ESLint Compatibility - daidodo/format-imports GitHub Wiki

ESLint Compatibility

Table of contents

Introduction

When formatting a source file, formatSourceFromFile will try to search for ESLint config and automatically adjust the result to follow the rules. This is done by translating relevant rules and merging them into the base Configuration provided in parameters.

Currently, the supported rules are:

For them to work, you need to ensure that:

  • ESLint is installed and properly configured.
  • The file to format is not ignored/excluded by ESLint or the base Configuration provided in parameters.
  • The ESLint rules are in effect, i.e. either "warn" or "error" level.

Note: It's ok that ESLint is not found so this feature is off without any impact.

The ESLint rules might conflict with the base Configuration. In this case, ESLint rules will win to avoid lint errors.

Here is how ESLint rule options are translated and merged to Configuration.

sort-imports

Rule details:

This rule checks all import declarations and verifies that all imports are first sorted by the used member syntax and then alphabetically by the first member or alias name.

ignoreDeclarationSort and ignoreMemberSort

If ignoreDeclarationSort is false, imports will be grouped and sorted based on allowSeparatedGroups and memberSyntaxSortOrder options. The groups and sub-groups from the base Configuration might be disregarded in some situations as described in the next section.

If either ignoreMemberSort or ignoreDeclarationSort is false, binding names within an import will be sorted complying to ESLint and based on ignoreCase, which means the global sortRules.names and all groups' sort.names from the base Configuration will be disregarded.

If both ignoreMemberSort and ignoreDeclarationSort are true, no changes to the base Configuration.

allowSeparatedGroups and memberSyntaxSortOrder

If allowSeparatedGroups is false, all imports will be grouped by memberSyntaxSortOrder instead of groupRules from the base Configuration, and then sorted by the first binding names or alias regardless of sortImportsBy from the base Configuration.

For example,

import-sorter.json:

{
  "groupRules": ["^a", "^b"]
}

Without ESLint sort-imports rules, imports would be formatted as follows:

// Group "^a"
import A from "a";
import { B, C } from "ab";

// Group "^b"
import { D, E } from "b";

When configuring ESLint with:

.eslintrc.json:

{
  "rules": {
    "sort-imports": [
      "warn",
      {
        "allowSeparatedGroups": false,
        "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
      }
    ]
  }
}

The result would be:

// Group "multiple"
import { B, C } from "ab";
import { D, E } from "b";

// Group "single"
import A from "a";

If allowSeparatedGroups is true, imports will still be grouped by groupRules from the base Configuration, but sub-grouped by memberSyntaxSortOrder instead of subGroups , and then sorted by the first binding names or alias regardless of sortImportsBy from the base Configuration.

For example,

import-sorter.json:

{
  "groupRules": ["^a", "^b"](/daidodo/format-imports/wiki/"^a",-"^b")
}

Without ESLint sort-import rules, imports would be formatted as:

// Group ["^a", "^b"]
import A from "a"; // Sub-group "^a"
import { B, C } from "ab";
import { D, E } from "b"; // Sub-group "^b"

When configuring ESLint with:

.eslintrc.json:

{
  "rules": {
    "sort-imports": [
      "warn",
      {
        "allowSeparatedGroups": true,
        "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
      }
    ]
  }
}

The result would be:

// Group ["^a", "^b"]
import { B, C } from "ab"; // Sub-group "multiple"
import { D, E } from "b";
import A from "a"; // Sub-group "single"

memberSyntaxSortOrder Translation

The translation from a memberSyntaxSortOrder item to a group/sub-group is as follows:

  • "none" to {"flags": "scripts"}, which accepts all script imports;

  • "all" to {"flags": "namespace"}, which accepts all namespace imports;

  • "multiple" to {"flags": "multiple"}, which accepts all imports with multiple names, e.g.:

    import { A, B } from "a";
    import C, { D } from "b";
    import E, * as F from "c";
    
  • "single" to {"flags": "single"}, which accepts all imports with single name, e.g.:

    import A from "a";
    import { B } from "b";
    

ignoreCase

If false, the global sortRules.names and all groups' sort.names will be replaced with ["AZ", "_", "az"].

If true, the global sortRules.names and all groups' sort.names will be replaced with ["_", "aA"].

For example,

import-sorter.json:

{
  "sortRules": {
    "names": ["az", "_", "AZ"]
  }
}
// "sort-imports": "off"
import { a, _, A } from "x";

// "sort-imports": ["warn", { "ignoreCase": false }]
import { A, _, a } from "x";

// "sort-imports": ["warn", { "ignoreCase": true }]
import { _, a, A } from "x";

max-len

Rule details

This rule enforces a maximum line length to increase code readability and maintainability.

If on, this rule affects the following options from Configuration:

In addition, tabWidth (default 4) will be considered when calculating line length if tabType in Configuration is tab.

Other fields from the rule are ignored.

indent

Rule details

This rule enforces a consistent indentation style.

If enabled, the 2nd option ("tab" or a number) will impact tabType and tabSize in Configuration.

The 3rd option is ignored even though there is an ImportDeclaration field inside, because the use cases that it's not the default (1) are too rare.

@typescript-eslint/indent is also supported in the same way.

eol-last

Rule details

This rule enforces at least one newline (or absence thereof) at the end of non-empty files.

When the rule is enabled, insertFinalNewline from Configuration will be overridden:

  • When the option is "never", insertFinalNewline will be false.
  • Otherwise, insertFinalNewline will be true.

Notes:

  • "unix", "windows" and "always" options are indistinguishable.

semi

Rule details

This rule enforces consistent use of semicolons.

When the rule is enabled, hasSemicolon from Configuration will be overridden:

  • When the option is "always", hasSemicolon will be true.
  • Otherwise, hasSemicolon will be false.

@typescript-eslint/semi is also supported in the same way.

Notes:

  • The object option is ignored.

comma-dangle

Rule details

This rule enforces consistent use of trailing commas in object and array literals.

When the rule is enabled, trailingComma from Configuration will be overridden:

  • When the option is "never", trailingComma will be none.
  • When the option is "always", trailingComma will be always.
  • When the option is "always-multiline", "only-multiline" or "ignore", trailingComma will be multiLine.
  • When the option is an object, only imports is considered:
    • When imports is "never", trailingComma will be none.
    • When imports is "always", trailingComma will be always.
    • When imports is "always-multiline", "only-multiline" or "ignore", trailingComma will be multiLine.

@typescript-eslint/comma-dangle is also supported in the same way.

Notes:

  • exports in the option object is ignored.

object-curly-spacing

Rule details

Enforces consistent spacing inside braces.

If enabled, bracketSpacing from Configuration will be overridden:

  • When the string option is "never", bracketSpacing will be false.
  • When the string option is "always", bracketSpacing will be true.

@typescript-eslint/object-curly-spacing is also supported in the same way.

Notes:

  • The object option is ignored.

import/newline-after-import

Rule details:

Enforces having one or more empty lines after the last top-level import statement or require call.

If enabled, the number of empty lines after the last import declaration will be defined by its count option instead of emptyLinesAfterAllImports from the base Configuration.

For example,

import-sorter.json:

{
  "emptyLinesAfterAllImports": 1
}
// "import/newline-after-import": "off"
import A from "a";

const a = new A();


// "import/newline-after-import": ["error", { "count": 2 }]
import A from "a";


const a = new A();

import/no-useless-path-segments

Rule details:

Use this rule to prevent unnecessary path segments in import and require statements.

When enabled, useless ending slash (/) will be removed when normalizing import and export paths, regardless of removeLastSlashInPath from the base Configuration.

If noUselessIndex is set to true, useless ending index (and index.js[x]/ts[x]) will also be removed, regardless of removeLastIndexInPath from the base Configuration.

For example:

import-sorter.json:

{
  "removeLastSlashInPath": false,
  "removeLastIndexInPath": false
}
// "import/no-useless-path-segments": "off"
import "a/b/";
import A from "./";
import B from "../";
import { C } from "./c/index";

// "import/no-useless-path-segments": ["error", { "noUselessIndex": false }]
import "a/b";
import A from ".";
import B from "..";
import { C } from "./c/index";

// "import/no-useless-path-segments": ["error", { "noUselessIndex": true }]
import "a/b";
import A from ".";
import B from "..";
import { C } from "./c";

Notes:

  • CommonJS imports are NOT supported regardless of commonjs option.

Ignore Rules

Sometimes you may want to ignore some or all ESLint rules. You can achieve that via ignoreESLintRules. It accepts one or more regular expresses and matches rule names against them.

For example, to ignore all ESLint rules:

import_sorter.json:

{
  "ignoreESLintRules": ".*"
}

Or to ignore indent, @typescript-eslint/indent and sort-imports rules:

import_sorter.json:

{
  "ignoreESLintRules": ["indent$", "^sort-imports$"]
}

Limitations

Currently, the inline ESLint disable/enable comments are not recognized, while ignored files and directories are properly handled.