js-style-kit 0.6.0 → 0.7.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/README.md +5 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.js +48 -77
- package/dist/index.js.map +1 -1
- package/package.json +36 -33
- package/src/eslint/base/README.md +186 -0
- package/src/eslint/base/config.ts +37 -0
- package/src/eslint/base/rules.ts +444 -0
- package/src/eslint/base/types.ts +20 -0
- package/src/eslint/constants.ts +52 -0
- package/src/eslint/convex/README.md +30 -0
- package/src/eslint/convex/config.ts +34 -0
- package/src/eslint/convex/rules.ts +8 -0
- package/src/eslint/convex/types.ts +8 -0
- package/src/eslint/ignores.ts +31 -0
- package/src/eslint/import/README.md +397 -0
- package/src/eslint/import/config.ts +48 -0
- package/src/eslint/import/rules.ts +81 -0
- package/src/eslint/index.ts +259 -0
- package/src/eslint/jsdoc/README.md +399 -0
- package/src/eslint/jsdoc/config.ts +29 -0
- package/src/eslint/jsdoc/rules.ts +81 -0
- package/src/eslint/jsdoc/types.ts +56 -0
- package/src/eslint/nextjs/config.ts +25 -0
- package/src/eslint/nextjs/rules.ts +25 -0
- package/src/eslint/nextjs/types.ts +27 -0
- package/src/eslint/perfectionist/README.md +454 -0
- package/src/eslint/perfectionist/config.ts +25 -0
- package/src/eslint/perfectionist/rules.ts +39 -0
- package/src/eslint/prefer-arrow-function/config.ts +33 -0
- package/src/eslint/prefer-arrow-function/types.ts +13 -0
- package/src/eslint/process-custom-rules.ts +72 -0
- package/src/eslint/query/README.md +254 -0
- package/src/eslint/query/config.ts +27 -0
- package/src/eslint/query/rules.ts +11 -0
- package/src/eslint/query/types.ts +11 -0
- package/src/eslint/react/README.md +416 -0
- package/src/eslint/react/config.ts +65 -0
- package/src/eslint/react/rules.ts +188 -0
- package/src/eslint/react/types.ts +26 -0
- package/src/eslint/react-refresh/config.ts +28 -0
- package/src/eslint/react-refresh/rules.ts +48 -0
- package/src/eslint/storybook/README.md +424 -0
- package/src/eslint/storybook/config.ts +57 -0
- package/src/eslint/testing/README.md +436 -0
- package/src/eslint/testing/config.ts +90 -0
- package/src/eslint/testing/jest-rules.ts +47 -0
- package/src/eslint/testing/vitest-rules.ts +42 -0
- package/src/eslint/turbo/README.md +380 -0
- package/src/eslint/turbo/config.ts +26 -0
- package/src/eslint/turbo/types.ts +7 -0
- package/src/eslint/types.ts +29 -0
- package/src/eslint/typescript/README.md +229 -0
- package/src/eslint/typescript/config.ts +48 -0
- package/src/eslint/typescript/rules.ts +137 -0
- package/src/eslint/typescript/types.ts +35 -0
- package/src/eslint/unicorn/README.md +497 -0
- package/src/eslint/unicorn/config.ts +36 -0
- package/src/eslint/unicorn/rules.ts +86 -0
- package/src/index.ts +3 -0
- package/src/modules.d.ts +5 -0
- package/src/prettier/README.md +413 -0
- package/src/prettier/index.ts +110 -0
- package/src/utils/is-type.ts +60 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { JsdocRules } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates ESLint rules configuration for JSDoc comments.
|
|
5
|
+
*
|
|
6
|
+
* @param requireJsdoc - Whether to enforce JSDoc comments on functions and classes. Defaults to false.
|
|
7
|
+
* @param typescript - Whether TypeScript is being used in the project. When true, some rules are adjusted to be more TypeScript-friendly. Defaults to true.
|
|
8
|
+
* @returns An object containing ESLint rules configuration for JSDoc validation and formatting.
|
|
9
|
+
*/
|
|
10
|
+
export const jsdocRules = (
|
|
11
|
+
requireJsdoc = false,
|
|
12
|
+
typescript = true,
|
|
13
|
+
): JsdocRules => ({
|
|
14
|
+
"jsdoc/check-access": "warn",
|
|
15
|
+
"jsdoc/check-alignment": "warn",
|
|
16
|
+
"jsdoc/check-param-names": [
|
|
17
|
+
"warn",
|
|
18
|
+
{
|
|
19
|
+
checkDestructured: true,
|
|
20
|
+
enableFixer: true,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
"jsdoc/check-property-names": "warn",
|
|
24
|
+
"jsdoc/check-tag-names": [
|
|
25
|
+
"warn",
|
|
26
|
+
{
|
|
27
|
+
typed: true,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
"jsdoc/check-types": "warn",
|
|
31
|
+
"jsdoc/check-values": "warn",
|
|
32
|
+
"jsdoc/empty-tags": "warn",
|
|
33
|
+
"jsdoc/implements-on-classes": "warn",
|
|
34
|
+
"jsdoc/multiline-blocks": "warn",
|
|
35
|
+
"jsdoc/no-blank-block-descriptions": "off",
|
|
36
|
+
"jsdoc/no-defaults": "warn",
|
|
37
|
+
"jsdoc/no-multi-asterisks": "warn",
|
|
38
|
+
"jsdoc/no-types": typescript ? "warn" : "off",
|
|
39
|
+
"jsdoc/no-undefined-types": typescript ? "off" : "warn",
|
|
40
|
+
"jsdoc/require-asterisk-prefix": "warn",
|
|
41
|
+
"jsdoc/require-description": requireJsdoc ? "warn" : "off",
|
|
42
|
+
"jsdoc/require-jsdoc":
|
|
43
|
+
requireJsdoc ?
|
|
44
|
+
[
|
|
45
|
+
"warn",
|
|
46
|
+
{
|
|
47
|
+
require: {
|
|
48
|
+
ArrowFunctionExpression: true,
|
|
49
|
+
ClassDeclaration: true,
|
|
50
|
+
ClassExpression: true,
|
|
51
|
+
FunctionDeclaration: true,
|
|
52
|
+
FunctionExpression: true,
|
|
53
|
+
MethodDefinition: true,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
]
|
|
57
|
+
: "off",
|
|
58
|
+
"jsdoc/require-param": requireJsdoc ? "warn" : "off",
|
|
59
|
+
"jsdoc/require-param-description": "warn",
|
|
60
|
+
"jsdoc/require-param-name": "warn",
|
|
61
|
+
"jsdoc/require-property": requireJsdoc ? "warn" : "off",
|
|
62
|
+
"jsdoc/require-property-description": "warn",
|
|
63
|
+
"jsdoc/require-property-name": "warn",
|
|
64
|
+
"jsdoc/require-returns": requireJsdoc ? "warn" : "off",
|
|
65
|
+
"jsdoc/require-returns-check": "warn",
|
|
66
|
+
"jsdoc/require-returns-description": "warn",
|
|
67
|
+
"jsdoc/require-yields": "warn",
|
|
68
|
+
"jsdoc/require-yields-check": "warn",
|
|
69
|
+
"jsdoc/tag-lines": [
|
|
70
|
+
"warn",
|
|
71
|
+
"never",
|
|
72
|
+
{
|
|
73
|
+
startLines: 1, // Allow 1 line between description and first tag
|
|
74
|
+
tags: {
|
|
75
|
+
param: { lines: "never" }, // Enforce no lines between param tags
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
"jsdoc/text-escaping": "off",
|
|
80
|
+
"jsdoc/valid-types": "warn",
|
|
81
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { EslintRuleConfig } from "../types.js";
|
|
2
|
+
|
|
3
|
+
export type JsdocRules = Record<`jsdoc/${string}`, EslintRuleConfig> & {
|
|
4
|
+
"jsdoc/check-param-names": EslintRuleConfig<{
|
|
5
|
+
allowExtraTrailingParamDocs?: boolean;
|
|
6
|
+
checkDestructured?: boolean;
|
|
7
|
+
checkRestProperty?: boolean;
|
|
8
|
+
checkTypesPattern?: string;
|
|
9
|
+
disableExtraPropertyReporting?: boolean;
|
|
10
|
+
disableMissingParamChecks?: boolean;
|
|
11
|
+
enableFixer?: boolean;
|
|
12
|
+
useDefaultObjectProperties?: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
"jsdoc/require-jsdoc": EslintRuleConfig<{
|
|
15
|
+
checkConstructors?: boolean;
|
|
16
|
+
checkGetters?: boolean;
|
|
17
|
+
checkSetters?: boolean;
|
|
18
|
+
contexts?: (object | string)[];
|
|
19
|
+
enableFixer?: boolean;
|
|
20
|
+
exemptEmptyConstructors?: boolean;
|
|
21
|
+
fixerMessage?: string;
|
|
22
|
+
minLineCount?: number | undefined;
|
|
23
|
+
publicOnly?:
|
|
24
|
+
| boolean
|
|
25
|
+
| {
|
|
26
|
+
ancestorsOnly?: boolean;
|
|
27
|
+
cjs?: boolean;
|
|
28
|
+
esm?: boolean;
|
|
29
|
+
window?: boolean;
|
|
30
|
+
};
|
|
31
|
+
require?: {
|
|
32
|
+
ArrowFunctionExpression?: boolean;
|
|
33
|
+
ClassDeclaration?: boolean;
|
|
34
|
+
ClassExpression?: boolean;
|
|
35
|
+
FunctionDeclaration?: boolean;
|
|
36
|
+
FunctionExpression?: boolean;
|
|
37
|
+
MethodDefinition?: boolean;
|
|
38
|
+
};
|
|
39
|
+
}>;
|
|
40
|
+
"jsdoc/tag-lines": EslintRuleConfig<
|
|
41
|
+
"always" | "any" | "never",
|
|
42
|
+
{
|
|
43
|
+
applyToEndTag?: boolean;
|
|
44
|
+
count?: number;
|
|
45
|
+
endLines?: null | number;
|
|
46
|
+
startLines?: null | number;
|
|
47
|
+
tags?: Record<
|
|
48
|
+
string,
|
|
49
|
+
{
|
|
50
|
+
count?: number;
|
|
51
|
+
lines?: "always" | "any" | "never";
|
|
52
|
+
}
|
|
53
|
+
>;
|
|
54
|
+
}
|
|
55
|
+
>;
|
|
56
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import nextjs from "eslint-plugin-nextjs";
|
|
2
|
+
|
|
3
|
+
import type { EslintConfigObject, EslintRuleConfig } from "../types.js";
|
|
4
|
+
|
|
5
|
+
import { configNames } from "../constants.js";
|
|
6
|
+
import { nextjsRules } from "./rules.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates an ESLint configuration for Next.js.
|
|
10
|
+
*
|
|
11
|
+
* @param customRules - Optional object containing custom rules to override or add to the Next.js configuration.
|
|
12
|
+
* @returns ESLint configuration object for Next.js
|
|
13
|
+
*/
|
|
14
|
+
export const nextjsConfig = (
|
|
15
|
+
customRules?: Record<string, EslintRuleConfig>,
|
|
16
|
+
): EslintConfigObject => ({
|
|
17
|
+
name: configNames.nextjs,
|
|
18
|
+
plugins: {
|
|
19
|
+
nextjs,
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
...nextjsRules,
|
|
23
|
+
...(customRules ?? {}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NextjsRules } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export const nextjsRules: NextjsRules = {
|
|
4
|
+
"nextjs/google-font-display": "warn",
|
|
5
|
+
"nextjs/google-font-preconnect": "warn",
|
|
6
|
+
"nextjs/inline-script-id": "warn",
|
|
7
|
+
"nextjs/next-script-for-ga": "warn",
|
|
8
|
+
"nextjs/no-assign-module-variable": "warn",
|
|
9
|
+
"nextjs/no-async-client-component": "warn",
|
|
10
|
+
"nextjs/no-before-interactive-script-outside-document": "warn",
|
|
11
|
+
"nextjs/no-css-tags": "warn",
|
|
12
|
+
"nextjs/no-document-import-in-page": "warn",
|
|
13
|
+
"nextjs/no-duplicate-head": "warn",
|
|
14
|
+
"nextjs/no-head-element": "warn",
|
|
15
|
+
"nextjs/no-head-import-in-document": "warn",
|
|
16
|
+
"nextjs/no-html-link-for-pages": "warn",
|
|
17
|
+
"nextjs/no-img-element": "warn",
|
|
18
|
+
"nextjs/no-page-custom-font": "warn",
|
|
19
|
+
"nextjs/no-script-component-in-head": "warn",
|
|
20
|
+
"nextjs/no-styled-jsx-in-document": "warn",
|
|
21
|
+
"nextjs/no-sync-scripts": "warn",
|
|
22
|
+
"nextjs/no-title-in-document-head": "warn",
|
|
23
|
+
"nextjs/no-typos": "warn",
|
|
24
|
+
"nextjs/no-unwanted-polyfillio": "warn",
|
|
25
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EslintRuleConfig } from "../types.js";
|
|
2
|
+
|
|
3
|
+
// This fixes an index signature issue
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
5
|
+
export type NextjsRules = {
|
|
6
|
+
"nextjs/google-font-display": EslintRuleConfig;
|
|
7
|
+
"nextjs/google-font-preconnect": EslintRuleConfig;
|
|
8
|
+
"nextjs/inline-script-id": EslintRuleConfig;
|
|
9
|
+
"nextjs/next-script-for-ga": EslintRuleConfig;
|
|
10
|
+
"nextjs/no-assign-module-variable": EslintRuleConfig;
|
|
11
|
+
"nextjs/no-async-client-component": EslintRuleConfig;
|
|
12
|
+
"nextjs/no-before-interactive-script-outside-document": EslintRuleConfig;
|
|
13
|
+
"nextjs/no-css-tags": EslintRuleConfig;
|
|
14
|
+
"nextjs/no-document-import-in-page": EslintRuleConfig;
|
|
15
|
+
"nextjs/no-duplicate-head": EslintRuleConfig;
|
|
16
|
+
"nextjs/no-head-element": EslintRuleConfig;
|
|
17
|
+
"nextjs/no-head-import-in-document": EslintRuleConfig;
|
|
18
|
+
"nextjs/no-html-link-for-pages": EslintRuleConfig;
|
|
19
|
+
"nextjs/no-img-element": EslintRuleConfig;
|
|
20
|
+
"nextjs/no-page-custom-font": EslintRuleConfig;
|
|
21
|
+
"nextjs/no-script-component-in-head": EslintRuleConfig;
|
|
22
|
+
"nextjs/no-styled-jsx-in-document": EslintRuleConfig;
|
|
23
|
+
"nextjs/no-sync-scripts": EslintRuleConfig;
|
|
24
|
+
"nextjs/no-title-in-document-head": EslintRuleConfig;
|
|
25
|
+
"nextjs/no-typos": EslintRuleConfig;
|
|
26
|
+
"nextjs/no-unwanted-polyfillio": EslintRuleConfig;
|
|
27
|
+
};
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Perfectionist Configuration
|
|
2
|
+
|
|
3
|
+
Automatic code organization through intelligent sorting of imports, objects, types, and more with `eslint-plugin-perfectionist`.
|
|
4
|
+
|
|
5
|
+
[← Back to main README](../../../README.md)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Perfectionist configuration is **enabled by default** and provides:
|
|
10
|
+
|
|
11
|
+
- Automatic sorting for imports, exports, and named imports
|
|
12
|
+
- Object key and property sorting
|
|
13
|
+
- TypeScript type and interface organization
|
|
14
|
+
- Consistent code structure across your codebase
|
|
15
|
+
- Natural alphabetical ordering (smart number handling)
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { eslintConfig } from "js-style-kit";
|
|
21
|
+
|
|
22
|
+
export default eslintConfig({
|
|
23
|
+
sorting: true, // Enabled by default
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## What Gets Sorted
|
|
28
|
+
|
|
29
|
+
Perfectionist automatically organizes:
|
|
30
|
+
|
|
31
|
+
- Import statements
|
|
32
|
+
- Named imports and exports
|
|
33
|
+
- Object literals and properties
|
|
34
|
+
- TypeScript interfaces and types
|
|
35
|
+
- Enums and union types
|
|
36
|
+
- JSX props
|
|
37
|
+
- Classes and decorators
|
|
38
|
+
- Array includes, Maps, and Sets
|
|
39
|
+
|
|
40
|
+
## Sorting Algorithm
|
|
41
|
+
|
|
42
|
+
All sorting uses **natural ascending order** by default:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
// Natural sort understands numbers
|
|
46
|
+
["item1", "item2", "item10", "item20"];
|
|
47
|
+
// Not: ["item1", "item10", "item2", "item20"]
|
|
48
|
+
|
|
49
|
+
// Case-insensitive alphabetical
|
|
50
|
+
["Apple", "banana", "Cherry"];
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Key Features
|
|
54
|
+
|
|
55
|
+
### Import Sorting
|
|
56
|
+
|
|
57
|
+
Automatically organizes imports for better readability:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// ✅ After auto-fix - properly sorted
|
|
61
|
+
import { useEffect, useState } from "react";
|
|
62
|
+
import { format, parse } from "date-fns";
|
|
63
|
+
|
|
64
|
+
import { Button } from "@/components/Button";
|
|
65
|
+
import { config } from "@/config";
|
|
66
|
+
|
|
67
|
+
import { apiClient } from "./api";
|
|
68
|
+
import { formatDate } from "./utils";
|
|
69
|
+
|
|
70
|
+
// ❌ Before - unsorted
|
|
71
|
+
import { useState, useEffect } from "react";
|
|
72
|
+
import { formatDate } from "./utils";
|
|
73
|
+
import { Button } from "@/components/Button";
|
|
74
|
+
import { parse, format } from "date-fns";
|
|
75
|
+
import { apiClient } from "./api";
|
|
76
|
+
import { config } from "@/config";
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Rules:**
|
|
80
|
+
|
|
81
|
+
- `perfectionist/sort-imports` - Sorts import statements
|
|
82
|
+
- `perfectionist/sort-named-imports` - Sorts named imports within braces
|
|
83
|
+
- `perfectionist/sort-named-exports` - Sorts named exports
|
|
84
|
+
- `perfectionist/sort-exports` - Sorts export statements
|
|
85
|
+
|
|
86
|
+
### Object Sorting
|
|
87
|
+
|
|
88
|
+
Maintains consistent object key order:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// ✅ Good - sorted keys
|
|
92
|
+
const user = {
|
|
93
|
+
age: 30,
|
|
94
|
+
email: "user@example.com",
|
|
95
|
+
id: "123",
|
|
96
|
+
name: "Alice",
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// ❌ Bad - unsorted keys
|
|
100
|
+
const user = {
|
|
101
|
+
name: "Alice",
|
|
102
|
+
id: "123",
|
|
103
|
+
email: "user@example.com",
|
|
104
|
+
age: 30,
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Rules:**
|
|
109
|
+
|
|
110
|
+
- `perfectionist/sort-objects` - Sorts object literal keys
|
|
111
|
+
|
|
112
|
+
### TypeScript Types
|
|
113
|
+
|
|
114
|
+
Organizes TypeScript definitions:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// ✅ Good - sorted interface properties
|
|
118
|
+
interface User {
|
|
119
|
+
age: number;
|
|
120
|
+
email: string;
|
|
121
|
+
id: string;
|
|
122
|
+
name: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ✅ Good - sorted union types
|
|
126
|
+
type Status = "active" | "inactive" | "pending";
|
|
127
|
+
|
|
128
|
+
// ✅ Good - sorted intersection types
|
|
129
|
+
type Combined = Base & Extra & Middle;
|
|
130
|
+
|
|
131
|
+
// ❌ Bad - unsorted
|
|
132
|
+
interface User {
|
|
133
|
+
name: string;
|
|
134
|
+
id: string;
|
|
135
|
+
email: string;
|
|
136
|
+
age: number;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Rules:**
|
|
141
|
+
|
|
142
|
+
- `perfectionist/sort-interfaces` - Sorts interface properties
|
|
143
|
+
- `perfectionist/sort-object-types` - Sorts type object properties
|
|
144
|
+
- `perfectionist/sort-union-types` - Sorts union type members
|
|
145
|
+
- `perfectionist/sort-intersection-types` - Sorts intersection type members
|
|
146
|
+
- `perfectionist/sort-enums` - Sorts enum members
|
|
147
|
+
|
|
148
|
+
### JSX Props
|
|
149
|
+
|
|
150
|
+
Maintains consistent prop order:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
// ✅ Good - sorted props
|
|
154
|
+
<Button
|
|
155
|
+
className="btn"
|
|
156
|
+
disabled={false}
|
|
157
|
+
onClick={handleClick}
|
|
158
|
+
type="submit"
|
|
159
|
+
>
|
|
160
|
+
Submit
|
|
161
|
+
</Button>
|
|
162
|
+
|
|
163
|
+
// ❌ Bad - unsorted props
|
|
164
|
+
<Button
|
|
165
|
+
onClick={handleClick}
|
|
166
|
+
type="submit"
|
|
167
|
+
className="btn"
|
|
168
|
+
disabled={false}
|
|
169
|
+
>
|
|
170
|
+
Submit
|
|
171
|
+
</Button>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Rules:**
|
|
175
|
+
|
|
176
|
+
- `perfectionist/sort-jsx-props` - Sorts JSX element props
|
|
177
|
+
|
|
178
|
+
### Classes
|
|
179
|
+
|
|
180
|
+
Organizes class members and decorators:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// ✅ Good - sorted members
|
|
184
|
+
class UserService {
|
|
185
|
+
private cache: Map<string, User>;
|
|
186
|
+
private logger: Logger;
|
|
187
|
+
|
|
188
|
+
constructor(logger: Logger) {
|
|
189
|
+
this.logger = logger;
|
|
190
|
+
this.cache = new Map();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
getUser(id: string): User {
|
|
194
|
+
/* ... */
|
|
195
|
+
}
|
|
196
|
+
saveUser(user: User): void {
|
|
197
|
+
/* ... */
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ✅ Good - sorted decorators
|
|
202
|
+
@Component()
|
|
203
|
+
@Injectable()
|
|
204
|
+
@Module()
|
|
205
|
+
class MyClass {}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Rules:**
|
|
209
|
+
|
|
210
|
+
- `perfectionist/sort-classes` - Sorts class members
|
|
211
|
+
- `perfectionist/sort-decorators` - Sorts decorators
|
|
212
|
+
|
|
213
|
+
### Other Collections
|
|
214
|
+
|
|
215
|
+
Sorts various other structures:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
// ✅ Good - sorted array includes
|
|
219
|
+
const colors = ["blue", "green", "red"];
|
|
220
|
+
|
|
221
|
+
// ✅ Good - sorted Map entries
|
|
222
|
+
const map = new Map([
|
|
223
|
+
["apple", 1],
|
|
224
|
+
["banana", 2],
|
|
225
|
+
["cherry", 3],
|
|
226
|
+
]);
|
|
227
|
+
|
|
228
|
+
// ✅ Good - sorted Set values
|
|
229
|
+
const set = new Set(["a", "b", "c"]);
|
|
230
|
+
|
|
231
|
+
// ✅ Good - sorted variable declarations
|
|
232
|
+
const a = 1,
|
|
233
|
+
b = 2,
|
|
234
|
+
c = 3;
|
|
235
|
+
|
|
236
|
+
// ✅ Good - sorted switch cases
|
|
237
|
+
switch (value) {
|
|
238
|
+
case "a":
|
|
239
|
+
return 1;
|
|
240
|
+
case "b":
|
|
241
|
+
return 2;
|
|
242
|
+
case "c":
|
|
243
|
+
return 3;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Rules:**
|
|
248
|
+
|
|
249
|
+
- `perfectionist/sort-array-includes` - Sorts array include calls
|
|
250
|
+
- `perfectionist/sort-maps` - Sorts Map constructor entries
|
|
251
|
+
- `perfectionist/sort-sets` - Sorts Set constructor values
|
|
252
|
+
- `perfectionist/sort-variable-declarations` - Sorts variable declarations
|
|
253
|
+
- `perfectionist/sort-switch-case` - Sorts switch case statements
|
|
254
|
+
- `perfectionist/sort-heritage-clauses` - Sorts class extends/implements
|
|
255
|
+
|
|
256
|
+
## Complete Example
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
// ✅ Fully sorted code with Perfectionist
|
|
260
|
+
import type { Config, User } from "./types";
|
|
261
|
+
|
|
262
|
+
import { format, parse } from "date-fns";
|
|
263
|
+
import { useEffect, useState } from "react";
|
|
264
|
+
|
|
265
|
+
import { apiClient } from "./api";
|
|
266
|
+
|
|
267
|
+
interface UserProfile {
|
|
268
|
+
age: number;
|
|
269
|
+
avatar?: string;
|
|
270
|
+
email: string;
|
|
271
|
+
id: string;
|
|
272
|
+
name: string;
|
|
273
|
+
role: "admin" | "user";
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const defaultConfig: Config = {
|
|
277
|
+
apiUrl: "https://api.example.com",
|
|
278
|
+
debug: false,
|
|
279
|
+
timeout: 5000,
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const createUser = (data: User): UserProfile => {
|
|
283
|
+
return {
|
|
284
|
+
age: data.age,
|
|
285
|
+
email: data.email,
|
|
286
|
+
id: data.id,
|
|
287
|
+
name: data.name,
|
|
288
|
+
role: data.role,
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export { apiClient, defaultConfig };
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Module Sorting
|
|
296
|
+
|
|
297
|
+
Module-level sorting is **disabled by default** as it can be disruptive:
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
// perfectionist/sort-modules is "off"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
This prevents the plugin from reordering top-level statements like:
|
|
304
|
+
|
|
305
|
+
- Function declarations
|
|
306
|
+
- Class declarations
|
|
307
|
+
- Variable declarations
|
|
308
|
+
- Export statements
|
|
309
|
+
|
|
310
|
+
If you want to enable module sorting:
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
export default eslintConfig({
|
|
314
|
+
perfectionist: true,
|
|
315
|
+
rules: {
|
|
316
|
+
"perfectionist/sort-modules": "warn",
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Customization
|
|
322
|
+
|
|
323
|
+
### Disable Specific Sorting
|
|
324
|
+
|
|
325
|
+
```js
|
|
326
|
+
export default eslintConfig({
|
|
327
|
+
perfectionist: true,
|
|
328
|
+
rules: {
|
|
329
|
+
// Disable JSX prop sorting
|
|
330
|
+
"perfectionist/sort-jsx-props": "off",
|
|
331
|
+
|
|
332
|
+
// Disable object sorting
|
|
333
|
+
"perfectionist/sort-objects": "off",
|
|
334
|
+
|
|
335
|
+
// Enable module sorting
|
|
336
|
+
"perfectionist/sort-modules": "warn",
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### File-Specific Overrides
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
export default eslintConfig({
|
|
345
|
+
perfectionist: true,
|
|
346
|
+
overrides: [
|
|
347
|
+
{
|
|
348
|
+
files: ["**/*.config.ts"],
|
|
349
|
+
rules: {
|
|
350
|
+
// Don't sort objects in config files
|
|
351
|
+
"perfectionist/sort-objects": "off",
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
],
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Benefits
|
|
359
|
+
|
|
360
|
+
### Consistency
|
|
361
|
+
|
|
362
|
+
- Same structure across all files
|
|
363
|
+
- Reduces diff noise in code reviews
|
|
364
|
+
- Easier to find properties and imports
|
|
365
|
+
|
|
366
|
+
### Maintainability
|
|
367
|
+
|
|
368
|
+
- Clear organization patterns
|
|
369
|
+
- Prevents merge conflicts from ordering
|
|
370
|
+
- Auto-fixes maintain order
|
|
371
|
+
|
|
372
|
+
### Readability
|
|
373
|
+
|
|
374
|
+
- Natural alphabetical order is easy to scan
|
|
375
|
+
- Grouped related items stay together
|
|
376
|
+
- Predictable structure
|
|
377
|
+
|
|
378
|
+
## Common Patterns
|
|
379
|
+
|
|
380
|
+
### React Component
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import type { FC, ReactNode } from "react";
|
|
384
|
+
|
|
385
|
+
import { useCallback, useEffect, useState } from "react";
|
|
386
|
+
|
|
387
|
+
interface ButtonProps {
|
|
388
|
+
children: ReactNode;
|
|
389
|
+
className?: string;
|
|
390
|
+
disabled?: boolean;
|
|
391
|
+
onClick?: () => void;
|
|
392
|
+
type?: "button" | "submit";
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export const Button: FC<ButtonProps> = ({
|
|
396
|
+
children,
|
|
397
|
+
className,
|
|
398
|
+
disabled = false,
|
|
399
|
+
onClick,
|
|
400
|
+
type = "button",
|
|
401
|
+
}) => {
|
|
402
|
+
return (
|
|
403
|
+
<button
|
|
404
|
+
className={className}
|
|
405
|
+
disabled={disabled}
|
|
406
|
+
onClick={onClick}
|
|
407
|
+
type={type}
|
|
408
|
+
>
|
|
409
|
+
{children}
|
|
410
|
+
</button>
|
|
411
|
+
);
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### API Client
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
import type { RequestConfig, Response } from "./types";
|
|
419
|
+
|
|
420
|
+
import { auth } from "./auth";
|
|
421
|
+
import { config } from "./config";
|
|
422
|
+
import { logger } from "./logger";
|
|
423
|
+
|
|
424
|
+
export class ApiClient {
|
|
425
|
+
private baseUrl: string;
|
|
426
|
+
private headers: Record<string, string>;
|
|
427
|
+
private timeout: number;
|
|
428
|
+
|
|
429
|
+
async delete(url: string): Promise<Response> {
|
|
430
|
+
/* ... */
|
|
431
|
+
}
|
|
432
|
+
async get(url: string): Promise<Response> {
|
|
433
|
+
/* ... */
|
|
434
|
+
}
|
|
435
|
+
async post(url: string, data: unknown): Promise<Response> {
|
|
436
|
+
/* ... */
|
|
437
|
+
}
|
|
438
|
+
async put(url: string, data: unknown): Promise<Response> {
|
|
439
|
+
/* ... */
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Related Configurations
|
|
445
|
+
|
|
446
|
+
- [Import](../import/README.md) - Import validation (works alongside Perfectionist)
|
|
447
|
+
- [TypeScript](../typescript/README.md) - TypeScript type checking
|
|
448
|
+
- [Base](../base/README.md) - Base ESLint rules
|
|
449
|
+
|
|
450
|
+
## Learn More
|
|
451
|
+
|
|
452
|
+
- [eslint-plugin-perfectionist](https://github.com/azat-io/eslint-plugin-perfectionist)
|
|
453
|
+
- [Natural Sort Algorithm](https://en.wikipedia.org/wiki/Natural_sort_order)
|
|
454
|
+
- [Main README](../../../README.md)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import perfectionist from "eslint-plugin-perfectionist";
|
|
2
|
+
|
|
3
|
+
import type { EslintConfigObject, EslintRuleConfig } from "../types.js";
|
|
4
|
+
|
|
5
|
+
import { configNames } from "../constants.js";
|
|
6
|
+
import { perfectionistRules } from "./rules.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates an ESLint configuration for Perfectionist.
|
|
10
|
+
*
|
|
11
|
+
* @param customRules - Optional object containing custom rules to override or add to the Perfectionist configuration.
|
|
12
|
+
* @returns ESLint configuration object for Perfectionist
|
|
13
|
+
*/
|
|
14
|
+
export const perfectionistConfig = (
|
|
15
|
+
customRules?: Record<string, EslintRuleConfig>,
|
|
16
|
+
): EslintConfigObject => ({
|
|
17
|
+
name: configNames.perfectionist,
|
|
18
|
+
plugins: {
|
|
19
|
+
perfectionist,
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
...perfectionistRules,
|
|
23
|
+
...(customRules ?? {}),
|
|
24
|
+
},
|
|
25
|
+
});
|