eslint-plugin-flawless 0.1.0
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.
- package/LICENSE +23 -0
- package/README.md +200 -0
- package/dist/index.d.mts +164 -0
- package/dist/index.mjs +1622 -0
- package/package.json +90 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright for portions of eslint-plugin-arrow-return-style-x are held by u3u,
|
|
4
|
+
2023 as part of eslint-plugin-arrow-return-style. All other copyright for
|
|
5
|
+
eslint-plugin-arrow-return-style-x are held by Christopher Buss
|
|
6
|
+
<christopher.buss@pm.me>, 2025.
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
9
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
10
|
+
the Software without restriction, including without limitation the rights to
|
|
11
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
12
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
20
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
21
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
22
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
23
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# eslint-plugin-template
|
|
2
|
+
|
|
3
|
+
> A modern, TypeScript-first template for building ESLint plugins (Flat Config
|
|
4
|
+
> ready)
|
|
5
|
+
|
|
6
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
7
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
8
|
+
[![License][license-src]][license-href]
|
|
9
|
+
|
|
10
|
+
This repository is a starter template for creating your own ESLint plugin with:
|
|
11
|
+
|
|
12
|
+
- ESLint 9 Flat Config support out of the box
|
|
13
|
+
- TypeScript with strong typing for rules and options
|
|
14
|
+
- Vitest-based rule tests via eslint-vitest-rule-tester
|
|
15
|
+
- Rule scaffolding script to generate rule code, tests, and docs
|
|
16
|
+
- Auto-generated README rules section via eslint-doc-generator
|
|
17
|
+
|
|
18
|
+
Use it as a “Use this template” on GitHub or fork and rename.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
1. Create your repo from this template
|
|
23
|
+
|
|
24
|
+
- Click “Use this template” on GitHub, or
|
|
25
|
+
- Degit locally: `degit christopher-buss/eslint-plugin-template my-plugin`
|
|
26
|
+
|
|
27
|
+
2. Install dependencies
|
|
28
|
+
|
|
29
|
+
```pwsh
|
|
30
|
+
pnpm i
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Rename the package and plugin
|
|
34
|
+
|
|
35
|
+
Update these fields to your plugin name (e.g., `eslint-plugin-awesome`):
|
|
36
|
+
|
|
37
|
+
- `package.json` → `name`, `description`, `repository`, `author`, `license`
|
|
38
|
+
- README title and badges
|
|
39
|
+
|
|
40
|
+
The runtime plugin name (used in config) is derived from the package name by
|
|
41
|
+
removing the `eslint-plugin-` prefix. For `eslint-plugin-awesome` the plugin key
|
|
42
|
+
becomes `awesome`.
|
|
43
|
+
|
|
44
|
+
4. Scaffold your first rule
|
|
45
|
+
|
|
46
|
+
```pwsh
|
|
47
|
+
pnpm create-rule my-new-rule
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This generates:
|
|
51
|
+
|
|
52
|
+
- `src/rules/my-new-rule/rule.ts` – rule implementation
|
|
53
|
+
- `src/rules/my-new-rule/rule.spec.ts` – tests
|
|
54
|
+
- `src/rules/my-new-rule/documentation.md` – rule docs
|
|
55
|
+
|
|
56
|
+
5. Run tests and docs
|
|
57
|
+
|
|
58
|
+
```pwsh
|
|
59
|
+
pnpm test
|
|
60
|
+
pnpm eslint-docs
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The docs command updates the auto-generated rules list in this README.
|
|
64
|
+
|
|
65
|
+
## Using your plugin
|
|
66
|
+
|
|
67
|
+
Once published to npm as `eslint-plugin-awesome`, you can enable it in a
|
|
68
|
+
project.
|
|
69
|
+
|
|
70
|
+
### Flat Config (ESLint 9+)
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
// eslint.config.js / eslint.config.mjs / eslint.config.ts
|
|
74
|
+
import yourPlugin from "eslint-plugin-awesome";
|
|
75
|
+
|
|
76
|
+
export default [
|
|
77
|
+
// Enable all recommended rules from your plugin
|
|
78
|
+
yourPlugin.configs.recommended,
|
|
79
|
+
|
|
80
|
+
// Or wire it manually
|
|
81
|
+
{
|
|
82
|
+
plugins: {
|
|
83
|
+
awesome: yourPlugin,
|
|
84
|
+
},
|
|
85
|
+
rules: {
|
|
86
|
+
"awesome/my-new-rule": "error",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Legacy Config (.eslintrc)
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"extends": ["plugin:yourname/recommended"]
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
Scripts you’ll use during development:
|
|
103
|
+
|
|
104
|
+
- `pnpm dev` – fast stub build for local iteration
|
|
105
|
+
- `pnpm build` – type-safe build with d.ts via tsdown
|
|
106
|
+
- `pnpm test` – run Vitest tests
|
|
107
|
+
- `pnpm lint` – run ESLint on this repo
|
|
108
|
+
- `pnpm typecheck` – run `tsc --noEmit`
|
|
109
|
+
- `pnpm eslint-docs` – regenerate README rules list
|
|
110
|
+
- `pnpm release` – bump version via bumpp
|
|
111
|
+
|
|
112
|
+
Requirements:
|
|
113
|
+
|
|
114
|
+
- Node.js >= 20
|
|
115
|
+
- pnpm >= 10
|
|
116
|
+
- ESLint >= 9.15.0 (peer dep for consumers)
|
|
117
|
+
|
|
118
|
+
## Project structure
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
src/
|
|
122
|
+
configs/ # Flat config presets (e.g., recommended)
|
|
123
|
+
rules/ # Your rules (each in its own folder)
|
|
124
|
+
plugin.ts # Plugin host (name, version, rules)
|
|
125
|
+
util.ts # Rule creator with docs links
|
|
126
|
+
index.ts # Entry combining plugin + configs (default export)
|
|
127
|
+
scripts/
|
|
128
|
+
create-rule.ts # Scaffolds a new rule (code, tests, docs)
|
|
129
|
+
template/ # Rule templates used by the script
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
{ "extends": ["plugin:awesome/recommended"] }
|
|
133
|
+
|
|
134
|
+
- The plugin key is computed from your package name (see `src/plugin.ts`).
|
|
135
|
+
- `src/configs/recommended` is provided for convenience; add your rules there
|
|
136
|
+
when ready.
|
|
137
|
+
|
|
138
|
+
## Scaffolding a rule
|
|
139
|
+
|
|
140
|
+
```pwsh
|
|
141
|
+
pnpm create-rule my-new-rule
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
What happens:
|
|
145
|
+
|
|
146
|
+
1. Creates `src/rules/my-new-rule/` with `rule.ts`, `rule.spec.ts`,
|
|
147
|
+
`documentation.md`.
|
|
148
|
+
2. Attempts to register the rule. If automatic edit cannot be applied, the
|
|
149
|
+
script prints the exact import and entry you can paste into your plugin/index
|
|
150
|
+
file.
|
|
151
|
+
3. Run `pnpm test` to validate, then `pnpm eslint-docs` to refresh this README.
|
|
152
|
+
|
|
153
|
+
## Publishing
|
|
154
|
+
|
|
155
|
+
Typical flow:
|
|
156
|
+
|
|
157
|
+
```pwsh
|
|
158
|
+
pnpm test
|
|
159
|
+
pnpm build
|
|
160
|
+
pnpm release # chooses the next semver and commits tags
|
|
161
|
+
# CI publishes to npm
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Rules reference
|
|
165
|
+
|
|
166
|
+
Generate this section with:
|
|
167
|
+
|
|
168
|
+
```pwsh
|
|
169
|
+
pnpm eslint-docs
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
<!-- begin auto-generated rules list -->
|
|
173
|
+
|
|
174
|
+
💭 Requires
|
|
175
|
+
[type information](https://typescript-eslint.io/linting/typed-linting).
|
|
176
|
+
|
|
177
|
+
| Name | Description | 💭 |
|
|
178
|
+
| :---------------------------------------------------------------- | :---------------------------------------------------------- | :-- |
|
|
179
|
+
| [naming-convention](src/rules/naming-convention/documentation.md) | Enforce naming conventions for everything across a codebase | 💭 |
|
|
180
|
+
|
|
181
|
+
<!-- end auto-generated rules list -->
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
PRs and issues welcome. If you’re using this as a template, adapt the sections
|
|
186
|
+
to your needs and replace the badges and links.
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
[MIT](./LICENSE) © 2025 [Christopher Buss](https://github.com/christopher-buss)
|
|
191
|
+
|
|
192
|
+
<!-- Badges -->
|
|
193
|
+
|
|
194
|
+
[npm-version-src]: https://img.shields.io/npm/v/eslint-plugin-flawless
|
|
195
|
+
[npm-version-href]: https://npmjs.com/package/eslint-plugin-flawless
|
|
196
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/eslint-plugin-flawless
|
|
197
|
+
[npm-downloads-href]: https://npmjs.com/package/eslint-plugin-flawless
|
|
198
|
+
[license-src]:
|
|
199
|
+
https://img.shields.io/github/license/christopher-buss/eslint-plugin-template.svg
|
|
200
|
+
[license-href]: ./LICENSE
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { TSESLint } from "@typescript-eslint/utils";
|
|
2
|
+
import "@typescript-eslint/utils/eslint-utils";
|
|
3
|
+
import * as _typescript_eslint_utils_ts_eslint0 from "@typescript-eslint/utils/ts-eslint";
|
|
4
|
+
import { Linter } from "eslint";
|
|
5
|
+
|
|
6
|
+
//#region src/util.d.ts
|
|
7
|
+
interface PluginDocumentation {
|
|
8
|
+
description: string;
|
|
9
|
+
recommended?: boolean;
|
|
10
|
+
requiresTypeChecking: boolean;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/rules/naming-convention/utils/enums.d.ts
|
|
14
|
+
declare const Selector: {
|
|
15
|
+
readonly variable: 1;
|
|
16
|
+
readonly function: 2;
|
|
17
|
+
readonly parameter: 4;
|
|
18
|
+
readonly objectStyleEnum: 8;
|
|
19
|
+
readonly parameterProperty: 16;
|
|
20
|
+
readonly classicAccessor: 32;
|
|
21
|
+
readonly enumMember: 64;
|
|
22
|
+
readonly classMethod: 128;
|
|
23
|
+
readonly objectLiteralMethod: 256;
|
|
24
|
+
readonly typeMethod: 512;
|
|
25
|
+
readonly classProperty: 1024;
|
|
26
|
+
readonly objectLiteralProperty: 2048;
|
|
27
|
+
readonly typeProperty: 4096;
|
|
28
|
+
readonly autoAccessor: 8192;
|
|
29
|
+
readonly class: 16384;
|
|
30
|
+
readonly interface: 32768;
|
|
31
|
+
readonly typeAlias: 65536;
|
|
32
|
+
readonly enum: 131072;
|
|
33
|
+
readonly typeParameter: 262144;
|
|
34
|
+
readonly import: 524288;
|
|
35
|
+
};
|
|
36
|
+
type SelectorString = keyof typeof Selector;
|
|
37
|
+
declare const MetaSelector: {
|
|
38
|
+
readonly default: -1;
|
|
39
|
+
readonly variableLike: 15;
|
|
40
|
+
readonly memberLike: 16368;
|
|
41
|
+
readonly typeLike: 507904;
|
|
42
|
+
readonly method: 896;
|
|
43
|
+
readonly property: 7168;
|
|
44
|
+
readonly accessor: 8224;
|
|
45
|
+
};
|
|
46
|
+
type MetaSelectorString = keyof typeof MetaSelector;
|
|
47
|
+
declare const Modifier: {
|
|
48
|
+
readonly const: 1;
|
|
49
|
+
readonly readonly: 2;
|
|
50
|
+
readonly static: 4;
|
|
51
|
+
readonly public: 8;
|
|
52
|
+
readonly protected: 16;
|
|
53
|
+
readonly private: 32;
|
|
54
|
+
readonly "#private": 64;
|
|
55
|
+
readonly abstract: 128;
|
|
56
|
+
readonly destructured: 256;
|
|
57
|
+
readonly global: 512;
|
|
58
|
+
readonly exported: 1024;
|
|
59
|
+
readonly unused: 2048;
|
|
60
|
+
readonly requiresQuotes: 4096;
|
|
61
|
+
readonly override: 8192;
|
|
62
|
+
readonly async: 16384;
|
|
63
|
+
readonly default: 32768;
|
|
64
|
+
readonly namespace: 65536;
|
|
65
|
+
};
|
|
66
|
+
type ModifierString = keyof typeof Modifier;
|
|
67
|
+
declare const PredefinedFormat: {
|
|
68
|
+
readonly camelCase: 1;
|
|
69
|
+
readonly strictCamelCase: 2;
|
|
70
|
+
readonly PascalCase: 3;
|
|
71
|
+
readonly StrictPascalCase: 4;
|
|
72
|
+
readonly snake_case: 5;
|
|
73
|
+
readonly UPPER_CASE: 6;
|
|
74
|
+
};
|
|
75
|
+
type PredefinedFormatString = keyof typeof PredefinedFormat;
|
|
76
|
+
declare const TypeModifier: {
|
|
77
|
+
readonly boolean: 131072;
|
|
78
|
+
readonly string: 262144;
|
|
79
|
+
readonly number: 524288;
|
|
80
|
+
readonly function: 1048576;
|
|
81
|
+
readonly array: 2097152;
|
|
82
|
+
};
|
|
83
|
+
type TypeModifierString = keyof typeof TypeModifier;
|
|
84
|
+
declare const UnderscoreOption: {
|
|
85
|
+
readonly forbid: 1;
|
|
86
|
+
readonly allow: 2;
|
|
87
|
+
readonly require: 3;
|
|
88
|
+
readonly requireDouble: 4;
|
|
89
|
+
readonly allowDouble: 5;
|
|
90
|
+
readonly allowSingleOrDouble: 6;
|
|
91
|
+
};
|
|
92
|
+
type IndividualAndMetaSelectorsString = MetaSelectorString | SelectorString;
|
|
93
|
+
type UnderscoreOptionString = keyof typeof UnderscoreOption;
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/rules/naming-convention/utils/types.d.ts
|
|
96
|
+
interface MatchRegex {
|
|
97
|
+
match: boolean;
|
|
98
|
+
regex: string;
|
|
99
|
+
}
|
|
100
|
+
interface NamingSelector {
|
|
101
|
+
custom?: MatchRegex;
|
|
102
|
+
filter?: MatchRegex | string;
|
|
103
|
+
/**
|
|
104
|
+
* Format options.
|
|
105
|
+
*/
|
|
106
|
+
format: Array<PredefinedFormatString> | null;
|
|
107
|
+
leadingUnderscore?: UnderscoreOptionString;
|
|
108
|
+
modifiers?: Array<ModifierString>;
|
|
109
|
+
prefix?: Array<string>;
|
|
110
|
+
/**
|
|
111
|
+
* Selector options.
|
|
112
|
+
*/
|
|
113
|
+
selector: Array<IndividualAndMetaSelectorsString> | IndividualAndMetaSelectorsString;
|
|
114
|
+
suffix?: Array<string>;
|
|
115
|
+
trailingUnderscore?: UnderscoreOptionString;
|
|
116
|
+
types?: Array<TypeModifierString>;
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/rules/naming-convention/rule.d.ts
|
|
120
|
+
type MessageIds$1 = "doesNotMatchFormat" | "doesNotMatchFormatTrimmed" | "missingAffix" | "missingUnderscore" | "satisfyCustom" | "unexpectedUnderscore";
|
|
121
|
+
type Options$1 = Array<NamingSelector>;
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/plugin.d.ts
|
|
124
|
+
declare const plugin: {
|
|
125
|
+
meta: {
|
|
126
|
+
name: string;
|
|
127
|
+
version: string;
|
|
128
|
+
};
|
|
129
|
+
rules: {
|
|
130
|
+
"naming-convention": TSESLint.RuleModule<MessageIds$1, Options$1, PluginDocumentation, TSESLint.RuleListener>;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/index.d.ts
|
|
135
|
+
declare const _default: {
|
|
136
|
+
configs: {
|
|
137
|
+
recommended: {
|
|
138
|
+
plugins: {
|
|
139
|
+
[x: string]: {
|
|
140
|
+
meta: {
|
|
141
|
+
name: string;
|
|
142
|
+
version: string;
|
|
143
|
+
};
|
|
144
|
+
rules: {
|
|
145
|
+
"naming-convention": _typescript_eslint_utils_ts_eslint0.RuleModule<MessageIds$1, Options$1, PluginDocumentation, _typescript_eslint_utils_ts_eslint0.RuleListener>;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
rules: {};
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
meta: {
|
|
153
|
+
name: string;
|
|
154
|
+
version: string;
|
|
155
|
+
};
|
|
156
|
+
rules: {
|
|
157
|
+
"naming-convention": _typescript_eslint_utils_ts_eslint0.RuleModule<MessageIds$1, Options$1, PluginDocumentation, _typescript_eslint_utils_ts_eslint0.RuleListener>;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
type RuleOptions = { [K in keyof RuleDefinitions]: RuleDefinitions[K]["defaultOptions"] };
|
|
161
|
+
type Rules = { [K in keyof RuleOptions]: Linter.RuleEntry<RuleOptions[K]> };
|
|
162
|
+
type RuleDefinitions = typeof plugin.rules;
|
|
163
|
+
//#endregion
|
|
164
|
+
export { RuleOptions, Rules, _default as default };
|