Skip to content

Commit

Permalink
Merge pull request #34 from phanect/cliengine-deprecation
Browse files Browse the repository at this point in the history
Rule redesign & refactoring due to the CLIEngine deprecation
  • Loading branch information
phanect committed Dec 13, 2020
2 parents 2abf7a9 + e7927fb commit 9a74246
Show file tree
Hide file tree
Showing 12 changed files with 475 additions and 407 deletions.
149 changes: 120 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# eslint-plugin-editorconfig

ESLint plugin to follow EditorConfig
An ESLint plugin to enforce EditorConfig rules

[![CircleCI](https://circleci.com/gh/phanect/eslint-plugin-editorconfig.svg?style=svg)](https://circleci.com/gh/phanect/eslint-plugin-editorconfig) [![NPM Version](https://img.shields.io/npm/v/eslint-plugin-editorconfig.svg)](https://npmjs.org/package/eslint-plugin-editorconfig)

Expand All @@ -20,19 +20,35 @@ $ npm install --save-dev eslint eslint-plugin-editorconfig

Like other ESLint plugins,

- add `editorconfig` in the `rules`.
- add `"editorconfig"` in the `plugins`.
- add rules in the `rules`
- add `"editorconfig"` in the `plugins`

in your .eslintrc*

```json
{
// ...
"rules": {
"editorconfig/editorconfig": "error"
"editorconfig/charset": "error",
"editorconfig/eol-last": "error",
"editorconfig/indent": "error",
"editorconfig/linebreak-style": "error",
"editorconfig/no-trailing-spaces": "error"
},
"plugins": [ "editorconfig" ]
}
```

Or you can extend `plugin:editorconfig/all` instead of adding rules.

```json
{
// ...
"extends": [ "plugin:editorconfig/all" ],
"plugins": [ "editorconfig" ]
}
```

## Conflicting ESLint rules

Following rules may conflicts `editorconfig` rule.
Expand All @@ -57,41 +73,116 @@ If they are specified in the extended config, consider adding `plugin:editorconf
}
```

### Passing options
If you extend `plugin:editorconfig/all`, the rules above are turned off too, so you don't have to add `plugin:editorconfig/noconflict` in addition to `plugin:editorconfig/all`.

Internally, eslint-plugin-editorconfig uses above options to verify/fix JS code.
You can pass options to some rules.
### Rules

```json
{
// ...
"rules": {
"editorconfig/editorconfig": [ "error", {
"indent": { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 }},
"no-trailing-spaces": { "skipBlankLines": true, "ignoreComments": true },
}]
},
"plugins": [ "editorconfig" ]
Internally, eslint-plugin-editorconfig uses the existing ESLint and typescript-eslint rules to verify/fix the code.
Some rules allow passing options.

All citation in this section is from the backend ESLint rule document otherwise noted.
#### Enforce EditorConfig rules for charset (`editorconfig/charset`)

The corresponding EditorCongig property is `charset`.
The backend ESLint rule is [`unicode-bom`](https://eslint.org/docs/rules/unicode-bom)

This plugin works only when `utf-8` or `utf-8-bom` is specified. If other value is specified in .editorconfig, ESLint does not verify charset.
ESLint only verifies if BOM is specified or not.

##### Options

None

##### When Not To Use It

> If you use some UTF-16 or UTF-32 files and you want to allow a file to optionally begin with a Unicode BOM, you should turn this rule off.
#### Enforce EditorConfig rules for the newlines at the end of files (`editorconfig/eol-last`)

The corresponding EditorCongig property is `insert_final_newline`.
The backend ESLint rule is [`eol-last`](https://eslint.org/docs/rules/eol-last)

##### Options

None

#### Enforce EditorConfig rules for indentation (`editorconfig/indent`)

The corresponding EditorCongig property is `indent_style` and `indent_size`.
The backend ESLint rule is [`indent`](https://eslint.org/docs/rules/indent) and [`@typescript-eslint/indent`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/indent.md).

As documented, `@typescript-eslint/indent` is unstable currently. Please read typescript-eslint#1824 before using this rule for TypeScript.

##### Options

> * `"SwitchCase"` (default: 0) enforces indentation level for `case` clauses in `switch` statements
> * `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations. It can also be `"first"`, indicating all the declarators should be aligned with the first declarator.
> * `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs. This can also be set to `"off"` to disable checking for file-level IIFEs.
> * `"MemberExpression"` (default: 1) enforces indentation level for multi-line property chains. This can also be set to `"off"` to disable checking for MemberExpression indentation.
> * `"FunctionDeclaration"` takes an object to define rules for function declarations.
> * `parameters` (default: 1) enforces indentation level for parameters in a function declaration. This can either be a number indicating indentation level, or the string `"first"` indicating that all parameters of the declaration must be aligned with the first parameter. This can also be set to `"off"` to disable checking for FunctionDeclaration parameters.
> * `body` (default: 1) enforces indentation level for the body of a function declaration.
> * `"FunctionExpression"` takes an object to define rules for function expressions.
> * `parameters` (default: 1) enforces indentation level for parameters in a function expression. This can either be a number indicating indentation level, or the string `"first"` indicating that all parameters of the expression must be aligned with the first parameter. This can also be set to `"off"` to disable checking for FunctionExpression parameters.
> * `body` (default: 1) enforces indentation level for the body of a function expression.
> * `"CallExpression"` takes an object to define rules for function call expressions.
> * `arguments` (default: 1) enforces indentation level for arguments in a call expression. This can either be a number indicating indentation level, or the string `"first"` indicating that all arguments of the expression must be aligned with the first argument. This can also be set to `"off"` to disable checking for CallExpression arguments.
> * `"ArrayExpression"` (default: 1) enforces indentation level for elements in arrays. It can also be set to the string `"first"`, indicating that all the elements in the array should be aligned with the first element. This can also be set to `"off"` to disable checking for array elements.
> * `"ObjectExpression"` (default: 1) enforces indentation level for properties in objects. It can be set to the string `"first"`, indicating that all properties in the object should be aligned with the first property. This can also be set to `"off"` to disable checking for object properties.
> * `"ImportDeclaration"` (default: 1) enforces indentation level for import statements. It can be set to the string `"first"`, indicating that all imported members from a module should be aligned with the first member in the list. This can also be set to `"off"` to disable checking for imported module members.
> * `"flatTernaryExpressions": true` (`false` by default) requires no indentation for ternary expressions which are nested in other ternary expressions.
> * `"offsetTernaryExpressions": true` (`false` by default) requires indentation for values of ternary expressions.
> * `"ignoredNodes"` accepts an array of [selectors](/docs/developer-guide/selectors.md). If an AST node is matched by any of the selectors, the indentation of tokens which are direct children of that node will be ignored. This can be used as an escape hatch to relax the rule if you disagree with the indentation that it enforces for a particular syntactic pattern.
> * `"ignoreComments"` (default: false) can be used when comments do not need to be aligned with nodes on the previous or next line.
Example (based on the code in the [document for the backend rule `indent`](https://eslint.org/docs/rules/indent)):

```javascript
/*eslint indent: ["error", { "SwitchCase": 1 }]*/

switch(a){
case "a":
break;
case "b":
break;
}
```

Currently, following rules are supported.
See original rule documents for supported options.
Note: The third option parameter of the original backend `indent` rule should be passed as the second option parameter to this `editorconfig/indent` rule.

- [indent](https://eslint.org/docs/rules/indent)
- [no-trailing-spaces](https://eslint.org/docs/rules/no-trailing-spaces)
#### Enforce EditorConfig rules for linebreak style (`editorconfig/linebreak-style`)

## Unsupported EditorConfig Parameters
The corresponding EditorCongig property is `end_of_line`.
The backend ESLint rule is [`linebreak-style`](https://eslint.org/docs/rules/linebreak-style)

Some of the EditorConfig parameters are unsupported.
`end_of_line = cr` is not supported. When `end_of_line = cr` is specified in .editorconfig, This plugin does nothing.

### end_of_line
When `end_of_line = cr` is specified in .editorconfig, ESLint does nothing.
##### Options

### charset
This plugin works only when `utf-8` or `utf-8-bom` is specified. If other value is specified in .editorconfig, charset is not verified by ESLint.
ESLint only verifies if BOM is specified or not.
None

#### Enforce EditorConfig rules for trailing spaces (`editorconfig/no-trailing-spaces`)

The corresponding EditorCongig property is `trim_trailing_whitespace`.
The backend ESLint rule is [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)

##### Options

> * `"skipBlankLines": false` (default) disallows trailing whitespace on empty lines
> * `"skipBlankLines": true` allows trailing whitespace on empty lines
> * `"ignoreComments": false` (default) disallows trailing whitespace in comment blocks
> * `"ignoreComments": true` allows trailing whitespace in comment blocks
Example (copied from [document for the backend rule `no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)):

```javascript
/*eslint no-trailing-spaces: ["error", { "skipBlankLines": true }]*/

var foo = 0;
var baz = 5;
//•••••
```

## License

[MIT](http://vjpr.mit-license.org)
[MIT](https://vjpr.mit-license.org)
46 changes: 46 additions & 0 deletions lib/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @file Report and fix EditorConfig rule violation.
* @author Jumpei Ogawa
*/
"use strict";

const { rules } = require("@typescript-eslint/eslint-plugin");
const editorconfig = require("editorconfig");
const { Linter } = require("eslint");
const { klona } = require("klona/lite");

module.exports.buildRule = ({ baseRuleName, description, omitFirstOption, getESLintOption }) => {
const jsBaseRule = new Linter().getRules().get(baseRuleName);
const tsBaseRule = rules[baseRuleName] ? rules[baseRuleName] : jsBaseRule;

// Remove first option
if (omitFirstOption !== false) {
jsBaseRule.meta.schema.shift();
}

return {
meta: {
...jsBaseRule.meta,

docs: {
...jsBaseRule.meta.docs,
description,
url: "https://github.com/phanect/eslint-plugin-editorconfig",
},
},

create: function(context) {
const filename = context.getFilename();
const ecParams = editorconfig.parseSync(context.getFilename(filename));
const { enabled, eslintOption } = getESLintOption(ecParams);
const baseRule = filename.endsWith(".ts") ? tsBaseRule : jsBaseRule;
const _context = klona(context);

if (eslintOption) {
_context.options.unshift(eslintOption);
}

return enabled ? baseRule.create(_context) : {};
},
};
};
17 changes: 17 additions & 0 deletions lib/rules/charset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use strict";

const { buildRule } = require("../base");

module.exports = buildRule({
baseRuleName: "unicode-bom",
description: "Enforce EditorConfig rules for charset",
getESLintOption: (ecParams) => {
if (ecParams.charset === "utf-8") {
return { enabled: true, eslintOption: "never" };
} else if (ecParams.charset === "utf-8-bom") {
return { enabled: true, eslintOption: "always" };
} else {
return { enabled: false };
}
},
});
132 changes: 0 additions & 132 deletions lib/rules/editorconfig.js

This file was deleted.

0 comments on commit 9a74246

Please sign in to comment.