eslint-plugin-react-naming-convention 2.7.4-next.0 → 2.7.4-next.10
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 +9 -0
- package/dist/index.js +33 -32
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -38,6 +38,15 @@ export default defineConfig(
|
|
|
38
38
|
);
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
> [!NOTE]
|
|
42
|
+
> Naming convention rules enforce consistent naming patterns for `React` entities.
|
|
43
|
+
|
|
44
|
+
- [`component-name`](./naming-convention-component-name) - Enforces naming conventions for components (⚙️ Configurable)
|
|
45
|
+
- [`context-name`](./naming-convention-context-name) - Enforces context names ending with `Context` suffix
|
|
46
|
+
- [`filename`](./naming-convention-filename) - Enforces consistent file naming (⚙️ Configurable)
|
|
47
|
+
- [`filename-extension`](./naming-convention-filename-extension) - Enforces `JSX` file extensions (⚙️ Configurable)
|
|
48
|
+
- [`use-state`](./naming-convention-use-state) - Enforces symmetric naming of `useState` pairs (e.g., `[value, setValue]`)
|
|
49
|
+
|
|
41
50
|
## Rules
|
|
42
51
|
|
|
43
52
|
<https://eslint-react.xyz/docs/rules/overview#naming-convention-rules>
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RE_CAMEL_CASE, RE_CONSTANT_CASE, RE_KEBAB_CASE, RE_PASCAL_CASE, RE_SNAKE_CASE, WEBSITE_URL, defineRuleListener, getConfigAdapters, getSettingsFromContext, toRegExp } from "@eslint-react/shared";
|
|
2
|
-
import {
|
|
2
|
+
import { isComponentName, isCreateContextCall, isUseRefCall, isUseStateCall, useComponentCollector, useComponentCollectorLegacy } from "@eslint-react/core";
|
|
3
3
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
4
|
+
import { findEnclosingAssignmentTarget } from "@eslint-react/var";
|
|
4
5
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
5
6
|
import { compare } from "compare-versions";
|
|
6
7
|
import { P, match } from "ts-pattern";
|
|
@@ -13,9 +14,9 @@ import * as AST from "@eslint-react/ast";
|
|
|
13
14
|
var __defProp = Object.defineProperty;
|
|
14
15
|
var __exportAll = (all, symbols) => {
|
|
15
16
|
let target = {};
|
|
16
|
-
for (var name
|
|
17
|
-
__defProp(target, name
|
|
18
|
-
get: all[name
|
|
17
|
+
for (var name in all) {
|
|
18
|
+
__defProp(target, name, {
|
|
19
|
+
get: all[name],
|
|
19
20
|
enumerable: true
|
|
20
21
|
});
|
|
21
22
|
}
|
|
@@ -41,7 +42,7 @@ const rules = {
|
|
|
41
42
|
//#endregion
|
|
42
43
|
//#region package.json
|
|
43
44
|
var name = "eslint-plugin-react-naming-convention";
|
|
44
|
-
var version = "2.7.4-next.
|
|
45
|
+
var version = "2.7.4-next.10";
|
|
45
46
|
|
|
46
47
|
//#endregion
|
|
47
48
|
//#region src/utils/create-rule.ts
|
|
@@ -97,24 +98,24 @@ function create$5(context) {
|
|
|
97
98
|
const fCollector = useComponentCollector(context);
|
|
98
99
|
const cCollector = useComponentCollectorLegacy(context);
|
|
99
100
|
return defineRuleListener(fCollector.visitor, cCollector.visitor, { "Program:exit"(program) {
|
|
100
|
-
for (const { id, name
|
|
101
|
-
if (isValidName(name
|
|
101
|
+
for (const { id, name, node: component } of fCollector.ctx.getAllComponents(program)) {
|
|
102
|
+
if (isValidName(name, options)) continue;
|
|
102
103
|
context.report({
|
|
103
104
|
messageId: "invalidComponentName",
|
|
104
105
|
node: id ?? component,
|
|
105
106
|
data: {
|
|
106
|
-
name
|
|
107
|
+
name,
|
|
107
108
|
rule
|
|
108
109
|
}
|
|
109
110
|
});
|
|
110
111
|
}
|
|
111
|
-
for (const { id, name
|
|
112
|
-
if (isValidName(name
|
|
112
|
+
for (const { id, name, node } of cCollector.ctx.getAllComponents(program)) {
|
|
113
|
+
if (isValidName(name, options)) continue;
|
|
113
114
|
context.report({
|
|
114
115
|
messageId: "invalidComponentName",
|
|
115
116
|
node: id ?? node,
|
|
116
117
|
data: {
|
|
117
|
-
name
|
|
118
|
+
name,
|
|
118
119
|
rule
|
|
119
120
|
}
|
|
120
121
|
});
|
|
@@ -133,10 +134,10 @@ function normalizeOptions(options) {
|
|
|
133
134
|
}
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
|
-
function isValidName(name
|
|
137
|
-
if (name
|
|
138
|
-
if (options.excepts.some((regex) => regex.test(name
|
|
139
|
-
const normalized = name
|
|
137
|
+
function isValidName(name, options) {
|
|
138
|
+
if (name == null) return true;
|
|
139
|
+
if (options.excepts.some((regex) => regex.test(name))) return true;
|
|
140
|
+
const normalized = name.split(".").at(-1) ?? name;
|
|
140
141
|
switch (options.rule) {
|
|
141
142
|
case "CONSTANT_CASE": return RE_CONSTANT_CASE.test(normalized);
|
|
142
143
|
case "PascalCase":
|
|
@@ -161,19 +162,19 @@ var context_name_default = createRule({
|
|
|
161
162
|
});
|
|
162
163
|
function create$4(context) {
|
|
163
164
|
if (!context.sourceCode.text.includes("createContext")) return {};
|
|
164
|
-
const { version
|
|
165
|
-
if (compare(version
|
|
165
|
+
const { version } = getSettingsFromContext(context);
|
|
166
|
+
if (compare(version, "19.0.0", "<")) return {};
|
|
166
167
|
return { CallExpression(node) {
|
|
167
168
|
if (!isCreateContextCall(context, node)) return;
|
|
168
|
-
const [id, name
|
|
169
|
+
const [id, name] = match(findEnclosingAssignmentTarget(node)).with({
|
|
169
170
|
type: AST_NODE_TYPES.Identifier,
|
|
170
171
|
name: P.string
|
|
171
|
-
}, (id
|
|
172
|
+
}, (id) => [id, id.name]).with({
|
|
172
173
|
type: AST_NODE_TYPES.MemberExpression,
|
|
173
174
|
property: { name: P.string }
|
|
174
|
-
}, (id
|
|
175
|
+
}, (id) => [id, id.property.name]).otherwise(() => [null, null]);
|
|
175
176
|
if (id == null) return;
|
|
176
|
-
if (isComponentName(name
|
|
177
|
+
if (isComponentName(name) && name.endsWith("Context")) return;
|
|
177
178
|
context.report({
|
|
178
179
|
messageId: "invalidContextName",
|
|
179
180
|
node: id
|
|
@@ -248,14 +249,14 @@ function create$3(context) {
|
|
|
248
249
|
const options = context.options[0] ?? defaultOptions$2[0];
|
|
249
250
|
const rule = typeof options === "string" ? options : options.rule ?? "PascalCase";
|
|
250
251
|
const excepts = typeof options === "string" ? [] : (options.excepts ?? []).map((s) => toRegExp(s));
|
|
251
|
-
function validate(name
|
|
252
|
-
if (ignores.some((pattern) => pattern.test(name
|
|
253
|
-
const filteredName = name
|
|
252
|
+
function validate(name, casing = rule, ignores = excepts) {
|
|
253
|
+
if (ignores.some((pattern) => pattern.test(name))) return true;
|
|
254
|
+
const filteredName = name.match(/[\w.-]/gu)?.join("") ?? "";
|
|
254
255
|
if (filteredName.length === 0) return true;
|
|
255
256
|
return match(casing).with("PascalCase", () => RE_PASCAL_CASE.test(filteredName)).with("camelCase", () => RE_CAMEL_CASE.test(filteredName)).with("kebab-case", () => RE_KEBAB_CASE.test(filteredName)).with("snake_case", () => RE_SNAKE_CASE.test(filteredName)).exhaustive();
|
|
256
257
|
}
|
|
257
|
-
function getSuggestion(name
|
|
258
|
-
return match(casing).with("PascalCase", () => pascalCase(name
|
|
258
|
+
function getSuggestion(name, casing = rule) {
|
|
259
|
+
return match(casing).with("PascalCase", () => pascalCase(name)).with("camelCase", () => camelCase(name)).with("kebab-case", () => kebabCase(name)).with("snake_case", () => snakeCase(name)).exhaustive();
|
|
259
260
|
}
|
|
260
261
|
return { Program(node) {
|
|
261
262
|
const [basename = "", ...rest] = path.basename(context.filename).split(".");
|
|
@@ -377,15 +378,15 @@ function create$1(context) {
|
|
|
377
378
|
return { CallExpression(node) {
|
|
378
379
|
if (!isUseRefCall(node)) return;
|
|
379
380
|
if (AST.getUnderlyingExpression(node.parent).type === AST_NODE_TYPES.MemberExpression) return;
|
|
380
|
-
const [id, name
|
|
381
|
+
const [id, name] = match(findEnclosingAssignmentTarget(node)).with({
|
|
381
382
|
type: AST_NODE_TYPES.Identifier,
|
|
382
383
|
name: P.string
|
|
383
|
-
}, (id
|
|
384
|
+
}, (id) => [id, id.name]).with({
|
|
384
385
|
type: AST_NODE_TYPES.MemberExpression,
|
|
385
386
|
property: { name: P.string }
|
|
386
|
-
}, (id
|
|
387
|
+
}, (id) => [id, id.property.name]).otherwise(() => [null, null]);
|
|
387
388
|
if (id == null) return;
|
|
388
|
-
if (name
|
|
389
|
+
if (name.endsWith("Ref") || name === "ref") return;
|
|
389
390
|
context.report({
|
|
390
391
|
messageId: "invalidRefName",
|
|
391
392
|
node: id
|
|
@@ -459,7 +460,7 @@ function create(context) {
|
|
|
459
460
|
return;
|
|
460
461
|
}
|
|
461
462
|
if (setter == null || !enforceSetterName) return;
|
|
462
|
-
const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id
|
|
463
|
+
const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id) => id.name).otherwise(() => null);
|
|
463
464
|
if (setterName == null || !setterName.startsWith("set")) {
|
|
464
465
|
context.report({
|
|
465
466
|
messageId: "invalidSetterName",
|
|
@@ -467,7 +468,7 @@ function create(context) {
|
|
|
467
468
|
});
|
|
468
469
|
return;
|
|
469
470
|
}
|
|
470
|
-
const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, ({ name
|
|
471
|
+
const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, ({ name }) => snakeCase(name)).with({ type: AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
|
|
471
472
|
return properties.reduce((acc, prop) => {
|
|
472
473
|
if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) return [...acc, prop.key.name];
|
|
473
474
|
return acc;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-naming-convention",
|
|
3
|
-
"version": "2.7.4-next.
|
|
3
|
+
"version": "2.7.4-next.10",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for naming convention related rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"directory": "packages/plugins/eslint-plugin-react-naming-convention"
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
23
|
-
"author": "Rel1cx
|
|
23
|
+
"author": "Rel1cx",
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"type": "module",
|
|
26
26
|
"exports": {
|
|
@@ -45,16 +45,16 @@
|
|
|
45
45
|
"compare-versions": "^6.1.1",
|
|
46
46
|
"string-ts": "^2.3.1",
|
|
47
47
|
"ts-pattern": "^5.9.0",
|
|
48
|
-
"@eslint-react/ast": "2.7.4-next.
|
|
49
|
-
"@eslint-react/eff": "2.7.4-next.
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
48
|
+
"@eslint-react/ast": "2.7.4-next.10",
|
|
49
|
+
"@eslint-react/eff": "2.7.4-next.10",
|
|
50
|
+
"@eslint-react/var": "2.7.4-next.10",
|
|
51
|
+
"@eslint-react/core": "2.7.4-next.10",
|
|
52
|
+
"@eslint-react/shared": "2.7.4-next.10"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/react": "^19.2.9",
|
|
56
56
|
"@types/react-dom": "^19.2.3",
|
|
57
|
-
"tsdown": "^0.20.
|
|
57
|
+
"tsdown": "^0.20.1",
|
|
58
58
|
"@local/configs": "0.0.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|