Skip to content

Commit 3a3cb65

Browse files
committed
Move no-forbidden-props rule to rules-removed and update imports
1 parent 2bd38e5 commit 3a3cb65

File tree

14 files changed

+244
-29
lines changed

14 files changed

+244
-29
lines changed

.pkgs/configs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"@stylistic/eslint-plugin": "^5.5.0",
2424
"eslint-plugin-de-morgan": "^2.0.0",
2525
"eslint-plugin-function": "^0.0.33",
26-
"eslint-plugin-jsdoc": "^61.1.11",
26+
"eslint-plugin-jsdoc": "^61.1.12",
2727
"eslint-plugin-perfectionist": "^4.15.1",
2828
"eslint-plugin-regexp": "^2.10.0",
2929
"eslint-plugin-unicorn": "^62.0.0",

.pkgs/eslint-plugin-local/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"@typescript-eslint/types": "^8.46.2",
3232
"@typescript-eslint/utils": "^8.46.2",
3333
"eslint-plugin-de-morgan": "^2.0.0",
34-
"eslint-plugin-jsdoc": "^61.1.11",
34+
"eslint-plugin-jsdoc": "^61.1.12",
3535
"eslint-plugin-perfectionist": "^4.15.1",
3636
"eslint-plugin-regexp": "^2.10.0",
3737
"eslint-plugin-unicorn": "^62.0.0",
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
---
2+
title: no-forbidden-props
3+
---
4+
5+
**Full Name in `@eslint-react/eslint-plugin`**
6+
7+
```plain copy
8+
@eslint-react/no-forbidden-props
9+
```
10+
11+
**Full Name in `eslint-plugin-react-x`**
12+
13+
```plain copy
14+
react-x/no-forbidden-props
15+
```
16+
17+
**Features**
18+
19+
`🔧` `🧪`
20+
21+
<Callout type="warning" title="DEPRECATED">
22+
Use [`no-restricted-syntax`](https://eslint.org/docs/latest/rules/no-restricted-syntax) rule or type checking instead. This rule is deprecated and will be removed in future releases.
23+
</Callout>
24+
25+
## Description
26+
27+
Disallow certain props on components. This rule helps enforce consistent prop naming conventions and prevents the use of specific props that may be problematic or against your team's coding standards.
28+
29+
By default, this rule forbids snake\_case props (props containing underscores) to encourage camelCase naming conventions.
30+
31+
## Rule Options
32+
33+
The rule accepts an object with the following properties:
34+
35+
- `forbid` (array): An array of forbidden prop configurations. Each item can be:
36+
- A string: The exact prop name to forbid
37+
- An object with `prop` and optional `excludedNodes` or `includedNodes`:
38+
- `prop` (string): The prop name or regex pattern to forbid
39+
- `excludedNodes` (array): Component names where this prop is allowed
40+
- `includedNodes` (array): Component names where this prop is forbidden (others are allowed)
41+
42+
### Default Configuration
43+
44+
```json
45+
{
46+
"forbid": [{ "prop": "/_/" }]
47+
}
48+
```
49+
50+
This default configuration forbids any prop containing an underscore (snake\_case).
51+
52+
## Examples
53+
54+
### Default Behavior (Forbids snake\_case props)
55+
56+
#### Failing
57+
58+
```tsx
59+
<div snake_case="value" />
60+
<Component user_name="test" />
61+
<ns:Element data_value="test" />
62+
```
63+
64+
#### Passing
65+
66+
```tsx
67+
<div camelCase="value" />
68+
<Component userName="test" />
69+
<ns:Element dataValue="test" />
70+
```
71+
72+
### Custom Forbidden Props
73+
74+
Configuration:
75+
76+
```json
77+
{
78+
"forbid": ["className", "style"]
79+
}
80+
```
81+
82+
#### Failing
83+
84+
```tsx
85+
<div className="test" />
86+
<Component style={{}} />
87+
```
88+
89+
#### Passing
90+
91+
```tsx
92+
<div id="test" />
93+
<Component id="test" />
94+
```
95+
96+
### Regex Patterns
97+
98+
Configuration:
99+
100+
```json
101+
{
102+
"forbid": [
103+
{ "prop": "/^data-/" },
104+
{ "prop": "/^aria-/" }
105+
]
106+
}
107+
```
108+
109+
#### Failing
110+
111+
```tsx
112+
<div data-testid="test" />
113+
<div aria-label="test" />
114+
<div data-cy="test" />
115+
```
116+
117+
#### Passing
118+
119+
```tsx
120+
<div id="test" />
121+
<div className="test" />
122+
```
123+
124+
### Node-Specific Exclusions
125+
126+
Configuration:
127+
128+
```json
129+
{
130+
"forbid": [
131+
{
132+
"prop": "/_/",
133+
"excludedNodes": ["Button"]
134+
}
135+
]
136+
}
137+
```
138+
139+
#### Failing
140+
141+
```tsx
142+
<div snake_case="value" />
143+
<Span snake_case="value" />
144+
```
145+
146+
#### Passing
147+
148+
```tsx
149+
<Button snake_case="value" />;
150+
```
151+
152+
### Node-Specific Inclusions
153+
154+
Configuration:
155+
156+
```json
157+
{
158+
"forbid": [
159+
{
160+
"prop": "/_/",
161+
"includedNodes": ["Button", "Input"]
162+
}
163+
]
164+
}
165+
```
166+
167+
#### Failing
168+
169+
```tsx
170+
<Button snake_case="value" />
171+
<Input snake_case="value" />
172+
```
173+
174+
#### Passing
175+
176+
```tsx
177+
<div snake_case="value" />
178+
<span snake_case="value" />
179+
```
180+
181+
### Mixed Configuration
182+
183+
```json
184+
{
185+
"forbid": [
186+
"className",
187+
{ "prop": "/^data-/", "excludedNodes": ["Button"] },
188+
{ "prop": "/^aria-/", "includedNodes": ["Input"] }
189+
]
190+
}
191+
```
192+
193+
This configuration:
194+
195+
- Forbids `className` on all components
196+
- Forbids `data-*` props on all components except `Button`
197+
- Forbids `aria-*` props only on `Input` components
198+
199+
## Implementation
200+
201+
- [Rule Source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x/src/rules-removed/no-forbidden-props.ts)
202+
- [Test Source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x/src/rules-removed/no-forbidden-props.spec.ts)
203+
204+
## Notes
205+
206+
- Spread attributes (`{...props}`) are ignored by this rule
207+
- JSXMemberExpression components (like `React.Component`) are supported for prop checking, but node-specific filtering may not work as expected
208+
- Regex patterns should be wrapped in forward slashes (e.g., `/pattern/`)
209+
- The rule processes each forbidden prop configuration independently

apps/website/content/docs/rules/meta.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
"no-default-props",
3131
"no-direct-mutation-state",
3232
"no-duplicate-key",
33-
"no-forbidden-props",
3433
"no-forward-ref",
3534
"no-implicit-key",
3635
"no-leaked-conditional-rendering",

apps/website/eslint.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const dirname = fileURLToPath(new URL(".", import.meta.url));
2626
const gitignore = fileURLToPath(new URL(".gitignore", import.meta.url));
2727

2828
export default defineConfig([
29+
// @ts-expect-error - types issue
2930
includeIgnoreFile(gitignore, "Imported .gitignore patterns"),
3031
globalIgnores(GLOB_IGNORES),
3132
{

apps/website/migration/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,9 @@ export const redirects = [
7070
destination: "/docs/rules/prefer-use-state-lazy-initialization",
7171
permanent: true,
7272
},
73+
{
74+
source: "/docs/rules/no-forbidden-props",
75+
destination: "/docs/rules-removed/no-forbidden-props",
76+
permanent: true,
77+
},
7378
] as const;

apps/website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"twoslash": "^0.3.4"
3030
},
3131
"devDependencies": {
32-
"@effect/language-service": "^0.53.3",
32+
"@effect/language-service": "^0.54.0",
3333
"@eslint-react/eslint-plugin": "workspace:*",
3434
"@eslint-react/shared": "workspace:*",
3535
"@eslint/js": "^9.39.0",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"update:website": "tsx ./scripts/update-website.ts"
5353
},
5454
"devDependencies": {
55-
"@effect/language-service": "^0.53.3",
55+
"@effect/language-service": "^0.54.0",
5656
"@effect/platform": "^0.92.1",
5757
"@effect/platform-node": "^0.98.4",
5858
"@eslint/compat": "^1.4.1",
@@ -87,7 +87,7 @@
8787
"ts-pattern": "^5.9.0",
8888
"tsdown": "^0.15.12",
8989
"tsx": "^4.20.6",
90-
"type-fest": "^5.1.0",
90+
"type-fest": "^5.2.0",
9191
"typedoc": "^0.28.14",
9292
"typedoc-plugin-markdown": "^4.9.0",
9393
"typedoc-plugin-mdn-links": "^5.0.10",

packages/plugins/eslint-plugin-react-x/src/plugin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import noCreateRef from "./rules/no-create-ref";
3030
import noDefaultProps from "./rules/no-default-props";
3131
import noDirectMutationState from "./rules/no-direct-mutation-state";
3232
import noDuplicateKey from "./rules/no-duplicate-key";
33-
import noForbiddenProps from "./rules/no-forbidden-props";
3433
import noForwardRef from "./rules/no-forward-ref";
3534
import noImplicitKey from "./rules/no-implicit-key";
3635
import noLeakedConditionalRendering from "./rules/no-leaked-conditional-rendering";
@@ -66,6 +65,8 @@ import preferNamespaceImport from "./rules/prefer-namespace-import";
6665
import preferReadOnlyProps from "./rules/prefer-read-only-props";
6766
import preferUseStateLazyInitialization from "./rules/prefer-use-state-lazy-initialization";
6867

68+
import noForbiddenProps from "./rules-removed/no-forbidden-props";
69+
6970
export const plugin: CompatiblePlugin = {
7071
meta: {
7172
name,

0 commit comments

Comments
 (0)