Skip to content

Commit 9a74246

Browse files
authored
Merge pull request #34 from phanect/cliengine-deprecation
Rule redesign & refactoring due to the CLIEngine deprecation
2 parents 2abf7a9 + e7927fb commit 9a74246

File tree

12 files changed

+475
-407
lines changed

12 files changed

+475
-407
lines changed

README.md

Lines changed: 120 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# eslint-plugin-editorconfig
22

3-
ESLint plugin to follow EditorConfig
3+
An ESLint plugin to enforce EditorConfig rules
44

55
[![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)
66

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

2121
Like other ESLint plugins,
2222

23-
- add `editorconfig` in the `rules`.
24-
- add `"editorconfig"` in the `plugins`.
23+
- add rules in the `rules`
24+
- add `"editorconfig"` in the `plugins`
25+
26+
in your .eslintrc*
2527

2628
```json
2729
{
2830
// ...
2931
"rules": {
30-
"editorconfig/editorconfig": "error"
32+
"editorconfig/charset": "error",
33+
"editorconfig/eol-last": "error",
34+
"editorconfig/indent": "error",
35+
"editorconfig/linebreak-style": "error",
36+
"editorconfig/no-trailing-spaces": "error"
3137
},
3238
"plugins": [ "editorconfig" ]
3339
}
3440
```
3541

42+
Or you can extend `plugin:editorconfig/all` instead of adding rules.
43+
44+
```json
45+
{
46+
// ...
47+
"extends": [ "plugin:editorconfig/all" ],
48+
"plugins": [ "editorconfig" ]
49+
}
50+
```
51+
3652
## Conflicting ESLint rules
3753

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

60-
### Passing options
76+
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`.
6177

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

65-
```json
66-
{
67-
// ...
68-
"rules": {
69-
"editorconfig/editorconfig": [ "error", {
70-
"indent": { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 }},
71-
"no-trailing-spaces": { "skipBlankLines": true, "ignoreComments": true },
72-
}]
73-
},
74-
"plugins": [ "editorconfig" ]
80+
Internally, eslint-plugin-editorconfig uses the existing ESLint and typescript-eslint rules to verify/fix the code.
81+
Some rules allow passing options.
82+
83+
All citation in this section is from the backend ESLint rule document otherwise noted.
84+
#### Enforce EditorConfig rules for charset (`editorconfig/charset`)
85+
86+
The corresponding EditorCongig property is `charset`.
87+
The backend ESLint rule is [`unicode-bom`](https://eslint.org/docs/rules/unicode-bom)
88+
89+
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.
90+
ESLint only verifies if BOM is specified or not.
91+
92+
##### Options
93+
94+
None
95+
96+
##### When Not To Use It
97+
98+
> 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.
99+
100+
#### Enforce EditorConfig rules for the newlines at the end of files (`editorconfig/eol-last`)
101+
102+
The corresponding EditorCongig property is `insert_final_newline`.
103+
The backend ESLint rule is [`eol-last`](https://eslint.org/docs/rules/eol-last)
104+
105+
##### Options
106+
107+
None
108+
109+
#### Enforce EditorConfig rules for indentation (`editorconfig/indent`)
110+
111+
The corresponding EditorCongig property is `indent_style` and `indent_size`.
112+
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).
113+
114+
As documented, `@typescript-eslint/indent` is unstable currently. Please read typescript-eslint#1824 before using this rule for TypeScript.
115+
116+
##### Options
117+
118+
> * `"SwitchCase"` (default: 0) enforces indentation level for `case` clauses in `switch` statements
119+
> * `"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.
120+
> * `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs. This can also be set to `"off"` to disable checking for file-level IIFEs.
121+
> * `"MemberExpression"` (default: 1) enforces indentation level for multi-line property chains. This can also be set to `"off"` to disable checking for MemberExpression indentation.
122+
> * `"FunctionDeclaration"` takes an object to define rules for function declarations.
123+
> * `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.
124+
> * `body` (default: 1) enforces indentation level for the body of a function declaration.
125+
> * `"FunctionExpression"` takes an object to define rules for function expressions.
126+
> * `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.
127+
> * `body` (default: 1) enforces indentation level for the body of a function expression.
128+
> * `"CallExpression"` takes an object to define rules for function call expressions.
129+
> * `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.
130+
> * `"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.
131+
> * `"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.
132+
> * `"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.
133+
> * `"flatTernaryExpressions": true` (`false` by default) requires no indentation for ternary expressions which are nested in other ternary expressions.
134+
> * `"offsetTernaryExpressions": true` (`false` by default) requires indentation for values of ternary expressions.
135+
> * `"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.
136+
> * `"ignoreComments"` (default: false) can be used when comments do not need to be aligned with nodes on the previous or next line.
137+
138+
Example (based on the code in the [document for the backend rule `indent`](https://eslint.org/docs/rules/indent)):
139+
140+
```javascript
141+
/*eslint indent: ["error", { "SwitchCase": 1 }]*/
142+
143+
switch(a){
144+
case "a":
145+
break;
146+
case "b":
147+
break;
75148
}
76149
```
77150

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

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

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

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

88-
### end_of_line
89-
When `end_of_line = cr` is specified in .editorconfig, ESLint does nothing.
160+
##### Options
90161

91-
### charset
92-
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.
93-
ESLint only verifies if BOM is specified or not.
162+
None
163+
164+
#### Enforce EditorConfig rules for trailing spaces (`editorconfig/no-trailing-spaces`)
165+
166+
The corresponding EditorCongig property is `trim_trailing_whitespace`.
167+
The backend ESLint rule is [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)
168+
169+
##### Options
170+
171+
> * `"skipBlankLines": false` (default) disallows trailing whitespace on empty lines
172+
> * `"skipBlankLines": true` allows trailing whitespace on empty lines
173+
> * `"ignoreComments": false` (default) disallows trailing whitespace in comment blocks
174+
> * `"ignoreComments": true` allows trailing whitespace in comment blocks
175+
176+
Example (copied from [document for the backend rule `no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)):
177+
178+
```javascript
179+
/*eslint no-trailing-spaces: ["error", { "skipBlankLines": true }]*/
180+
181+
var foo = 0;
182+
var baz = 5;
183+
//•••••
184+
```
94185

95186
## License
96187

97-
[MIT](http://vjpr.mit-license.org)
188+
[MIT](https://vjpr.mit-license.org)

lib/base.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @file Report and fix EditorConfig rule violation.
3+
* @author Jumpei Ogawa
4+
*/
5+
"use strict";
6+
7+
const { rules } = require("@typescript-eslint/eslint-plugin");
8+
const editorconfig = require("editorconfig");
9+
const { Linter } = require("eslint");
10+
const { klona } = require("klona/lite");
11+
12+
module.exports.buildRule = ({ baseRuleName, description, omitFirstOption, getESLintOption }) => {
13+
const jsBaseRule = new Linter().getRules().get(baseRuleName);
14+
const tsBaseRule = rules[baseRuleName] ? rules[baseRuleName] : jsBaseRule;
15+
16+
// Remove first option
17+
if (omitFirstOption !== false) {
18+
jsBaseRule.meta.schema.shift();
19+
}
20+
21+
return {
22+
meta: {
23+
...jsBaseRule.meta,
24+
25+
docs: {
26+
...jsBaseRule.meta.docs,
27+
description,
28+
url: "https://github.com/phanect/eslint-plugin-editorconfig",
29+
},
30+
},
31+
32+
create: function(context) {
33+
const filename = context.getFilename();
34+
const ecParams = editorconfig.parseSync(context.getFilename(filename));
35+
const { enabled, eslintOption } = getESLintOption(ecParams);
36+
const baseRule = filename.endsWith(".ts") ? tsBaseRule : jsBaseRule;
37+
const _context = klona(context);
38+
39+
if (eslintOption) {
40+
_context.options.unshift(eslintOption);
41+
}
42+
43+
return enabled ? baseRule.create(_context) : {};
44+
},
45+
};
46+
};

lib/rules/charset.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"use strict";
2+
3+
const { buildRule } = require("../base");
4+
5+
module.exports = buildRule({
6+
baseRuleName: "unicode-bom",
7+
description: "Enforce EditorConfig rules for charset",
8+
getESLintOption: (ecParams) => {
9+
if (ecParams.charset === "utf-8") {
10+
return { enabled: true, eslintOption: "never" };
11+
} else if (ecParams.charset === "utf-8-bom") {
12+
return { enabled: true, eslintOption: "always" };
13+
} else {
14+
return { enabled: false };
15+
}
16+
},
17+
});

lib/rules/editorconfig.js

Lines changed: 0 additions & 132 deletions
This file was deleted.

0 commit comments

Comments
 (0)