@zilero/eslint 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aleksandr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # 🎯 @zilero/eslint
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/Zilero232/dev-config-hub">
5
+ <img src="https://img.shields.io/github/actions/workflow/status/Zilero232/dev-config-hub/integrate.yaml?label=CI&logo=GitHub" alt="CI status">
6
+ </a>
7
+ <a href="https://www.npmjs.com/package/@zilero/eslint">
8
+ <img src="https://img.shields.io/npm/dm/@zilero/eslint?logo=NPM" alt="npm downloads">
9
+ </a>
10
+ <a href="https://github.com/Zilero232/cli">
11
+ <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="npm license">
12
+ </a>
13
+ <a href="https://github.com/Zilero232/dev-config-hub/tree/main/tools/eslint">
14
+ <img src="https://img.shields.io/npm/v/@zilero/eslint?label=version" alt="version">
15
+ </a>
16
+ </p>
17
+
18
+ > ✨ Comprehensive ESLint configuration for React and Node.js projects with TypeScript support
19
+
20
+ ## ✨ Features
21
+
22
+ - 📦 Ready - made configuration out of the box
23
+ - 🚀 Optimized for React and Node.js
24
+ - 💪 Full TypeScript support
25
+ - 🎨 Integration with Prettier
26
+ - ⚡ High performance
27
+ - 🔧 Easy setup
28
+ - 📱 Next support.JS
29
+ - 🎭 JSX/TSX compatibility
30
+
31
+ ## 📥 Installation
32
+
33
+ ### Using npm
34
+
35
+ ```bash
36
+ npm install --save-dev @zilero/eslint
37
+ ```
38
+ ### Using yarn
39
+
40
+ ```bash
41
+ yarn add -D @zilero/eslint
42
+ ```
43
+
44
+ ### Using pnpm
45
+
46
+ ```bash
47
+ pnpm install -D @zilero/eslint
48
+ ```
49
+
50
+ ## 🚀 Quick start
51
+
52
+ Create the `.eslint.config.js` at the root of your project:
53
+
54
+ ```javascript
55
+ import { eslint } from '@zilero/eslint';
56
+
57
+ export default eslint({
58
+ typescript: true
59
+ });
60
+ ```
61
+
62
+ Add scripts to your `package.json`:
63
+
64
+ ```json
65
+ "scripts": {
66
+ "lint:check": "eslint",
67
+ "lint:fix": "eslint --fix",
68
+ }
69
+ ```
70
+
71
+ ## 🤝 Contributing
72
+
73
+ We'd love for you to contribute to `@zilero/eslint`! Whether it's reporting bugs, suggesting features, or submitting pull requests, your help is always appreciated.
74
+
75
+ ### How to contribute:
76
+
77
+ 1. Fork the repository.
78
+ 2. Create a new branch (`git checkout -b feature/your-feature`).
79
+ 3. Make your changes.
80
+ 4. Commit your changes (`git commit -am 'Add new feature'`).
81
+ 5. Push to the branch (`git push origin feature/your-feature`).
82
+ 6. Open a pull request.
83
+
84
+ ## 📜 Code of Conduct
85
+
86
+ Please follow our [Code of Conduct](CODE_OF_CONDUCT.md) when participating in this project to ensure a welcoming and productive atmosphere.
87
+
88
+ ## 🔒 Security Policy
89
+
90
+ Security is our priority. If you encounter any issues, please read our full [Security Policy](SECURITY.md) to report vulnerabilities safely and responsibly.
91
+
92
+ ## 👥 Team
93
+
94
+ These folks keep the project moving and are resources for help.
95
+
96
+ <table>
97
+ <tbody>
98
+ <tr>
99
+ <td align="center" valign="top" width="11%">
100
+ <a href="https://career.habr.com/zilero">
101
+ <img src="https://avatars.githubusercontent.com/u/68345676?s=400&u=eb7df22c29a8aca48def78ec54a7526601c9fd8f&v=4" width="100" height="100" alt="Artemev Alexandr - Avatar">
102
+ <br />
103
+ Artemev A. A.
104
+ </a>
105
+ </td>
106
+ </tr>
107
+ </tbody>
108
+ </table>
109
+
110
+ ## 📄 License
111
+
112
+ License `@zilero/eslint` is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,462 @@
1
+ import antfu from '@antfu/eslint-config';
2
+ import pluginNext from '@next/eslint-plugin-next';
3
+ import pluginJsxA11y from 'eslint-plugin-jsx-a11y';
4
+ import pluginReact from 'eslint-plugin-react';
5
+ import { transformRules } from './utils/transformRules';
6
+
7
+ /** @type {import('@zilero/eslint').Eslint} */
8
+ export const eslint = ({ jsxA11y = false, next = false, sort = false, ...options }, ...configs) => {
9
+ const stylistic = options?.stylistic ?? false;
10
+
11
+ if (next) {
12
+ configs.unshift({
13
+ name: 'eslint/next',
14
+ plugins: {
15
+ 'eslint-next': pluginNext,
16
+ },
17
+ rules: {
18
+ ...transformRules(pluginNext.configs.recommended.rules, '@next/next', 'eslint-next'),
19
+ },
20
+ });
21
+ }
22
+
23
+ if (jsxA11y) {
24
+ configs.unshift({
25
+ name: 'eslint/jsx-a11y',
26
+ plugins: {
27
+ 'eslint-jsx-a11y': pluginJsxA11y,
28
+ },
29
+ rules: {
30
+ ...transformRules(pluginJsxA11y.flatConfigs.recommended.rules, 'jsx-a11y', 'eslint-jsx-a11y'),
31
+ },
32
+ });
33
+ }
34
+
35
+ if (options.react) {
36
+ configs.unshift({
37
+ name: 'eslint/react',
38
+ plugins: {
39
+ 'eslint-react': pluginReact,
40
+ },
41
+ rules: {
42
+ ...transformRules(pluginReact.configs.recommended.rules, 'react', 'eslint-react'),
43
+
44
+ /**
45
+ * Enforce arrow functions for React components
46
+ * @example
47
+ * // ✓ Good
48
+ * const Component = () => { return <div />; }
49
+ * // ✗ Bad
50
+ * function Component() { return <div />; }
51
+ */
52
+ 'eslint-react/function-component-definition': [
53
+ 'error',
54
+ {
55
+ namedComponents: ['arrow-function'], // For named components
56
+ unnamedComponents: 'arrow-function', // For anonymous components
57
+ },
58
+ ],
59
+
60
+ /**
61
+ * Disable PropTypes validation
62
+ * Use TypeScript types instead of runtime checks
63
+ */
64
+ 'eslint-react/prop-types': 'off',
65
+
66
+ /**
67
+ * Disable React import requirement
68
+ * Not needed in modern React with new JSX transform
69
+ * @example
70
+ * // ✓ Good
71
+ * const App = () => <div />
72
+ * // Old way (no longer needed)
73
+ * import React from 'react'
74
+ */
75
+ 'eslint-react/react-in-jsx-scope': 'off',
76
+
77
+ /**
78
+ * Enforce destructuring for props and state
79
+ * @example
80
+ * // ✓ Good
81
+ * const { name, age } = props;
82
+ * // ✗ Bad
83
+ * const name = props.name;
84
+ */
85
+ 'eslint-react/destructuring-assignment': ['error', 'always'],
86
+
87
+ /**
88
+ * Enforce consistent naming for hooks
89
+ * @example
90
+ * // ✓ Good
91
+ * const useCustomHook = () => {};
92
+ * // ✗ Bad
93
+ * const customHook = () => {};
94
+ */
95
+ 'eslint-react/hook-naming-convention': [
96
+ 'error',
97
+ {
98
+ prefix: 'use',
99
+ },
100
+ ],
101
+
102
+ /**
103
+ * Enforce consistent naming for boolean props
104
+ * @example
105
+ * // ✓ Good
106
+ * <Component isVisible={true} hasData={false} />
107
+ * // ✗ Bad
108
+ * <Component visible={true} data={false} />
109
+ */
110
+ 'eslint-react/boolean-prop-naming': ['error', { prefix: 'is|has|should|can|will|did' }],
111
+ },
112
+
113
+ // React-specific settings
114
+ settings: {
115
+ react: {
116
+ version: 'detect', // Automatically detect React version
117
+ },
118
+ },
119
+ });
120
+ }
121
+
122
+ if (stylistic) {
123
+ configs.unshift({
124
+ name: 'eslint/formatter',
125
+ rules: {
126
+ /**
127
+ * Always require parentheses around arrow function arguments
128
+ * @example
129
+ * // ✓ Good
130
+ * (x) => x
131
+ * // ✗ Bad
132
+ * x => x
133
+ */
134
+ 'style/arrow-parens': ['error', 'always'],
135
+
136
+ /**
137
+ * Brace style for blocks - disabled to avoid conflicts
138
+ * Let other rules handle this
139
+ */
140
+ 'style/brace-style': 'off',
141
+
142
+ /**
143
+ * Disallow trailing commas
144
+ * @example
145
+ * // ✓ Good
146
+ * { a: 1, b: 2 }
147
+ * // ✗ Bad
148
+ * { a: 1, b: 2, }
149
+ */
150
+ 'style/comma-dangle': ['error', 'never'],
151
+
152
+ /**
153
+ * Enforce 2 spaces indentation with 1 space for switch cases
154
+ * @example
155
+ * // ✓ Good
156
+ * function foo() {
157
+ * if (bar) {
158
+ * baz();
159
+ * }
160
+ * }
161
+ */
162
+ 'style/indent': ['error', 2, { SwitchCase: 1 }],
163
+
164
+ /**
165
+ * JSX newline formatting - disabled for better readability
166
+ */
167
+ 'style/jsx-curly-newline': 'off',
168
+
169
+ /**
170
+ * Allow multiple JSX expressions per line
171
+ */
172
+ 'style/jsx-one-expression-per-line': 'off',
173
+
174
+ /**
175
+ * Use single quotes in JSX
176
+ * @example
177
+ * // ✓ Good
178
+ * <div className='foo'>
179
+ * // ✗ Bad
180
+ * <div className="foo">
181
+ */
182
+ 'style/jsx-quotes': ['error', 'prefer-single'],
183
+
184
+ /**
185
+ * Enforce Unix linebreaks (LF)
186
+ * Prevents issues with different operating systems
187
+ */
188
+ 'style/linebreak-style': ['error', 'unix'],
189
+
190
+ /**
191
+ * Maximum line length of 150 characters
192
+ * Ignores comments, strings, and template literals
193
+ * @example
194
+ * // ✓ Good: Lines under 150 characters
195
+ * // ✗ Bad: Lines over 150 characters (with exceptions)
196
+ */
197
+ 'style/max-len': [
198
+ 'error',
199
+ 150,
200
+ 2,
201
+ {
202
+ ignoreComments: true, // Ignore comments when checking length
203
+ ignoreStrings: true, // Ignore strings when checking length
204
+ ignoreTemplateLiterals: true, // Ignore template literals when checking length
205
+ },
206
+ ],
207
+
208
+ /**
209
+ * TypeScript interface/type member delimiter style - disabled
210
+ */
211
+ 'style/member-delimiter-style': 'off',
212
+
213
+ /**
214
+ * Allow flexible multiline ternary expressions
215
+ */
216
+ 'style/multiline-ternary': 'off',
217
+
218
+ /**
219
+ * Disallow tabs in favor of spaces
220
+ */
221
+ 'style/no-tabs': 'error',
222
+
223
+ /**
224
+ * Allow flexible operator linebreaks
225
+ */
226
+ 'style/operator-linebreak': 'off',
227
+
228
+ /**
229
+ * Quotation marks for object properties - disabled
230
+ */
231
+ 'style/quote-props': 'off',
232
+
233
+ /**
234
+ * Use single quotes for strings, allow template literals
235
+ * @example
236
+ * // ✓ Good
237
+ * const str = 'string'
238
+ * const template = `template`
239
+ * // ✗ Bad
240
+ * const str = "string"
241
+ */
242
+ 'style/quotes': ['error', 'single', { allowTemplateLiterals: true }],
243
+
244
+ /**
245
+ * Require semicolons at the end of statements
246
+ * @example
247
+ * // ✓ Good
248
+ * const foo = 'bar';
249
+ * // ✗ Bad
250
+ * const foo = 'bar'
251
+ */
252
+ 'style/semi': ['error', 'always'],
253
+ },
254
+ });
255
+ }
256
+
257
+ if (sort) {
258
+ configs.unshift({
259
+ name: 'eslint/sort',
260
+ rules: {
261
+ /**
262
+ * Sort array includes calls alphabetically
263
+ * @example
264
+ * // ✓ Good
265
+ * ['a', 'b', 'c'].includes(x)
266
+ * // ✗ Bad
267
+ * ['c', 'a', 'b'].includes(x)
268
+ */
269
+ 'perfectionist/sort-array-includes': [
270
+ 'error',
271
+ {
272
+ order: 'asc', // Ascending order
273
+ type: 'alphabetical', // Sort alphabetically
274
+ },
275
+ ],
276
+
277
+ /**
278
+ * Enforce consistent import ordering
279
+ * Groups:
280
+ * 1. Type imports
281
+ * 2. Built-in & external modules
282
+ * 3. Internal type imports
283
+ * 4. Internal modules
284
+ * 5. Parent/sibling type imports
285
+ * 6. Parent/sibling modules
286
+ * 7. Object imports
287
+ * 8. Style imports
288
+ * 9. Side effect styles
289
+ * 10. Unknown
290
+ */
291
+ 'perfectionist/sort-imports': [
292
+ 'error',
293
+ {
294
+ groups: [
295
+ 'type', // Type imports first
296
+ ['builtin', 'external'], // Node.js and external packages
297
+ 'internal-type', // Internal type imports
298
+ ['internal'], // Internal modules
299
+ ['parent-type', 'sibling-type', 'index-type'], // Relative type imports
300
+ ['parent', 'sibling', 'index'], // Relative module imports
301
+ 'object', // Object imports
302
+ 'style', // Style imports
303
+ 'side-effect-style', // Side effect styles
304
+ 'unknown', // Everything else
305
+ ],
306
+ internalPattern: ['^~/.*', '^@/.*'], // Internal module patterns
307
+ newlinesBetween: 'always', // Always add newlines between groups
308
+ order: 'asc', // Ascending order
309
+ type: 'natural', // Natural sort order
310
+ },
311
+ ],
312
+
313
+ /**
314
+ * Sort interface members
315
+ * @example
316
+ * // ✓ Good
317
+ * interface User {
318
+ * age: number;
319
+ * name: string;
320
+ * sayHello(): void;
321
+ * }
322
+ */
323
+ 'perfectionist/sort-interfaces': [
324
+ 'error',
325
+ {
326
+ groups: ['unknown', 'method', 'multiline'], // Group by type
327
+ order: 'asc', // Ascending order
328
+ type: 'alphabetical', // Sort alphabetically
329
+ },
330
+ ],
331
+
332
+ /**
333
+ * Sort JSX props in consistent order
334
+ * @example
335
+ * // ✓ Good
336
+ * <Button
337
+ * ref={ref}
338
+ * disabled
339
+ * label="Click me"
340
+ * onClick={handleClick}
341
+ * />
342
+ */
343
+ 'perfectionist/sort-jsx-props': [
344
+ 'error',
345
+ {
346
+ customGroups: {
347
+ callback: 'on*', // Event handlers
348
+ reserved: ['key', 'ref'], // React special props
349
+ },
350
+ groups: [
351
+ 'shorthand', // Boolean props
352
+ 'reserved', // React special props
353
+ 'multiline', // Multiline props
354
+ 'unknown', // Other props
355
+ 'callback', // Event handlers
356
+ ],
357
+ order: 'asc', // Ascending order
358
+ type: 'alphabetical', // Sort alphabetically
359
+ },
360
+ ],
361
+
362
+ /**
363
+ * Sort union types consistently
364
+ * @example
365
+ * // ✓ Good
366
+ * type Status = 'error' | 'loading' | 'success';
367
+ * type Value = boolean | null | number | string;
368
+ */
369
+ 'perfectionist/sort-union-types': [
370
+ 'error',
371
+ {
372
+ groups: [
373
+ 'conditional', // Conditional types
374
+ 'function', // Function types
375
+ 'import', // Import types
376
+ 'intersection', // Intersection types
377
+ 'keyword', // TypeScript keywords
378
+ 'literal', // Literal types
379
+ 'named', // Named types
380
+ 'object', // Object types
381
+ 'operator', // Operator types
382
+ 'tuple', // Tuple types
383
+ 'union', // Union types
384
+ 'nullish', // null/undefined
385
+ ],
386
+ order: 'asc', // Ascending order
387
+ specialCharacters: 'keep', // Keep special characters
388
+ type: 'alphabetical', // Sort alphabetically
389
+ },
390
+ ],
391
+ },
392
+ });
393
+ }
394
+
395
+ return antfu(
396
+ { ...options, stylistic },
397
+ {
398
+ name: 'eslint/rewrite',
399
+ rules: {
400
+ /**
401
+ * Disable requirement for curly braces
402
+ * Allows single-line if statements without braces
403
+ * @example
404
+ * // Both are allowed:
405
+ * if (foo) bar();
406
+ * if (foo) { bar(); }
407
+ */
408
+ 'antfu/curly': 'off',
409
+
410
+ /**
411
+ * Disable forced newline after if statement
412
+ * Allows more flexible formatting
413
+ * @example
414
+ * // Both are allowed:
415
+ * if (foo) bar();
416
+ * if (foo)
417
+ * bar();
418
+ */
419
+ 'antfu/if-newline': 'off',
420
+
421
+ /**
422
+ * Disable top-level function requirements
423
+ * Allows both named and anonymous functions at top level
424
+ * @example
425
+ * // Both are allowed:
426
+ * function foo() {}
427
+ * export default () => {}
428
+ */
429
+ 'antfu/top-level-function': 'off',
430
+
431
+ /**
432
+ * Warn on console statements
433
+ * Helps identify debugging code that shouldn't be in production
434
+ * @example
435
+ * // ⚠️ Warns:
436
+ * console.log('debug');
437
+ */
438
+ 'no-console': 'warn',
439
+
440
+ /**
441
+ * Disable exhaustive dependencies check for React hooks
442
+ * Allows manual control over hook dependencies
443
+ * @example
444
+ * // Allowed:
445
+ * useEffect(() => {}, [selectedDeps])
446
+ */
447
+ 'react-hooks/exhaustive-deps': 'off',
448
+
449
+ /**
450
+ * Disable lowercase test title requirement
451
+ * Allows more flexible test naming
452
+ * @example
453
+ * // Both are allowed:
454
+ * test('my test')
455
+ * test('My Test')
456
+ */
457
+ 'test/prefer-lowercase-title': 'off',
458
+ },
459
+ },
460
+ ...configs,
461
+ );
462
+ };
package/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import type { Awaitable, ConfigNames, OptionsConfig, TypedFlatConfigItem } from '@antfu/eslint-config';
2
+ import type { Linter } from 'eslint';
3
+ import type { FlatConfigComposer } from 'eslint-flat-config-utils';
4
+
5
+ /**
6
+ * Basic configuration options.
7
+ */
8
+ interface ConfigOptions extends OptionsConfig, TypedFlatConfigItem {
9
+ /** Enables accessibility rules for JSX */
10
+ jsxA11y?: boolean;
11
+ /** Adds support for Next.js */
12
+ next?: boolean;
13
+ /** Sorts rules alphabetically */
14
+ sort?: boolean;
15
+ }
16
+
17
+ /**
18
+ * Types of user configurations.
19
+ */
20
+ type UserConfig = Awaitable<FlatConfigComposer<any, any> | TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config[]>;
21
+
22
+ /**
23
+ * Main configuration function for ESLint.
24
+ */
25
+ type ConfigFunction = (options?: ConfigOptions, ...userConfigs: UserConfig[]) => FlatConfigComposer<TypedFlatConfigItem, ConfigNames>;
26
+
27
+ /**
28
+ * Exported module.
29
+ */
30
+ declare module '@zilero/eslint' {
31
+ export const Eslint: ConfigFunction;
32
+ }
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ const { eslint } = require('./eslint.config.js');
2
+
3
+ module.exports = { eslint };
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@zilero/eslint",
3
+ "icon": "🎯",
4
+ "displayName": "✨ Zilero ESLint Config",
5
+ "description": "🎯 Comprehensive ESLint configuration for React and Node.js projects",
6
+ "license": "MIT",
7
+ "version": "1.0.0",
8
+ "keywords": [
9
+ "eslint",
10
+ "eslint-config",
11
+ "react",
12
+ "node",
13
+ "typescript",
14
+ "javascript",
15
+ "linting",
16
+ "prettier",
17
+ "style-guide",
18
+ "code-quality"
19
+ ],
20
+ "author": {
21
+ "name": "Artemev Alexandr",
22
+ "url": "https://github.com/Zilero232",
23
+ "email": "sasha.artemev.1002@mail.ru"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/Zilero232/dev-config-hub/issues"
27
+ },
28
+ "homepage": "https://github.com/Zilero232/dev-config-hub",
29
+ "repository": {
30
+ "url": "git+https://github.com/Zilero232/dev-config-hub.git"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "index.d.ts",
37
+ "eslint.config.js",
38
+ "index.js"
39
+ ],
40
+ "main": "index.js",
41
+ "peerDependencies": {
42
+ "eslint": "^9.0.0"
43
+ },
44
+ "engines": {
45
+ "node": ">=16.0.0",
46
+ "npm": ">=7.0.0"
47
+ },
48
+ "funding": {
49
+ "type": "github",
50
+ "url": "https://github.com/sponsors/Zilero232"
51
+ },
52
+ "categories": [
53
+ "Formatters",
54
+ "Linters"
55
+ ],
56
+ "contributors": [
57
+ {
58
+ "name": "Artemev Alexandr",
59
+ "url": "https://github.com/Zilero232"
60
+ }
61
+ ],
62
+ "dependencies": {
63
+ "@antfu/eslint-config": "3.12.1",
64
+ "@eslint-react/eslint-plugin": "1.23.1",
65
+ "@next/eslint-plugin-next": "15.1.3",
66
+ "@vue/compiler-sfc": "3.5.13",
67
+ "eslint": "9.17.0",
68
+ "eslint-plugin-jsx-a11y": "6.10.2",
69
+ "eslint-plugin-react": "7.37.3",
70
+ "eslint-plugin-react-hooks": "5.1.0",
71
+ "eslint-plugin-react-refresh": "0.4.16"
72
+ }
73
+ }