@caspeco/eslint-config-react 5.0.0-beta.1 → 5.0.1-beta.1
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 +106 -104
- package/bin/README.md +40 -40
- package/bin/caspeco-react-migrate-v5.js +202 -189
- package/package.json +2 -2
- package/src/index.js +74 -74
- package/src/plugins/caspeco-react.js +45 -45
package/README.md
CHANGED
|
@@ -1,104 +1,106 @@
|
|
|
1
|
-
# @caspeco/eslint-config-react
|
|
2
|
-
|
|
3
|
-
Caspeco ESLint configuration for React + TypeScript projects.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install --save-dev @caspeco/eslint-config-react
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
### Migrating from v4.x
|
|
12
|
-
|
|
13
|
-
If you're upgrading from `@caspeco/eslint-config` v4.x, use the automated migration script:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Preview changes
|
|
17
|
-
npx caspeco-react-migrate-v5 src/ --dry-run
|
|
18
|
-
|
|
19
|
-
# Apply changes
|
|
20
|
-
npx caspeco-react-migrate-v5 src/
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
This updates the plugin namespace from `caspeco/` to `caspeco-react/`. See the [Migration Guide](../../MIGRATION.md) for details.
|
|
24
|
-
|
|
25
|
-
## Usage
|
|
26
|
-
|
|
27
|
-
Create an `eslint.config.js` file in your project root:
|
|
28
|
-
|
|
29
|
-
```js
|
|
30
|
-
import config from "@caspeco/eslint-config-react";
|
|
31
|
-
|
|
32
|
-
export default [{ ignores: ["dist/**/*", "build/**/*"] }, ...config];
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## What's Included
|
|
36
|
-
|
|
37
|
-
This configuration includes everything from our TypeScript config plus React-specific rules:
|
|
38
|
-
|
|
39
|
-
### Base TypeScript Configuration
|
|
40
|
-
|
|
41
|
-
- **TypeScript ESLint** - recommended-type-checked config
|
|
42
|
-
- **No Barrel Files** - Prevents barrel file usage
|
|
43
|
-
- **File Naming Conventions** - Enforces kebab-case for files and folders
|
|
44
|
-
- **Prettier Integration** - Compatible with Prettier formatting
|
|
45
|
-
|
|
46
|
-
### React-Specific Configuration
|
|
47
|
-
|
|
48
|
-
- **React Plugin** - Core React linting rules
|
|
49
|
-
- **React Hooks** - Enforces rules of hooks
|
|
50
|
-
- **React Refresh** - Fast Refresh support for Vite/development
|
|
51
|
-
- **Caspeco Plugin** - Custom rules for Caspeco projects (Chakra UI import restrictions)
|
|
52
|
-
|
|
53
|
-
## Peer Dependencies
|
|
54
|
-
|
|
55
|
-
This package requires the following peer dependencies (automatically installed by npm 7+):
|
|
56
|
-
|
|
57
|
-
- `eslint`
|
|
58
|
-
- `eslint-plugin-react`
|
|
59
|
-
- `eslint-plugin-react-hooks`
|
|
60
|
-
- `eslint-plugin-react-refresh`
|
|
61
|
-
- `globals`
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- `
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
# @caspeco/eslint-config-react
|
|
2
|
+
|
|
3
|
+
Caspeco ESLint configuration for React + TypeScript projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev @caspeco/eslint-config-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Migrating from v4.x
|
|
12
|
+
|
|
13
|
+
If you're upgrading from `@caspeco/eslint-config` v4.x, use the automated migration script:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Preview changes
|
|
17
|
+
npx caspeco-react-migrate-v5 src/ --dry-run
|
|
18
|
+
|
|
19
|
+
# Apply changes
|
|
20
|
+
npx caspeco-react-migrate-v5 src/
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This updates the plugin namespace from `caspeco/` to `caspeco-react/`. See the [Migration Guide](../../MIGRATION.md) for details.
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Create an `eslint.config.js` file in your project root:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import config from "@caspeco/eslint-config-react";
|
|
31
|
+
|
|
32
|
+
export default [{ ignores: ["dist/**/*", "build/**/*"] }, ...config];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What's Included
|
|
36
|
+
|
|
37
|
+
This configuration includes everything from our TypeScript config plus React-specific rules:
|
|
38
|
+
|
|
39
|
+
### Base TypeScript Configuration
|
|
40
|
+
|
|
41
|
+
- **TypeScript ESLint** - recommended-type-checked config
|
|
42
|
+
- **No Barrel Files** - Prevents barrel file usage
|
|
43
|
+
- **File Naming Conventions** - Enforces kebab-case for files and folders
|
|
44
|
+
- **Prettier Integration** - Compatible with Prettier formatting
|
|
45
|
+
|
|
46
|
+
### React-Specific Configuration
|
|
47
|
+
|
|
48
|
+
- **React Plugin** - Core React linting rules
|
|
49
|
+
- **React Hooks** - Enforces rules of hooks
|
|
50
|
+
- **React Refresh** - Fast Refresh support for Vite/development
|
|
51
|
+
- **Caspeco Plugin** - Custom rules for Caspeco projects (Chakra UI import restrictions)
|
|
52
|
+
|
|
53
|
+
## Peer Dependencies
|
|
54
|
+
|
|
55
|
+
This package requires the following peer dependencies (automatically installed by npm 7+):
|
|
56
|
+
|
|
57
|
+
- `eslint`
|
|
58
|
+
- `eslint-plugin-react`
|
|
59
|
+
- `eslint-plugin-react-hooks`
|
|
60
|
+
- `eslint-plugin-react-refresh`
|
|
61
|
+
- `globals`
|
|
62
|
+
|
|
63
|
+
See [package.json](./package.json) for specific version requirements.
|
|
64
|
+
|
|
65
|
+
**Note:** Additional TypeScript-related peer dependencies are inherited from `@caspeco/eslint-config-ts` (installed automatically as a regular dependency).
|
|
66
|
+
|
|
67
|
+
## Plugins
|
|
68
|
+
|
|
69
|
+
### eslint-plugin-react
|
|
70
|
+
|
|
71
|
+
[eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react)
|
|
72
|
+
|
|
73
|
+
Core React linting rules with the following customizations:
|
|
74
|
+
|
|
75
|
+
- `react-in-jsx-scope`: off (not needed in modern React)
|
|
76
|
+
- `prop-types`: off (using TypeScript instead)
|
|
77
|
+
- `display-name`: off
|
|
78
|
+
|
|
79
|
+
### eslint-plugin-react-hooks
|
|
80
|
+
|
|
81
|
+
[eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)
|
|
82
|
+
|
|
83
|
+
Enforces:
|
|
84
|
+
|
|
85
|
+
- Rules of Hooks (error)
|
|
86
|
+
- Exhaustive dependencies (warning)
|
|
87
|
+
|
|
88
|
+
### eslint-plugin-react-refresh
|
|
89
|
+
|
|
90
|
+
[eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh)
|
|
91
|
+
|
|
92
|
+
Ensures components are compatible with Fast Refresh in development.
|
|
93
|
+
|
|
94
|
+
### caspeco-react-plugin
|
|
95
|
+
|
|
96
|
+
Custom React-specific plugin with Caspeco rules:
|
|
97
|
+
|
|
98
|
+
- Discourages direct imports from `@chakra-ui/react` (use themed components instead)
|
|
99
|
+
|
|
100
|
+
## Relationship with @caspeco/eslint-config-ts
|
|
101
|
+
|
|
102
|
+
This package depends on and extends `@caspeco/eslint-config-ts`, which is automatically installed as a dependency. This ensures React projects always use the same TypeScript rules without drift. If you're building a React project, use this package. For vanilla TypeScript projects, use `@caspeco/eslint-config-ts`.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
package/bin/README.md
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
# Migration Scripts
|
|
2
|
-
|
|
3
|
-
## caspeco-react-migrate-v5
|
|
4
|
-
|
|
5
|
-
Automated migration script for updating from `@caspeco/eslint-config` v4.x to `@caspeco/eslint-config-react` v5.x.
|
|
6
|
-
|
|
7
|
-
### Usage
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# Preview changes (dry run)
|
|
11
|
-
npx caspeco-react-migrate-v5 src/ --dry-run
|
|
12
|
-
|
|
13
|
-
# Apply changes
|
|
14
|
-
npx caspeco-react-migrate-v5 src/
|
|
15
|
-
|
|
16
|
-
# Scan entire project
|
|
17
|
-
npx caspeco-react-migrate-v5 .
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### What it does
|
|
21
|
-
|
|
22
|
-
- Updates rule names: `caspeco/discourage-chakra-import` → `caspeco-react/discourage-chakra-import`
|
|
23
|
-
- Fixes ESLint disable comments
|
|
24
|
-
- Updates config files
|
|
25
|
-
- Processes `.js`, `.jsx`, `.ts`, `.tsx`, `.json`, and `.md` files
|
|
26
|
-
|
|
27
|
-
### Files processed
|
|
28
|
-
|
|
29
|
-
The script automatically:
|
|
30
|
-
|
|
31
|
-
- Skips `node_modules`, `.git`, `dist`, `build`, and `coverage` directories
|
|
32
|
-
- Recursively processes all supported file types
|
|
33
|
-
- Shows a summary of changes made
|
|
34
|
-
|
|
35
|
-
### Options
|
|
36
|
-
|
|
37
|
-
- `--dry-run`: Preview changes without modifying files
|
|
38
|
-
- First argument: Path to scan (defaults to current directory)
|
|
39
|
-
|
|
40
|
-
See the [Migration Guide](../../../MIGRATION.md) for full migration instructions.
|
|
1
|
+
# Migration Scripts
|
|
2
|
+
|
|
3
|
+
## caspeco-react-migrate-v5
|
|
4
|
+
|
|
5
|
+
Automated migration script for updating from `@caspeco/eslint-config` v4.x to `@caspeco/eslint-config-react` v5.x.
|
|
6
|
+
|
|
7
|
+
### Usage
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Preview changes (dry run)
|
|
11
|
+
npx caspeco-react-migrate-v5 src/ --dry-run
|
|
12
|
+
|
|
13
|
+
# Apply changes
|
|
14
|
+
npx caspeco-react-migrate-v5 src/
|
|
15
|
+
|
|
16
|
+
# Scan entire project
|
|
17
|
+
npx caspeco-react-migrate-v5 .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### What it does
|
|
21
|
+
|
|
22
|
+
- Updates rule names: `caspeco/discourage-chakra-import` → `caspeco-react/discourage-chakra-import`
|
|
23
|
+
- Fixes ESLint disable comments
|
|
24
|
+
- Updates config files
|
|
25
|
+
- Processes `.js`, `.jsx`, `.ts`, `.tsx`, `.json`, and `.md` files
|
|
26
|
+
|
|
27
|
+
### Files processed
|
|
28
|
+
|
|
29
|
+
The script automatically:
|
|
30
|
+
|
|
31
|
+
- Skips `node_modules`, `.git`, `dist`, `build`, and `coverage` directories
|
|
32
|
+
- Recursively processes all supported file types
|
|
33
|
+
- Shows a summary of changes made
|
|
34
|
+
|
|
35
|
+
### Options
|
|
36
|
+
|
|
37
|
+
- `--dry-run`: Preview changes without modifying files
|
|
38
|
+
- First argument: Path to scan (defaults to current directory)
|
|
39
|
+
|
|
40
|
+
See the [Migration Guide](../../../MIGRATION.md) for full migration instructions.
|
|
@@ -1,190 +1,203 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Migration script for v4.x to v5.x
|
|
5
|
-
*
|
|
6
|
-
* This script updates:
|
|
7
|
-
* - Package imports: @caspeco/eslint-config → @caspeco/eslint-config-react
|
|
8
|
-
* - Named imports: { reactConfig } → default import
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* npx caspeco-react-migrate-v5
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
console.log(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
console.log(`
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration script for v4.x to v5.x
|
|
5
|
+
*
|
|
6
|
+
* This script updates:
|
|
7
|
+
* - Package imports: @caspeco/eslint-config → @caspeco/eslint-config-react
|
|
8
|
+
* - Named imports: { reactConfig } → default import reactConfig
|
|
9
|
+
* - Rule names: caspeco/discourage-chakra-import → caspeco-react/discourage-chakra-import
|
|
10
|
+
* - ESLint disable comments
|
|
11
|
+
*
|
|
12
|
+
* Handles both:
|
|
13
|
+
* - Full migration: import { reactConfig } from "@caspeco/eslint-config"
|
|
14
|
+
* - Partial migration: import { reactConfig } from "@caspeco/eslint-config-react"
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* npx caspeco-react-migrate-v5 [path] [--dry-run]
|
|
18
|
+
*
|
|
19
|
+
* Examples:
|
|
20
|
+
* npx caspeco-react-migrate-v5 src/
|
|
21
|
+
* npx caspeco-react-migrate-v5 . --dry-run
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import fs from "fs";
|
|
25
|
+
import path from "path";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
27
|
+
|
|
28
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
+
const __dirname = path.dirname(__filename);
|
|
30
|
+
|
|
31
|
+
const args = process.argv.slice(2);
|
|
32
|
+
const isDryRun = args.includes("--dry-run");
|
|
33
|
+
const targetPath = args.find((arg) => !arg.startsWith("--")) || ".";
|
|
34
|
+
|
|
35
|
+
// Patterns to search and replace
|
|
36
|
+
const replacements = [
|
|
37
|
+
{
|
|
38
|
+
pattern: /caspeco\/discourage-chakra-import/g,
|
|
39
|
+
replacement: "caspeco-react/discourage-chakra-import",
|
|
40
|
+
description: "Rule name",
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
// Import transformation for eslint.config.js files
|
|
45
|
+
function transformImports(content, filename) {
|
|
46
|
+
if (!filename.includes("eslint.config.")) {
|
|
47
|
+
return { content, hasChanges: false };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let transformed = content;
|
|
51
|
+
let hasChanges = false;
|
|
52
|
+
|
|
53
|
+
// Replace import { reactConfig } from "@caspeco/eslint-config" → import reactConfig from "@caspeco/eslint-config-react"
|
|
54
|
+
// Also handle the case where package name is already updated but still using named import
|
|
55
|
+
const oldPackagePattern = /import\s*\{\s*reactConfig\s*\}\s*from\s*["']@caspeco\/eslint-config["']/;
|
|
56
|
+
const newPackagePattern = /import\s*\{\s*reactConfig\s*\}\s*from\s*["']@caspeco\/eslint-config-react["']/;
|
|
57
|
+
|
|
58
|
+
if (oldPackagePattern.test(transformed)) {
|
|
59
|
+
transformed = transformed.replace(
|
|
60
|
+
oldPackagePattern,
|
|
61
|
+
'import reactConfig from "@caspeco/eslint-config-react"',
|
|
62
|
+
);
|
|
63
|
+
hasChanges = true;
|
|
64
|
+
} else if (newPackagePattern.test(transformed)) {
|
|
65
|
+
// Package name already updated, just change from named to default import
|
|
66
|
+
transformed = transformed.replace(
|
|
67
|
+
newPackagePattern,
|
|
68
|
+
'import reactConfig from "@caspeco/eslint-config-react"',
|
|
69
|
+
);
|
|
70
|
+
hasChanges = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { content: transformed, hasChanges };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// File extensions to process
|
|
77
|
+
const extensions = [".js", ".jsx", ".ts", ".tsx", ".json", ".md", ".mjs", ".cjs"];
|
|
78
|
+
|
|
79
|
+
let filesProcessed = 0;
|
|
80
|
+
let filesChanged = 0;
|
|
81
|
+
let totalReplacements = 0;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Recursively process directory
|
|
85
|
+
*/
|
|
86
|
+
function processDirectory(dir) {
|
|
87
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const fullPath = path.join(dir, entry.name);
|
|
91
|
+
|
|
92
|
+
// Skip node_modules, .git, dist, build directories
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
if (["node_modules", ".git", "dist", "build", "coverage"].includes(entry.name)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
processDirectory(fullPath);
|
|
98
|
+
} else {
|
|
99
|
+
const ext = path.extname(entry.name);
|
|
100
|
+
if (extensions.includes(ext)) {
|
|
101
|
+
processFile(fullPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Process a single file
|
|
109
|
+
*/
|
|
110
|
+
function processFile(filePath) {
|
|
111
|
+
filesProcessed++;
|
|
112
|
+
|
|
113
|
+
let content;
|
|
114
|
+
try {
|
|
115
|
+
content = fs.readFileSync(filePath, "utf8");
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.error(`Error reading ${filePath}:`, err.message);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let newContent = content;
|
|
122
|
+
let fileReplacements = 0;
|
|
123
|
+
|
|
124
|
+
// First, try import transformations for config files
|
|
125
|
+
const filename = path.basename(filePath);
|
|
126
|
+
const importResult = transformImports(newContent, filename);
|
|
127
|
+
if (importResult.hasChanges) {
|
|
128
|
+
newContent = importResult.content;
|
|
129
|
+
fileReplacements++; // Count as one logical replacement (import + references)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Then apply all other replacement patterns
|
|
133
|
+
for (const { pattern, replacement } of replacements) {
|
|
134
|
+
const matches = newContent.match(pattern);
|
|
135
|
+
if (matches) {
|
|
136
|
+
fileReplacements += matches.length;
|
|
137
|
+
newContent = newContent.replace(pattern, replacement);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// If changes were made
|
|
142
|
+
if (fileReplacements > 0) {
|
|
143
|
+
filesChanged++;
|
|
144
|
+
totalReplacements += fileReplacements;
|
|
145
|
+
|
|
146
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
147
|
+
console.log(
|
|
148
|
+
`${isDryRun ? "[DRY RUN] " : ""}✓ ${relativePath} (${fileReplacements} replacement${fileReplacements > 1 ? "s" : ""})`,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
if (!isDryRun) {
|
|
152
|
+
try {
|
|
153
|
+
fs.writeFileSync(filePath, newContent, "utf8");
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.error(`Error writing ${filePath}:`, err.message);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Main execution
|
|
163
|
+
*/
|
|
164
|
+
function main() {
|
|
165
|
+
console.log("Caspeco Plugin Migration Tool");
|
|
166
|
+
console.log("==============================\n");
|
|
167
|
+
|
|
168
|
+
if (isDryRun) {
|
|
169
|
+
console.log("🔍 Running in DRY RUN mode - no files will be modified\n");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const resolvedPath = path.resolve(targetPath);
|
|
173
|
+
|
|
174
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
175
|
+
console.error(`Error: Path "${targetPath}" does not exist`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log(`Scanning: ${resolvedPath}\n`);
|
|
180
|
+
|
|
181
|
+
const stat = fs.statSync(resolvedPath);
|
|
182
|
+
if (stat.isDirectory()) {
|
|
183
|
+
processDirectory(resolvedPath);
|
|
184
|
+
} else {
|
|
185
|
+
processFile(resolvedPath);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log("\nSummary:");
|
|
189
|
+
console.log("========");
|
|
190
|
+
console.log(`Files scanned: ${filesProcessed}`);
|
|
191
|
+
console.log(`Files with changes: ${filesChanged}`);
|
|
192
|
+
console.log(`Total replacements: ${totalReplacements}`);
|
|
193
|
+
|
|
194
|
+
if (isDryRun && filesChanged > 0) {
|
|
195
|
+
console.log("\n💡 Run without --dry-run to apply changes");
|
|
196
|
+
} else if (filesChanged > 0) {
|
|
197
|
+
console.log("\n✅ Migration complete!");
|
|
198
|
+
} else {
|
|
199
|
+
console.log("\n✨ No files needed migration");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caspeco/eslint-config-react",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1-beta.1",
|
|
4
4
|
"description": "Caspeco ESLint configuration for React projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"test": "vitest"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@caspeco/eslint-config-ts": "5.0.
|
|
35
|
+
"@caspeco/eslint-config-ts": "5.0.1-beta.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@caspeco/test-utils": "*"
|
package/src/index.js
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
import tsConfig from "@caspeco/eslint-config-ts";
|
|
2
|
-
import reactRefresh from "eslint-plugin-react-refresh";
|
|
3
|
-
import reactPlugin from "eslint-plugin-react";
|
|
4
|
-
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
5
|
-
import caspecoReactPlugin from "./plugins/caspeco-react.js";
|
|
6
|
-
import globals from "globals";
|
|
7
|
-
|
|
8
|
-
/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} */
|
|
9
|
-
const flatConfig = [
|
|
10
|
-
// Extend the vanilla TypeScript config
|
|
11
|
-
...tsConfig,
|
|
12
|
-
// React plugin recommended config
|
|
13
|
-
{
|
|
14
|
-
...reactPlugin.configs.flat?.recommended,
|
|
15
|
-
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
16
|
-
settings: {
|
|
17
|
-
react: {
|
|
18
|
-
version: "detect",
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
languageOptions: {
|
|
22
|
-
...reactPlugin.configs.flat?.recommended.languageOptions,
|
|
23
|
-
globals: {
|
|
24
|
-
...globals.serviceworker,
|
|
25
|
-
...globals.browser,
|
|
26
|
-
},
|
|
27
|
-
parserOptions: {
|
|
28
|
-
...reactPlugin.configs.flat?.recommended.languageOptions?.parserOptions,
|
|
29
|
-
ecmaVersion: "latest",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
rules: {
|
|
33
|
-
...reactPlugin.configs.flat?.recommended.rules,
|
|
34
|
-
"react/react-in-jsx-scope": "off",
|
|
35
|
-
"react/prop-types": "off",
|
|
36
|
-
"react/display-name": "off",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
// React hooks plugin recommended config
|
|
40
|
-
{
|
|
41
|
-
...reactHooksPlugin.configs.recommended,
|
|
42
|
-
plugins: { "react-hooks": reactHooksPlugin },
|
|
43
|
-
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
44
|
-
rules: {
|
|
45
|
-
"react-hooks/rules-of-hooks": "error",
|
|
46
|
-
"react-hooks/exhaustive-deps": "warn",
|
|
47
|
-
// We ignore the compiler specific rules as we need React 19 for this.
|
|
48
|
-
// https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks#flat-config-eslintconfigjsts-1
|
|
49
|
-
// When we support this, we can add:
|
|
50
|
-
// ...reactHooksPlugin.configs.recommended.rules,
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
// React refresh plugin config
|
|
54
|
-
{
|
|
55
|
-
...reactRefresh.configs.recommended,
|
|
56
|
-
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
57
|
-
rules: {
|
|
58
|
-
...reactRefresh.configs.recommended.rules,
|
|
59
|
-
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
// Caspeco React custom rules
|
|
63
|
-
{
|
|
64
|
-
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
65
|
-
plugins: {
|
|
66
|
-
"caspeco-react": caspecoReactPlugin,
|
|
67
|
-
},
|
|
68
|
-
rules: {
|
|
69
|
-
"caspeco-react/discourage-chakra-import": "error",
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
export default flatConfig;
|
|
1
|
+
import tsConfig from "@caspeco/eslint-config-ts";
|
|
2
|
+
import reactRefresh from "eslint-plugin-react-refresh";
|
|
3
|
+
import reactPlugin from "eslint-plugin-react";
|
|
4
|
+
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
5
|
+
import caspecoReactPlugin from "./plugins/caspeco-react.js";
|
|
6
|
+
import globals from "globals";
|
|
7
|
+
|
|
8
|
+
/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} */
|
|
9
|
+
const flatConfig = [
|
|
10
|
+
// Extend the vanilla TypeScript config
|
|
11
|
+
...tsConfig,
|
|
12
|
+
// React plugin recommended config
|
|
13
|
+
{
|
|
14
|
+
...reactPlugin.configs.flat?.recommended,
|
|
15
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
16
|
+
settings: {
|
|
17
|
+
react: {
|
|
18
|
+
version: "detect",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
languageOptions: {
|
|
22
|
+
...reactPlugin.configs.flat?.recommended.languageOptions,
|
|
23
|
+
globals: {
|
|
24
|
+
...globals.serviceworker,
|
|
25
|
+
...globals.browser,
|
|
26
|
+
},
|
|
27
|
+
parserOptions: {
|
|
28
|
+
...reactPlugin.configs.flat?.recommended.languageOptions?.parserOptions,
|
|
29
|
+
ecmaVersion: "latest",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
...reactPlugin.configs.flat?.recommended.rules,
|
|
34
|
+
"react/react-in-jsx-scope": "off",
|
|
35
|
+
"react/prop-types": "off",
|
|
36
|
+
"react/display-name": "off",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
// React hooks plugin recommended config
|
|
40
|
+
{
|
|
41
|
+
...reactHooksPlugin.configs.recommended,
|
|
42
|
+
plugins: { "react-hooks": reactHooksPlugin },
|
|
43
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
44
|
+
rules: {
|
|
45
|
+
"react-hooks/rules-of-hooks": "error",
|
|
46
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
47
|
+
// We ignore the compiler specific rules as we need React 19 for this.
|
|
48
|
+
// https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks#flat-config-eslintconfigjsts-1
|
|
49
|
+
// When we support this, we can add:
|
|
50
|
+
// ...reactHooksPlugin.configs.recommended.rules,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
// React refresh plugin config
|
|
54
|
+
{
|
|
55
|
+
...reactRefresh.configs.recommended,
|
|
56
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
57
|
+
rules: {
|
|
58
|
+
...reactRefresh.configs.recommended.rules,
|
|
59
|
+
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
// Caspeco React custom rules
|
|
63
|
+
{
|
|
64
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.jsx"],
|
|
65
|
+
plugins: {
|
|
66
|
+
"caspeco-react": caspecoReactPlugin,
|
|
67
|
+
},
|
|
68
|
+
rules: {
|
|
69
|
+
"caspeco-react/discourage-chakra-import": "error",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
export default flatConfig;
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {import("eslint").Rule.RuleModule} Rule
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @type {{ rules: { [key: string]: Rule } }}
|
|
7
|
-
*/
|
|
8
|
-
const caspeco = {
|
|
9
|
-
rules: {
|
|
10
|
-
"discourage-chakra-import": {
|
|
11
|
-
meta: {
|
|
12
|
-
type: "suggestion",
|
|
13
|
-
docs: {
|
|
14
|
-
description:
|
|
15
|
-
'Discourage importing anything from "@chakra-ui/*". Use imports from "@caspeco/casper-ui-library" instead.',
|
|
16
|
-
category: "Best Practices",
|
|
17
|
-
url: "https://caspeco.github.io/eslint-config/#/plugins/caspeco?id=caspecodiscourage-chakra-import",
|
|
18
|
-
recommended: false,
|
|
19
|
-
},
|
|
20
|
-
messages: {
|
|
21
|
-
restrictedImport: "Importing from {{importPath}} is discouraged.",
|
|
22
|
-
},
|
|
23
|
-
schema: [],
|
|
24
|
-
},
|
|
25
|
-
create(context) {
|
|
26
|
-
return {
|
|
27
|
-
ImportDeclaration(node) {
|
|
28
|
-
const importPath = node.source.value;
|
|
29
|
-
if (typeof importPath === "string" && importPath.startsWith("@chakra-ui/")) {
|
|
30
|
-
context.report({
|
|
31
|
-
node,
|
|
32
|
-
messageId: "restrictedImport",
|
|
33
|
-
data: {
|
|
34
|
-
importPath,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export default caspeco;
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("eslint").Rule.RuleModule} Rule
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @type {{ rules: { [key: string]: Rule } }}
|
|
7
|
+
*/
|
|
8
|
+
const caspeco = {
|
|
9
|
+
rules: {
|
|
10
|
+
"discourage-chakra-import": {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: {
|
|
14
|
+
description:
|
|
15
|
+
'Discourage importing anything from "@chakra-ui/*". Use imports from "@caspeco/casper-ui-library" instead.',
|
|
16
|
+
category: "Best Practices",
|
|
17
|
+
url: "https://caspeco.github.io/eslint-config/#/plugins/caspeco?id=caspecodiscourage-chakra-import",
|
|
18
|
+
recommended: false,
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
restrictedImport: "Importing from {{importPath}} is discouraged.",
|
|
22
|
+
},
|
|
23
|
+
schema: [],
|
|
24
|
+
},
|
|
25
|
+
create(context) {
|
|
26
|
+
return {
|
|
27
|
+
ImportDeclaration(node) {
|
|
28
|
+
const importPath = node.source.value;
|
|
29
|
+
if (typeof importPath === "string" && importPath.startsWith("@chakra-ui/")) {
|
|
30
|
+
context.report({
|
|
31
|
+
node,
|
|
32
|
+
messageId: "restrictedImport",
|
|
33
|
+
data: {
|
|
34
|
+
importPath,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default caspeco;
|