@smartive/eslint-config 8.0.0-next.3 → 8.1.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 +27 -0
- package/dist/plugin/forbid-component-props.js +59 -8
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -141,6 +141,33 @@ Enabled in the `react` and `nextjs` rule sets as:
|
|
|
141
141
|
'smartive/forbid-component-props': ['warn', { forbid: ['style', 'className'] }]
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
Each entry in `forbid` is either a prop name or an object that narrows where the prop stays allowed:
|
|
145
|
+
|
|
146
|
+
| Key | Meaning |
|
|
147
|
+
| -------------------- | ---------------------------------------------------------------------------------------- |
|
|
148
|
+
| `propName` | The forbidden prop (required). |
|
|
149
|
+
| `allowedFor` | Component names the prop is still allowed on, matched exactly. |
|
|
150
|
+
| `allowedForPatterns` | Globs (`*` for any run of characters, `?` for one) the component name may match instead. |
|
|
151
|
+
| `message` | Replaces the default report message. |
|
|
152
|
+
|
|
153
|
+
Component names are matched on their full JSX name, so `<Mantine.Button />` matches `Mantine.*`.
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
'smartive/forbid-component-props': [
|
|
157
|
+
'error',
|
|
158
|
+
{
|
|
159
|
+
forbid: [
|
|
160
|
+
{
|
|
161
|
+
propName: 'className',
|
|
162
|
+
allowedFor: ['NextImage', 'NextLink'],
|
|
163
|
+
allowedForPatterns: ['*Icon', 'Mantine*'],
|
|
164
|
+
message: 'Avoid using className except NextImage, NextLink, icons and Mantine components',
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
]
|
|
169
|
+
```
|
|
170
|
+
|
|
144
171
|
## Development
|
|
145
172
|
|
|
146
173
|
```sh
|
|
@@ -11,6 +11,27 @@ const isComponent = (name) => {
|
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* The source text of the element name, so that `<Ui.Group.Item />` can be matched as `Ui.Group.Item`.
|
|
16
|
+
*/
|
|
17
|
+
const elementName = (name) => {
|
|
18
|
+
switch (name.type) {
|
|
19
|
+
case 'JSXIdentifier':
|
|
20
|
+
return name.name;
|
|
21
|
+
case 'JSXMemberExpression':
|
|
22
|
+
return `${elementName(name.object)}.${name.property.name}`;
|
|
23
|
+
default:
|
|
24
|
+
return `${name.namespace.name}:${name.name.name}`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Glob matching for `allowedForPatterns`: `*` matches any run of characters, `?` a single one.
|
|
29
|
+
*/
|
|
30
|
+
const globToRegExp = (pattern) => new RegExp(`^${pattern
|
|
31
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
32
|
+
.replace(/\*/g, '.*')
|
|
33
|
+
.replace(/\?/g, '.')}$`);
|
|
34
|
+
const normalize = (option) => (typeof option === 'string' ? { propName: option } : option);
|
|
14
35
|
/**
|
|
15
36
|
* Replacement for `react/forbid-component-props`, which has no equivalent in
|
|
16
37
|
* `@eslint-react/eslint-plugin` (https://eslint-react.xyz/docs/migrating-from-eslint-plugin-react).
|
|
@@ -28,7 +49,22 @@ export const forbidComponentProps = {
|
|
|
28
49
|
properties: {
|
|
29
50
|
forbid: {
|
|
30
51
|
type: 'array',
|
|
31
|
-
items: {
|
|
52
|
+
items: {
|
|
53
|
+
anyOf: [
|
|
54
|
+
{ type: 'string' },
|
|
55
|
+
{
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
propName: { type: 'string' },
|
|
59
|
+
allowedFor: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
60
|
+
allowedForPatterns: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
61
|
+
message: { type: 'string' },
|
|
62
|
+
},
|
|
63
|
+
required: ['propName'],
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
32
68
|
uniqueItems: true,
|
|
33
69
|
},
|
|
34
70
|
},
|
|
@@ -37,11 +73,19 @@ export const forbidComponentProps = {
|
|
|
37
73
|
],
|
|
38
74
|
messages: {
|
|
39
75
|
forbiddenProp: 'Prop "{{prop}}" is forbidden on components.',
|
|
76
|
+
forbiddenPropWithMessage: '{{message}}',
|
|
40
77
|
},
|
|
41
78
|
},
|
|
42
79
|
create(context) {
|
|
43
80
|
const { forbid = [] } = (context.options[0] ?? {});
|
|
44
|
-
const forbidden = new
|
|
81
|
+
const forbidden = new Map(forbid.map(normalize).map((entry) => [
|
|
82
|
+
entry.propName,
|
|
83
|
+
{
|
|
84
|
+
allowedFor: new Set(entry.allowedFor ?? []),
|
|
85
|
+
allowedForPatterns: (entry.allowedForPatterns ?? []).map(globToRegExp),
|
|
86
|
+
message: entry.message,
|
|
87
|
+
},
|
|
88
|
+
]));
|
|
45
89
|
if (forbidden.size === 0) {
|
|
46
90
|
return {};
|
|
47
91
|
}
|
|
@@ -51,17 +95,24 @@ export const forbidComponentProps = {
|
|
|
51
95
|
if (!isComponent(element.name)) {
|
|
52
96
|
return;
|
|
53
97
|
}
|
|
98
|
+
const component = elementName(element.name);
|
|
54
99
|
for (const attribute of element.attributes) {
|
|
55
100
|
if (attribute.type !== 'JSXAttribute' || attribute.name.type !== 'JSXIdentifier') {
|
|
56
101
|
continue;
|
|
57
102
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
103
|
+
const entry = forbidden.get(attribute.name.name);
|
|
104
|
+
if (!entry) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (entry.allowedFor.has(component) || entry.allowedForPatterns.some((pattern) => pattern.test(component))) {
|
|
108
|
+
continue;
|
|
64
109
|
}
|
|
110
|
+
context.report({
|
|
111
|
+
node: attribute,
|
|
112
|
+
...(entry.message
|
|
113
|
+
? { messageId: 'forbiddenPropWithMessage', data: { message: entry.message } }
|
|
114
|
+
: { messageId: 'forbiddenProp', data: { prop: attribute.name.name } }),
|
|
115
|
+
});
|
|
65
116
|
}
|
|
66
117
|
},
|
|
67
118
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartive/eslint-config",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "ESLint configuration by smartive",
|
|
5
5
|
"files": [
|
|
6
6
|
"README.md",
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"@commitlint/cli": "21.2.2",
|
|
56
56
|
"@commitlint/config-conventional": "21.2.2",
|
|
57
57
|
"@smartive/prettier-config": "3.1.2",
|
|
58
|
-
"@types/node": "25.9.
|
|
58
|
+
"@types/node": "25.9.7",
|
|
59
59
|
"@types/react": "19.3.0",
|
|
60
60
|
"@types/react-dom": "19.3.0",
|
|
61
61
|
"cz-conventional-changelog": "3.3.0",
|
|
62
|
-
"eslint": "10.
|
|
62
|
+
"eslint": "10.10.0",
|
|
63
63
|
"eslint-config-next": "16.3.5",
|
|
64
64
|
"husky": "9.1.7",
|
|
65
65
|
"next": "16.3.5",
|
|
66
|
-
"prettier": "3.9.
|
|
66
|
+
"prettier": "3.9.8",
|
|
67
67
|
"react": "19.3.0",
|
|
68
68
|
"react-dom": "19.3.0",
|
|
69
69
|
"typescript": "6.0.3"
|