@zilero/eslint 1.0.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 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
+ }