eslint-plugin-react-naming-convention 2.0.0-next.2 → 2.0.0-next.200

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 CHANGED
@@ -17,29 +17,32 @@ npm install --save-dev eslint-plugin-react-naming-convention
17
17
  // @ts-check
18
18
  import js from "@eslint/js";
19
19
  import reactNamingConvention from "eslint-plugin-react-naming-convention";
20
+ import { defineConfig } from "eslint/config";
20
21
  import tseslint from "typescript-eslint";
21
22
 
22
- export default tseslint.config({
23
- files: ["**/*.ts", "**/*.tsx"],
24
- extends: [
25
- js.configs.recommended,
26
- tseslint.configs.recommended,
27
- ],
28
- plugins: {
29
- "react-naming-convention": reactNamingConvention,
30
- },
31
- languageOptions: {
32
- parser: tseslint.parser,
33
- parserOptions: {
34
- projectService: true,
35
- tsconfigRootDir: import.meta.dirname,
23
+ export default defineConfig([
24
+ {
25
+ files: ["**/*.ts", "**/*.tsx"],
26
+ extends: [
27
+ js.configs.recommended,
28
+ tseslint.configs.recommended,
29
+ ],
30
+ plugins: {
31
+ "react-naming-convention": reactNamingConvention,
32
+ },
33
+ languageOptions: {
34
+ parser: tseslint.parser,
35
+ parserOptions: {
36
+ projectService: true,
37
+ tsconfigRootDir: import.meta.dirname,
38
+ },
39
+ },
40
+ rules: {
41
+ // Put rules you want to use here
42
+ "react-naming-convention/component-name": "warn",
36
43
  },
37
44
  },
38
- rules: {
39
- // Put rules you want to use here
40
- "react-naming-convention/component-name": "warn",
41
- },
42
- });
45
+ ]);
43
46
  ```
44
47
 
45
48
  ## Rules
package/dist/index.d.ts CHANGED
@@ -1,77 +1,20 @@
1
- import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
2
- import { RulePreset } from '@eslint-react/kit';
3
-
4
- type MessageID$2 = "missingDestructuring" | "invalidSetterNaming";
5
-
6
- type MessageID$1 = "useJsxFileExtension" | "useNonJsxFileExtension";
7
-
8
- type MessageID = "filenameEmpty" | "filenameInvalid";
1
+ import * as _eslint_react_kit0 from "@eslint-react/kit";
9
2
 
3
+ //#region src/index.d.ts
10
4
  declare const _default: {
11
- configs: {
12
- recommended: {
13
- plugins: {
14
- "react-naming-convention": {
15
- readonly meta: {
16
- readonly name: string;
17
- readonly version: string;
18
- };
19
- readonly rules: {
20
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
21
- allowAllCaps?: boolean;
22
- allowLeadingUnderscore?: boolean;
23
- allowNamespace?: boolean;
24
- excepts?: readonly string[];
25
- rule?: "CONSTANT_CASE" | "PascalCase";
26
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
27
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
28
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
29
- excepts?: readonly string[];
30
- extensions?: readonly string[];
31
- rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
32
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
33
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
34
- allow?: "always" | "as-needed";
35
- extensions?: readonly string[];
36
- ignoreFilesWithoutCode?: boolean;
37
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
38
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
39
- };
40
- };
41
- };
42
- name: string;
43
- rules: RulePreset;
44
- };
45
- "recommended-legacy": {
46
- plugins: string[];
47
- rules: RulePreset;
48
- };
49
- };
50
- meta: {
51
- readonly name: string;
52
- readonly version: string;
53
- };
54
- rules: {
55
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
56
- allowAllCaps?: boolean;
57
- allowLeadingUnderscore?: boolean;
58
- allowNamespace?: boolean;
59
- excepts?: readonly string[];
60
- rule?: "CONSTANT_CASE" | "PascalCase";
61
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
62
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
63
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
64
- excepts?: readonly string[];
65
- extensions?: readonly string[];
66
- rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
67
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
68
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
69
- allow?: "always" | "as-needed";
70
- extensions?: readonly string[];
71
- ignoreFilesWithoutCode?: boolean;
72
- } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
73
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
5
+ configs: {
6
+ recommended: {
7
+ plugins: {};
8
+ name?: string;
9
+ rules?: Record<string, _eslint_react_kit0.RuleConfig>;
10
+ settings?: _eslint_react_kit0.SettingsConfig;
74
11
  };
12
+ };
13
+ meta: {
14
+ name: string;
15
+ version: string;
16
+ };
17
+ rules: Record<string, _eslint_react_kit0.CompatibleRule>;
75
18
  };
76
-
77
- export { _default as default };
19
+ //#endregion
20
+ export { _default as default };
package/dist/index.js CHANGED
@@ -1,497 +1,463 @@
1
- import * as AST from '@eslint-react/ast';
2
- import * as ER2 from '@eslint-react/core';
3
- import { RegExp } from '@eslint-react/kit';
4
- import { getDocsUrl, getSettingsFromContext } from '@eslint-react/shared';
5
- import { ESLintUtils } from '@typescript-eslint/utils';
6
- import { identity, isObject } from '@eslint-react/eff';
7
- import { AST_NODE_TYPES } from '@typescript-eslint/types';
8
- import { match, P } from 'ts-pattern';
9
- import path from 'node:path';
10
- import { snakeCase, pascalCase, camelCase, kebabCase } from 'string-ts';
1
+ import { getConfigAdapters, getDocsUrl } from "@eslint-react/shared";
2
+ import * as AST from "@eslint-react/ast";
3
+ import * as ER from "@eslint-react/core";
4
+ import { RE_CAMEL_CASE, RE_CONSTANT_CASE, RE_KEBAB_CASE, RE_PASCAL_CASE, RE_SNAKE_CASE, toRegExp } from "@eslint-react/kit";
5
+ import { ESLintUtils } from "@typescript-eslint/utils";
6
+ import { identity, isObject } from "@eslint-react/eff";
7
+ import { AST_NODE_TYPES } from "@typescript-eslint/types";
8
+ import { P, match } from "ts-pattern";
9
+ import path from "node:path";
10
+ import { camelCase, kebabCase, pascalCase, snakeCase } from "string-ts";
11
11
 
12
+ //#region rolldown:runtime
12
13
  var __defProp = Object.defineProperty;
13
- var __export = (target, all) => {
14
- for (var name3 in all)
15
- __defProp(target, name3, { get: all[name3], enumerable: true });
14
+ var __export = (all) => {
15
+ let target = {};
16
+ for (var name$2 in all) __defProp(target, name$2, {
17
+ get: all[name$2],
18
+ enumerable: true
19
+ });
20
+ return target;
16
21
  };
17
22
 
18
- // src/configs/recommended.ts
19
- var recommended_exports = {};
20
- __export(recommended_exports, {
21
- name: () => name,
22
- rules: () => rules
23
+ //#endregion
24
+ //#region src/configs/recommended.ts
25
+ var recommended_exports = /* @__PURE__ */ __export({
26
+ name: () => name$1,
27
+ rules: () => rules
23
28
  });
24
- var name = "react-naming-convention/recommended";
25
- var rules = {
26
- "react-naming-convention/context-name": "warn"
27
- // "react-naming-convention/use-state": "warn",
28
- };
29
+ const name$1 = "react-naming-convention/recommended";
30
+ const rules = { "react-naming-convention/context-name": "warn" };
31
+
32
+ //#endregion
33
+ //#region package.json
34
+ var name = "eslint-plugin-react-naming-convention";
35
+ var version = "2.0.0-next.200";
29
36
 
30
- // package.json
31
- var name2 = "eslint-plugin-react-naming-convention";
32
- var version = "2.0.0-next.2";
33
- var createRule = ESLintUtils.RuleCreator(getDocsUrl("naming-convention"));
37
+ //#endregion
38
+ //#region src/utils/create-rule.ts
39
+ const createRule = ESLintUtils.RuleCreator(getDocsUrl("naming-convention"));
34
40
 
35
- // src/rules/component-name.ts
36
- var defaultOptions = [
37
- {
38
- allowAllCaps: false,
39
- excepts: [],
40
- rule: "PascalCase"
41
- }
42
- ];
43
- var schema = [
44
- {
45
- anyOf: [
46
- {
47
- type: "string",
48
- enum: ["PascalCase", "CONSTANT_CASE"]
49
- },
50
- {
51
- type: "object",
52
- additionalProperties: false,
53
- properties: {
54
- allowAllCaps: { type: "boolean" },
55
- /**
56
- * @todo Remove in the next major version
57
- * @deprecated
58
- */
59
- allowLeadingUnderscore: { type: "boolean" },
60
- /**
61
- * @todo Remove in the next major version
62
- * @deprecated
63
- */
64
- allowNamespace: { type: "boolean" },
65
- excepts: {
66
- type: "array",
67
- items: { type: "string", format: "regex" }
68
- },
69
- rule: {
70
- type: "string",
71
- enum: ["PascalCase", "CONSTANT_CASE"]
72
- }
73
- }
74
- }
75
- ]
76
- }
77
- ];
78
- var RULE_NAME = "component-name";
41
+ //#endregion
42
+ //#region src/rules/component-name.ts
43
+ const defaultOptions$2 = [{
44
+ allowAllCaps: false,
45
+ excepts: [],
46
+ rule: "PascalCase"
47
+ }];
48
+ const schema$2 = [{ anyOf: [{
49
+ type: "string",
50
+ enum: ["PascalCase", "CONSTANT_CASE"]
51
+ }, {
52
+ type: "object",
53
+ additionalProperties: false,
54
+ properties: {
55
+ allowAllCaps: { type: "boolean" },
56
+ excepts: {
57
+ type: "array",
58
+ items: {
59
+ type: "string",
60
+ format: "regex"
61
+ }
62
+ },
63
+ rule: {
64
+ type: "string",
65
+ enum: ["PascalCase", "CONSTANT_CASE"]
66
+ }
67
+ }
68
+ }] }];
69
+ const RULE_NAME$4 = "component-name";
79
70
  var component_name_default = createRule({
80
- meta: {
81
- type: "problem",
82
- defaultOptions: [...defaultOptions],
83
- docs: {
84
- description: "Enforces naming conventions for components."
85
- },
86
- messages: {
87
- invalid: "A component name '{{name}}' does not match {{rule}}."
88
- },
89
- schema
90
- },
91
- name: RULE_NAME,
92
- create,
93
- defaultOptions
71
+ meta: {
72
+ type: "problem",
73
+ defaultOptions: [...defaultOptions$2],
74
+ docs: { description: "Enforces naming conventions for components." },
75
+ messages: { invalidComponentName: "A component name '{{name}}' does not match {{rule}}." },
76
+ schema: schema$2
77
+ },
78
+ name: RULE_NAME$4,
79
+ create: create$4,
80
+ defaultOptions: defaultOptions$2
94
81
  });
95
- function create(context) {
96
- const options = normalizeOptions(context.options);
97
- const { rule } = options;
98
- const collector = ER2.useComponentCollector(context);
99
- const collectorLegacy = ER2.useComponentCollectorLegacy();
100
- return {
101
- ...collector.listeners,
102
- ...collectorLegacy.listeners,
103
- "Program:exit"(program) {
104
- const functionComponents = collector.ctx.getAllComponents(program);
105
- const classComponents = collectorLegacy.ctx.getAllComponents(program);
106
- for (const { node: component } of functionComponents.values()) {
107
- const id = AST.getFunctionId(component);
108
- if (id?.name == null) continue;
109
- const name3 = id.name;
110
- if (isValidName(name3, options)) return;
111
- context.report({
112
- messageId: "invalid",
113
- node: id,
114
- data: { name: name3, rule }
115
- });
116
- }
117
- for (const { node: component } of classComponents.values()) {
118
- const id = AST.getClassId(component);
119
- if (id?.name == null) continue;
120
- const name3 = id.name;
121
- if (isValidName(name3, options)) continue;
122
- context.report({
123
- messageId: "invalid",
124
- node: id,
125
- data: { name: name3, rule }
126
- });
127
- }
128
- }
129
- };
82
+ function create$4(context) {
83
+ const options = normalizeOptions(context.options);
84
+ const { rule } = options;
85
+ const collector = ER.useComponentCollector(context);
86
+ const collectorLegacy = ER.useComponentCollectorLegacy();
87
+ return {
88
+ ...collector.listeners,
89
+ ...collectorLegacy.listeners,
90
+ "Program:exit"(program) {
91
+ const functionComponents = collector.ctx.getAllComponents(program);
92
+ const classComponents = collectorLegacy.ctx.getAllComponents(program);
93
+ for (const { node: component } of functionComponents.values()) {
94
+ const id = AST.getFunctionId(component);
95
+ if (id?.name == null) continue;
96
+ const name$2 = id.name;
97
+ if (isValidName(name$2, options)) continue;
98
+ context.report({
99
+ messageId: "invalidComponentName",
100
+ node: id,
101
+ data: {
102
+ name: name$2,
103
+ rule
104
+ }
105
+ });
106
+ }
107
+ for (const { node: component } of classComponents.values()) {
108
+ const id = AST.getClassId(component);
109
+ if (id?.name == null) continue;
110
+ const name$2 = id.name;
111
+ if (isValidName(name$2, options)) continue;
112
+ context.report({
113
+ messageId: "invalidComponentName",
114
+ node: id,
115
+ data: {
116
+ name: name$2,
117
+ rule
118
+ }
119
+ });
120
+ }
121
+ }
122
+ };
130
123
  }
131
124
  function normalizeOptions(options) {
132
- const opts = options[0];
133
- const defaultOpts = defaultOptions[0];
134
- if (opts == null) return defaultOpts;
135
- return {
136
- ...defaultOpts,
137
- ...typeof opts === "string" ? { rule: opts } : {
138
- ...opts,
139
- excepts: opts.excepts?.map((s) => RegExp.toRegExp(s)) ?? []
140
- }
141
- };
125
+ const opts = options[0];
126
+ const defaultOpts = defaultOptions$2[0];
127
+ if (opts == null) return defaultOpts;
128
+ return {
129
+ ...defaultOpts,
130
+ ...typeof opts === "string" ? { rule: opts } : {
131
+ ...opts,
132
+ excepts: opts.excepts?.map((s) => toRegExp(s)) ?? []
133
+ }
134
+ };
142
135
  }
143
- function isValidName(name3, options) {
144
- if (name3 == null) return true;
145
- if (options.excepts.some((regex) => regex.test(name3))) return true;
146
- const normalized = name3.split(".").at(-1) ?? name3;
147
- switch (options.rule) {
148
- case "CONSTANT_CASE":
149
- return RegExp.CONSTANT_CASE.test(normalized);
150
- case "PascalCase":
151
- if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
152
- return options.allowAllCaps;
153
- }
154
- return RegExp.PASCAL_CASE.test(normalized);
155
- }
136
+ function isValidName(name$2, options) {
137
+ if (name$2 == null) return true;
138
+ if (options.excepts.some((regex) => regex.test(name$2))) return true;
139
+ const normalized = name$2.split(".").at(-1) ?? name$2;
140
+ switch (options.rule) {
141
+ case "CONSTANT_CASE": return RE_CONSTANT_CASE.test(normalized);
142
+ case "PascalCase":
143
+ if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) return options.allowAllCaps;
144
+ return RE_PASCAL_CASE.test(normalized);
145
+ }
156
146
  }
157
- var RULE_NAME2 = "context-name";
147
+
148
+ //#endregion
149
+ //#region src/rules/context-name.ts
150
+ const RULE_NAME$3 = "context-name";
158
151
  var context_name_default = createRule({
159
- meta: {
160
- type: "problem",
161
- docs: {
162
- description: "Enforces context name to be a valid component name with the suffix `Context`."
163
- },
164
- messages: {
165
- invalid: "A context name must be a valid component name with the suffix 'Context'."
166
- },
167
- schema: []
168
- },
169
- name: RULE_NAME2,
170
- create: create2,
171
- defaultOptions: []
152
+ meta: {
153
+ type: "problem",
154
+ docs: { description: "Enforces context name to be a valid component name with the suffix `Context`." },
155
+ messages: { invalidContextName: "A context name must be a valid component name with the suffix 'Context'." },
156
+ schema: []
157
+ },
158
+ name: RULE_NAME$3,
159
+ create: create$3,
160
+ defaultOptions: []
172
161
  });
173
- function create2(context) {
174
- if (!context.sourceCode.text.includes("createContext")) return {};
175
- return {
176
- CallExpression(node) {
177
- if (!ER2.isCreateContextCall(context, node)) return;
178
- const id = ER2.getInstanceId(node);
179
- if (id == null) return;
180
- const name3 = match(id).with({ type: AST_NODE_TYPES.Identifier, name: P.select() }, identity).with({ type: AST_NODE_TYPES.MemberExpression, property: { name: P.select(P.string) } }, identity).otherwise(() => null);
181
- if (name3 != null && ER2.isComponentName(name3) && name3.endsWith("Context")) return;
182
- context.report({
183
- messageId: "invalid",
184
- node: id
185
- });
186
- }
187
- };
162
+ function create$3(context) {
163
+ if (!context.sourceCode.text.includes("createContext")) return {};
164
+ return { CallExpression(node) {
165
+ if (!ER.isCreateContextCall(context, node)) return;
166
+ const id = ER.getInstanceId(node);
167
+ if (id == null) return;
168
+ const name$2 = match(id).with({
169
+ type: AST_NODE_TYPES.Identifier,
170
+ name: P.select()
171
+ }, identity).with({
172
+ type: AST_NODE_TYPES.MemberExpression,
173
+ property: { name: P.select(P.string) }
174
+ }, identity).otherwise(() => null);
175
+ if (name$2 != null && ER.isComponentName(name$2) && name$2.endsWith("Context")) return;
176
+ context.report({
177
+ messageId: "invalidContextName",
178
+ node: id
179
+ });
180
+ } };
188
181
  }
189
- var RULE_NAME3 = "filename";
190
- var defaultOptions2 = [
191
- {
192
- excepts: ["^index$"],
193
- extensions: [".js", ".jsx", ".ts", ".tsx"],
194
- rule: "PascalCase"
195
- }
196
- ];
197
- var schema2 = [
198
- {
199
- anyOf: [
200
- {
201
- type: "string",
202
- enum: ["PascalCase", "camelCase", "kebab-case", "snake_case"]
203
- },
204
- {
205
- type: "object",
206
- additionalProperties: false,
207
- properties: {
208
- excepts: {
209
- type: "array",
210
- items: { type: "string", format: "regex" }
211
- },
212
- extensions: {
213
- type: "array",
214
- items: { type: "string" },
215
- uniqueItems: true
216
- },
217
- rule: {
218
- type: "string",
219
- enum: ["PascalCase", "camelCase", "kebab-case", "snake_case"]
220
- }
221
- }
222
- }
223
- ]
224
- }
225
- ];
182
+
183
+ //#endregion
184
+ //#region src/rules/filename.ts
185
+ const RULE_NAME$2 = "filename";
186
+ const defaultOptions$1 = [{
187
+ excepts: [
188
+ "index",
189
+ String.raw`/^_/`,
190
+ String.raw`/^\$/`,
191
+ String.raw`/^[0-9]+$/`,
192
+ String.raw`/^\[[^\]]+\]$/`
193
+ ],
194
+ rule: "PascalCase"
195
+ }];
196
+ const schema$1 = [{ anyOf: [{
197
+ type: "string",
198
+ enum: [
199
+ "PascalCase",
200
+ "camelCase",
201
+ "kebab-case",
202
+ "snake_case"
203
+ ]
204
+ }, {
205
+ type: "object",
206
+ additionalProperties: false,
207
+ properties: {
208
+ excepts: {
209
+ type: "array",
210
+ items: {
211
+ type: "string",
212
+ format: "regex"
213
+ }
214
+ },
215
+ extensions: {
216
+ type: "array",
217
+ items: { type: "string" },
218
+ uniqueItems: true
219
+ },
220
+ rule: {
221
+ type: "string",
222
+ enum: [
223
+ "PascalCase",
224
+ "camelCase",
225
+ "kebab-case",
226
+ "snake_case"
227
+ ]
228
+ }
229
+ }
230
+ }] }];
226
231
  var filename_default = createRule({
227
- meta: {
228
- type: "problem",
229
- defaultOptions: [...defaultOptions2],
230
- docs: {
231
- description: "Enforces consistent file naming conventions."
232
- },
233
- messages: {
234
- filenameEmpty: "A file must have non-empty name.",
235
- filenameInvalid: "A file with name '{{name}}' does not match {{rule}}. Rename it to '{{suggestion}}'."
236
- },
237
- schema: schema2
238
- },
239
- name: RULE_NAME3,
240
- create: create3,
241
- defaultOptions: defaultOptions2
232
+ meta: {
233
+ type: "problem",
234
+ defaultOptions: [...defaultOptions$1],
235
+ docs: { description: "Enforces consistent file naming conventions." },
236
+ messages: {
237
+ empty: "A file must have non-empty name.",
238
+ invalidCase: "A file with name '{{name}}' does not match {{rule}}. Rename it to '{{suggestion}}'."
239
+ },
240
+ schema: schema$1
241
+ },
242
+ name: RULE_NAME$2,
243
+ create: create$2,
244
+ defaultOptions: defaultOptions$1
242
245
  });
243
- function create3(context) {
244
- const options = context.options[0] ?? defaultOptions2[0];
245
- const rule = typeof options === "string" ? options : options.rule ?? "PascalCase";
246
- const excepts = typeof options === "string" ? [] : options.excepts ?? [];
247
- function validate(name3, casing = rule, ignores = excepts) {
248
- const shouldIgnore = ignores.map((s) => RegExp.toRegExp(s)).some((pattern) => pattern.test(name3));
249
- if (shouldIgnore) return true;
250
- return match(casing).with("PascalCase", () => RegExp.PASCAL_CASE.test(name3)).with("camelCase", () => RegExp.CAMEL_CASE.test(name3)).with("kebab-case", () => RegExp.KEBAB_CASE.test(name3)).with("snake_case", () => RegExp.SNAKE_CASE.test(name3)).exhaustive();
251
- }
252
- function getSuggestion(name3, casing = rule) {
253
- return match(casing).with("PascalCase", () => pascalCase(name3)).with("camelCase", () => camelCase(name3)).with("kebab-case", () => kebabCase(name3)).with("snake_case", () => snakeCase(name3)).exhaustive();
254
- }
255
- return {
256
- Program(node) {
257
- const [basename = "", ...rest] = path.basename(context.filename).split(".");
258
- if (basename.length === 0) {
259
- context.report({ messageId: "filenameEmpty", node });
260
- return;
261
- }
262
- if (validate(basename)) {
263
- return;
264
- }
265
- context.report({
266
- messageId: "filenameInvalid",
267
- node,
268
- data: {
269
- name: context.filename,
270
- rule,
271
- suggestion: [getSuggestion(basename), ...rest].join(".")
272
- }
273
- });
274
- }
275
- };
246
+ function create$2(context) {
247
+ const options = context.options[0] ?? defaultOptions$1[0];
248
+ const rule = typeof options === "string" ? options : options.rule ?? "PascalCase";
249
+ const excepts = typeof options === "string" ? [] : (options.excepts ?? []).map((s) => toRegExp(s));
250
+ function validate(name$2, casing = rule, ignores = excepts) {
251
+ if (ignores.some((pattern) => pattern.test(name$2))) return true;
252
+ const filteredName = name$2.match(/[\w.-]/gu)?.join("") ?? "";
253
+ if (filteredName.length === 0) return true;
254
+ 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();
255
+ }
256
+ function getSuggestion(name$2, casing = rule) {
257
+ return match(casing).with("PascalCase", () => pascalCase(name$2)).with("camelCase", () => camelCase(name$2)).with("kebab-case", () => kebabCase(name$2)).with("snake_case", () => snakeCase(name$2)).exhaustive();
258
+ }
259
+ return { Program(node) {
260
+ const [basename = "", ...rest] = path.basename(context.filename).split(".");
261
+ if (basename.length === 0) {
262
+ context.report({
263
+ messageId: "empty",
264
+ node
265
+ });
266
+ return;
267
+ }
268
+ if (validate(basename)) return;
269
+ context.report({
270
+ messageId: "invalidCase",
271
+ node,
272
+ data: {
273
+ name: context.filename,
274
+ rule,
275
+ suggestion: [getSuggestion(basename), ...rest].join(".")
276
+ }
277
+ });
278
+ } };
276
279
  }
277
- var RULE_NAME4 = "filename-extension";
278
- var defaultOptions3 = [{
279
- allow: "as-needed",
280
- extensions: [".jsx", ".tsx"],
281
- ignoreFilesWithoutCode: false
280
+
281
+ //#endregion
282
+ //#region src/rules/filename-extension.ts
283
+ const RULE_NAME$1 = "filename-extension";
284
+ const defaultOptions = [{
285
+ allow: "as-needed",
286
+ extensions: [".jsx", ".tsx"],
287
+ ignoreFilesWithoutCode: false
282
288
  }];
283
- var schema3 = [
284
- {
285
- anyOf: [
286
- {
287
- type: "string",
288
- enum: ["always", "as-needed"]
289
- },
290
- {
291
- type: "object",
292
- additionalProperties: false,
293
- properties: {
294
- allow: {
295
- type: "string",
296
- enum: ["always", "as-needed"]
297
- },
298
- extensions: {
299
- type: "array",
300
- items: {
301
- type: "string"
302
- },
303
- uniqueItems: true
304
- },
305
- ignoreFilesWithoutCode: {
306
- type: "boolean"
307
- }
308
- }
309
- }
310
- ]
311
- }
312
- ];
289
+ const schema = [{ anyOf: [{
290
+ type: "string",
291
+ enum: ["always", "as-needed"]
292
+ }, {
293
+ type: "object",
294
+ additionalProperties: false,
295
+ properties: {
296
+ allow: {
297
+ type: "string",
298
+ enum: ["always", "as-needed"]
299
+ },
300
+ extensions: {
301
+ type: "array",
302
+ items: { type: "string" },
303
+ uniqueItems: true
304
+ },
305
+ ignoreFilesWithoutCode: { type: "boolean" }
306
+ }
307
+ }] }];
313
308
  var filename_extension_default = createRule({
314
- meta: {
315
- type: "problem",
316
- defaultOptions: [...defaultOptions3],
317
- docs: {
318
- description: "Enforces consistent file naming conventions."
319
- },
320
- messages: {
321
- useJsxFileExtension: "Use {{extensions}} file extension for JSX files.",
322
- useNonJsxFileExtension: "Do not use {{extensions}} file extension for files without JSX."
323
- },
324
- schema: schema3
325
- },
326
- name: RULE_NAME4,
327
- create: create4,
328
- defaultOptions: defaultOptions3
309
+ meta: {
310
+ type: "problem",
311
+ defaultOptions: [...defaultOptions],
312
+ docs: { description: "Enforces consistent file naming conventions." },
313
+ messages: {
314
+ missingJSXExtension: "Use {{extensions}} file extension for JSX files.",
315
+ unnecessaryJSXExtension: "Do not use {{extensions}} file extension for files without JSX."
316
+ },
317
+ schema
318
+ },
319
+ name: RULE_NAME$1,
320
+ create: create$1,
321
+ defaultOptions
329
322
  });
330
- function create4(context) {
331
- const options = context.options[0] ?? defaultOptions3[0];
332
- const allow = isObject(options) ? options.allow : options;
333
- const extensions = isObject(options) && "extensions" in options ? options.extensions : defaultOptions3[0].extensions;
334
- const extensionsString = extensions.map((ext) => `'${ext}'`).join(", ");
335
- const filename = context.filename;
336
- let hasJSXNode = false;
337
- return {
338
- JSXElement() {
339
- hasJSXNode = true;
340
- },
341
- JSXFragment() {
342
- hasJSXNode = true;
343
- },
344
- "Program:exit"(program) {
345
- const fileNameExt = filename.slice(filename.lastIndexOf("."));
346
- const isJSXExt = extensions.includes(fileNameExt);
347
- if (hasJSXNode && !isJSXExt) {
348
- context.report({
349
- messageId: "useJsxFileExtension",
350
- node: program,
351
- data: {
352
- extensions: extensionsString
353
- }
354
- });
355
- return;
356
- }
357
- const hasCode = program.body.length > 0;
358
- const ignoreFilesWithoutCode = isObject(options) && options.ignoreFilesWithoutCode === true;
359
- if (!hasCode && ignoreFilesWithoutCode) {
360
- return;
361
- }
362
- if (!hasJSXNode && isJSXExt && allow === "as-needed") {
363
- context.report({
364
- messageId: "useNonJsxFileExtension",
365
- node: program,
366
- data: {
367
- extensions: extensionsString
368
- }
369
- });
370
- }
371
- }
372
- };
323
+ function create$1(context) {
324
+ const options = context.options[0] ?? defaultOptions[0];
325
+ const allow = isObject(options) ? options.allow : options;
326
+ const extensions = isObject(options) && "extensions" in options ? options.extensions : defaultOptions[0].extensions;
327
+ const extensionsString = extensions.map((ext) => `'${ext}'`).join(", ");
328
+ const filename = context.filename;
329
+ let hasJSXNode = false;
330
+ return {
331
+ JSXElement() {
332
+ hasJSXNode = true;
333
+ },
334
+ JSXFragment() {
335
+ hasJSXNode = true;
336
+ },
337
+ "Program:exit"(program) {
338
+ const fileNameExt = filename.slice(filename.lastIndexOf("."));
339
+ const isJSXExt = extensions.includes(fileNameExt);
340
+ if (hasJSXNode && !isJSXExt) {
341
+ context.report({
342
+ messageId: "missingJSXExtension",
343
+ node: program,
344
+ data: { extensions: extensionsString }
345
+ });
346
+ return;
347
+ }
348
+ const hasCode = program.body.length > 0;
349
+ const ignoreFilesWithoutCode = isObject(options) && options.ignoreFilesWithoutCode === true;
350
+ if (!hasCode && ignoreFilesWithoutCode) return;
351
+ if (!hasJSXNode && isJSXExt && allow === "as-needed") context.report({
352
+ messageId: "unnecessaryJSXExtension",
353
+ node: program,
354
+ data: { extensions: extensionsString }
355
+ });
356
+ }
357
+ };
373
358
  }
374
- var RULE_NAME5 = "use-state";
375
- var RULE_FEATURES = [];
359
+
360
+ //#endregion
361
+ //#region src/rules/use-state.ts
362
+ const RULE_NAME = "use-state";
363
+ const RULE_FEATURES = [];
376
364
  var use_state_default = createRule({
377
- meta: {
378
- type: "problem",
379
- docs: {
380
- description: "Enforces destructuring and symmetric naming of `useState` hook value and setter.",
381
- [Symbol.for("rule_features")]: RULE_FEATURES
382
- },
383
- messages: {
384
- invalidSetterNaming: "The setter should be named 'set' followed by the capitalized state variable name, e.g., 'setState' for 'state'.",
385
- missingDestructuring: "useState should be destructured into a value and setter pair, e.g., const [state, setState] = useState(...)."
386
- },
387
- schema: []
388
- },
389
- name: RULE_NAME5,
390
- create: create5,
391
- defaultOptions: []
365
+ meta: {
366
+ type: "problem",
367
+ docs: {
368
+ description: "Enforces destructuring and symmetric naming of `useState` hook value and setter.",
369
+ [Symbol.for("rule_features")]: RULE_FEATURES
370
+ },
371
+ messages: {
372
+ invalidAssignment: "useState should be destructured into a value and setter pair, e.g., const [state, setState] = useState(...).",
373
+ invalidSetterName: "The setter should be named 'set' followed by the capitalized state variable name, e.g., 'setState' for 'state'."
374
+ },
375
+ schema: []
376
+ },
377
+ name: RULE_NAME,
378
+ create,
379
+ defaultOptions: []
392
380
  });
393
- function create5(context) {
394
- const alias = getSettingsFromContext(context).additionalHooks.useState ?? [];
395
- const isUseStateCall = ER2.isReactHookCallWithNameAlias(context, "useState", alias);
396
- return {
397
- CallExpression(node) {
398
- if (!isUseStateCall(node)) {
399
- return;
400
- }
401
- if (node.parent.type !== AST_NODE_TYPES.VariableDeclarator) {
402
- context.report({
403
- messageId: "missingDestructuring",
404
- node
405
- });
406
- return;
407
- }
408
- const id = ER2.getInstanceId(node);
409
- if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
410
- context.report({
411
- messageId: "missingDestructuring",
412
- node: id ?? node
413
- });
414
- return;
415
- }
416
- const [value, setter] = id.elements;
417
- if (value == null || setter == null) {
418
- context.report({
419
- messageId: "missingDestructuring",
420
- node: id
421
- });
422
- return;
423
- }
424
- const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => null);
425
- if (setterName == null || !setterName.startsWith("set")) {
426
- context.report({
427
- messageId: "invalidSetterNaming",
428
- node: setter
429
- });
430
- return;
431
- }
432
- const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, ({ name: name3 }) => snakeCase(name3)).with({ type: AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
433
- const values = properties.reduce((acc, prop) => {
434
- if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) {
435
- return [...acc, prop.key.name];
436
- }
437
- return acc;
438
- }, []);
439
- return values.join("_");
440
- }).otherwise(() => null);
441
- if (valueName == null) {
442
- context.report({
443
- messageId: "invalidSetterNaming",
444
- node: value
445
- });
446
- return;
447
- }
448
- if (snakeCase(setterName) !== `set_${valueName}`) {
449
- context.report({
450
- messageId: "invalidSetterNaming",
451
- node: setter
452
- });
453
- return;
454
- }
455
- }
456
- };
381
+ function create(context) {
382
+ return { CallExpression(node) {
383
+ if (!ER.isUseStateCall(node)) return;
384
+ if (node.parent.type !== AST_NODE_TYPES.VariableDeclarator) {
385
+ context.report({
386
+ messageId: "invalidAssignment",
387
+ node
388
+ });
389
+ return;
390
+ }
391
+ const id = ER.getInstanceId(node);
392
+ if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
393
+ context.report({
394
+ messageId: "invalidAssignment",
395
+ node: id ?? node
396
+ });
397
+ return;
398
+ }
399
+ const [value, setter] = id.elements;
400
+ if (value == null || setter == null) {
401
+ context.report({
402
+ messageId: "invalidAssignment",
403
+ node: id
404
+ });
405
+ return;
406
+ }
407
+ const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id$1) => id$1.name).otherwise(() => null);
408
+ if (setterName == null || !setterName.startsWith("set")) {
409
+ context.report({
410
+ messageId: "invalidSetterName",
411
+ node: setter
412
+ });
413
+ return;
414
+ }
415
+ const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, ({ name: name$2 }) => snakeCase(name$2)).with({ type: AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
416
+ return properties.reduce((acc, prop) => {
417
+ if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) return [...acc, prop.key.name];
418
+ return acc;
419
+ }, []).join("_");
420
+ }).otherwise(() => null);
421
+ if (valueName == null) {
422
+ context.report({
423
+ messageId: "invalidSetterName",
424
+ node: value
425
+ });
426
+ return;
427
+ }
428
+ if (snakeCase(setterName) !== `set_${valueName}`) {
429
+ context.report({
430
+ messageId: "invalidSetterName",
431
+ node: setter
432
+ });
433
+ return;
434
+ }
435
+ } };
457
436
  }
458
437
 
459
- // src/plugin.ts
460
- var plugin = {
461
- meta: {
462
- name: name2,
463
- version
464
- },
465
- rules: {
466
- ["component-name"]: component_name_default,
467
- ["context-name"]: context_name_default,
468
- ["filename"]: filename_default,
469
- ["filename-extension"]: filename_extension_default,
470
- ["use-state"]: use_state_default
471
- }
438
+ //#endregion
439
+ //#region src/plugin.ts
440
+ const plugin = {
441
+ meta: {
442
+ name,
443
+ version
444
+ },
445
+ rules: {
446
+ ["component-name"]: component_name_default,
447
+ ["context-name"]: context_name_default,
448
+ ["filename"]: filename_default,
449
+ ["filename-extension"]: filename_extension_default,
450
+ ["use-state"]: use_state_default
451
+ }
472
452
  };
473
453
 
474
- // src/index.ts
475
- function makeConfig(config) {
476
- return {
477
- ...config,
478
- plugins: {
479
- "react-naming-convention": plugin
480
- }
481
- };
482
- }
483
- function makeLegacyConfig({ rules: rules2 }) {
484
- return {
485
- plugins: ["react-naming-convention"],
486
- rules: rules2
487
- };
488
- }
489
- var index_default = {
490
- ...plugin,
491
- configs: {
492
- ["recommended"]: makeConfig(recommended_exports),
493
- ["recommended-legacy"]: makeLegacyConfig(recommended_exports)
494
- }
454
+ //#endregion
455
+ //#region src/index.ts
456
+ const { toFlatConfig } = getConfigAdapters("react-naming-convention", plugin);
457
+ var src_default = {
458
+ ...plugin,
459
+ configs: { ["recommended"]: toFlatConfig(recommended_exports) }
495
460
  };
496
461
 
497
- export { index_default as default };
462
+ //#endregion
463
+ export { src_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-naming-convention",
3
- "version": "2.0.0-next.2",
3
+ "version": "2.0.0-next.200",
4
4
  "description": "ESLint React's ESLint plugin for naming convention related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -35,46 +35,37 @@
35
35
  "./package.json"
36
36
  ],
37
37
  "dependencies": {
38
- "@typescript-eslint/scope-manager": "^8.30.1",
39
- "@typescript-eslint/type-utils": "^8.30.1",
40
- "@typescript-eslint/types": "^8.30.1",
41
- "@typescript-eslint/utils": "^8.30.1",
38
+ "@typescript-eslint/scope-manager": "^8.44.1",
39
+ "@typescript-eslint/type-utils": "^8.44.1",
40
+ "@typescript-eslint/types": "^8.44.1",
41
+ "@typescript-eslint/utils": "^8.44.1",
42
42
  "string-ts": "^2.2.1",
43
- "ts-pattern": "^5.7.0",
44
- "@eslint-react/ast": "2.0.0-next.2",
45
- "@eslint-react/kit": "2.0.0-next.2",
46
- "@eslint-react/eff": "2.0.0-next.2",
47
- "@eslint-react/core": "2.0.0-next.2",
48
- "@eslint-react/shared": "2.0.0-next.2",
49
- "@eslint-react/var": "2.0.0-next.2"
43
+ "ts-pattern": "^5.8.0",
44
+ "@eslint-react/ast": "2.0.0-next.200",
45
+ "@eslint-react/core": "2.0.0-next.200",
46
+ "@eslint-react/eff": "2.0.0-next.200",
47
+ "@eslint-react/kit": "2.0.0-next.200",
48
+ "@eslint-react/shared": "2.0.0-next.200",
49
+ "@eslint-react/var": "2.0.0-next.200"
50
50
  },
51
51
  "devDependencies": {
52
- "@types/react": "^19.1.2",
53
- "@types/react-dom": "^19.1.2",
54
- "tsup": "^8.4.0",
52
+ "@types/react": "^19.1.13",
53
+ "@types/react-dom": "^19.1.9",
54
+ "tsdown": "^0.15.4",
55
55
  "@local/configs": "0.0.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "eslint": "^9.24.0",
59
- "typescript": "^4.9.5 || ^5.4.5"
60
- },
61
- "peerDependenciesMeta": {
62
- "eslint": {
63
- "optional": false
64
- },
65
- "typescript": {
66
- "optional": true
67
- }
58
+ "eslint": "^9.36.0",
59
+ "typescript": "^5.9.2"
68
60
  },
69
61
  "engines": {
70
- "bun": ">=1.0.15",
71
62
  "node": ">=20.19.0"
72
63
  },
73
64
  "publishConfig": {
74
65
  "access": "public"
75
66
  },
76
67
  "scripts": {
77
- "build": "tsup --dts-resolve",
68
+ "build": "tsdown",
78
69
  "lint:publish": "publint",
79
70
  "lint:ts": "tsc --noEmit"
80
71
  }