eslint-plugin-react-naming-convention 1.29.1-beta.3 → 1.29.1-beta.7

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/dist/index.d.mts CHANGED
@@ -1,11 +1,9 @@
1
1
  import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
2
2
  import { RulePreset } from '@eslint-react/shared';
3
3
 
4
- type MessageID$2 = "useJsxFileExtension" | "useJsxFileExtensionAsNeeded";
4
+ type MessageID$1 = "useJsxFileExtension" | "useNonJsxFileExtension";
5
5
 
6
- type MessageID$1 = "filenameCaseMismatch" | "filenameEmpty";
7
-
8
- type MessageID = "usePascalCase" | "useConstantCase";
6
+ type MessageID = "filenameEmpty" | "filenameInvalid";
9
7
 
10
8
  declare const _default: {
11
9
  configs: {
@@ -17,25 +15,25 @@ declare const _default: {
17
15
  readonly version: string;
18
16
  };
19
17
  readonly rules: {
20
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("CONSTANT_CASE" | "PascalCase") | {
18
+ readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
21
19
  allowAllCaps?: boolean;
22
20
  allowLeadingUnderscore?: boolean;
23
21
  allowNamespace?: boolean;
24
22
  excepts?: readonly string[];
25
23
  rule?: "CONSTANT_CASE" | "PascalCase";
26
24
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
27
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"contextName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
28
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
25
+ readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
26
+ readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
29
27
  excepts?: readonly string[];
30
28
  extensions?: readonly string[];
31
29
  rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
32
30
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
33
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, readonly [("always" | "as-needed") | {
31
+ readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
34
32
  allow?: "always" | "as-needed";
35
33
  extensions?: readonly string[];
36
34
  ignoreFilesWithoutCode?: boolean;
37
35
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
38
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"badValueOrSetterName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
36
+ readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
39
37
  };
40
38
  };
41
39
  };
@@ -52,25 +50,25 @@ declare const _default: {
52
50
  readonly version: string;
53
51
  };
54
52
  rules: {
55
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("CONSTANT_CASE" | "PascalCase") | {
53
+ readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
56
54
  allowAllCaps?: boolean;
57
55
  allowLeadingUnderscore?: boolean;
58
56
  allowNamespace?: boolean;
59
57
  excepts?: readonly string[];
60
58
  rule?: "CONSTANT_CASE" | "PascalCase";
61
59
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
62
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"contextName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
63
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
60
+ readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
61
+ readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
64
62
  excepts?: readonly string[];
65
63
  extensions?: readonly string[];
66
64
  rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
67
65
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
68
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, readonly [("always" | "as-needed") | {
66
+ readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
69
67
  allow?: "always" | "as-needed";
70
68
  extensions?: readonly string[];
71
69
  ignoreFilesWithoutCode?: boolean;
72
70
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
73
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"badValueOrSetterName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
71
+ readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
74
72
  };
75
73
  };
76
74
 
package/dist/index.d.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
2
2
  import { RulePreset } from '@eslint-react/shared';
3
3
 
4
- type MessageID$2 = "useJsxFileExtension" | "useJsxFileExtensionAsNeeded";
4
+ type MessageID$1 = "useJsxFileExtension" | "useNonJsxFileExtension";
5
5
 
6
- type MessageID$1 = "filenameCaseMismatch" | "filenameEmpty";
7
-
8
- type MessageID = "usePascalCase" | "useConstantCase";
6
+ type MessageID = "filenameEmpty" | "filenameInvalid";
9
7
 
10
8
  declare const _default: {
11
9
  configs: {
@@ -17,25 +15,25 @@ declare const _default: {
17
15
  readonly version: string;
18
16
  };
19
17
  readonly rules: {
20
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("CONSTANT_CASE" | "PascalCase") | {
18
+ readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
21
19
  allowAllCaps?: boolean;
22
20
  allowLeadingUnderscore?: boolean;
23
21
  allowNamespace?: boolean;
24
22
  excepts?: readonly string[];
25
23
  rule?: "CONSTANT_CASE" | "PascalCase";
26
24
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
27
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"contextName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
28
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
25
+ readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
26
+ readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
29
27
  excepts?: readonly string[];
30
28
  extensions?: readonly string[];
31
29
  rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
32
30
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
33
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, readonly [("always" | "as-needed") | {
31
+ readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
34
32
  allow?: "always" | "as-needed";
35
33
  extensions?: readonly string[];
36
34
  ignoreFilesWithoutCode?: boolean;
37
35
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
38
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"badValueOrSetterName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
36
+ readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
39
37
  };
40
38
  };
41
39
  };
@@ -52,25 +50,25 @@ declare const _default: {
52
50
  readonly version: string;
53
51
  };
54
52
  rules: {
55
- readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("CONSTANT_CASE" | "PascalCase") | {
53
+ readonly "component-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", readonly [("CONSTANT_CASE" | "PascalCase") | {
56
54
  allowAllCaps?: boolean;
57
55
  allowLeadingUnderscore?: boolean;
58
56
  allowNamespace?: boolean;
59
57
  excepts?: readonly string[];
60
58
  rule?: "CONSTANT_CASE" | "PascalCase";
61
59
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
62
- readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"contextName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
63
- readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
60
+ readonly "context-name": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
61
+ readonly filename: _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, readonly [("PascalCase" | "camelCase" | "kebab-case" | "snake_case") | {
64
62
  excepts?: readonly string[];
65
63
  extensions?: readonly string[];
66
64
  rule?: "PascalCase" | "camelCase" | "kebab-case" | "snake_case";
67
65
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
68
- readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, readonly [("always" | "as-needed") | {
66
+ readonly "filename-extension": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, readonly [("always" | "as-needed") | {
69
67
  allow?: "always" | "as-needed";
70
68
  extensions?: readonly string[];
71
69
  ignoreFilesWithoutCode?: boolean;
72
70
  } | undefined], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
73
- readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"badValueOrSetterName", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
71
+ readonly "use-state": _typescript_eslint_utils_ts_eslint.RuleModule<"invalid", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
74
72
  };
75
73
  };
76
74
 
package/dist/index.js CHANGED
@@ -2,11 +2,10 @@
2
2
 
3
3
  var AST = require('@eslint-react/ast');
4
4
  var core = require('@eslint-react/core');
5
- var eff = require('@eslint-react/eff');
6
- var JSX = require('@eslint-react/jsx');
7
5
  var shared = require('@eslint-react/shared');
8
- var tsPattern = require('ts-pattern');
6
+ var eff = require('@eslint-react/eff');
9
7
  var types = require('@typescript-eslint/types');
8
+ var tsPattern = require('ts-pattern');
10
9
  var path = require('path');
11
10
  var stringTs = require('string-ts');
12
11
 
@@ -31,7 +30,6 @@ function _interopNamespace(e) {
31
30
  }
32
31
 
33
32
  var AST__namespace = /*#__PURE__*/_interopNamespace(AST);
34
- var JSX__namespace = /*#__PURE__*/_interopNamespace(JSX);
35
33
  var path__default = /*#__PURE__*/_interopDefault(path);
36
34
 
37
35
  var __defProp = Object.defineProperty;
@@ -54,16 +52,13 @@ var rules = {
54
52
 
55
53
  // package.json
56
54
  var name2 = "eslint-plugin-react-naming-convention";
57
- var version = "1.29.1-beta.3";
55
+ var version = "1.29.1-beta.7";
58
56
  var createRule = shared.createRuleForPlugin("naming-convention");
59
57
 
60
58
  // src/rules/component-name.ts
61
- var RULE_NAME = "component-name";
62
59
  var defaultOptions = [
63
60
  {
64
61
  allowAllCaps: false,
65
- allowLeadingUnderscore: false,
66
- allowNamespace: false,
67
62
  excepts: [],
68
63
  rule: "PascalCase"
69
64
  }
@@ -80,7 +75,15 @@ var schema = [
80
75
  additionalProperties: false,
81
76
  properties: {
82
77
  allowAllCaps: { type: "boolean" },
78
+ /**
79
+ * @todo Remove in the next major version
80
+ * @deprecated
81
+ */
83
82
  allowLeadingUnderscore: { type: "boolean" },
83
+ /**
84
+ * @todo Remove in the next major version
85
+ * @deprecated
86
+ */
84
87
  allowNamespace: { type: "boolean" },
85
88
  excepts: {
86
89
  type: "array",
@@ -95,82 +98,28 @@ var schema = [
95
98
  ]
96
99
  }
97
100
  ];
98
- function normalizeOptions(options) {
99
- const opts = options[0];
100
- if (opts == null) {
101
- return defaultOptions[0];
102
- }
103
- if (typeof opts === "string") {
104
- return { ...defaultOptions[0], rule: opts };
105
- }
106
- return {
107
- ...opts,
108
- excepts: opts.excepts?.map((pattern) => new RegExp(pattern, "u")) ?? []
109
- };
110
- }
111
- function getViolationMessage(name3, options) {
112
- if (name3 == null) return eff._;
113
- const {
114
- allowAllCaps = false,
115
- allowLeadingUnderscore = false,
116
- allowNamespace = false,
117
- excepts,
118
- rule
119
- } = options;
120
- if (excepts.some((regex) => regex.test(name3))) {
121
- return eff._;
122
- }
123
- let normalized = name3.normalize("NFKD").replace(/[\u0300-\u036F]/g, "");
124
- normalized = normalized.split(".").at(-1) ?? normalized;
125
- if (allowNamespace) {
126
- normalized = normalized.replace(":", "");
127
- }
128
- if (allowLeadingUnderscore) {
129
- normalized = normalized.replace(/^_/, "");
130
- }
131
- return tsPattern.match(rule).with("CONSTANT_CASE", () => shared.RE_CONSTANT_CASE.test(normalized) ? eff._ : "useConstantCase").with("PascalCase", () => {
132
- if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
133
- return allowAllCaps ? eff._ : "usePascalCase";
134
- }
135
- return shared.RE_PASCAL_CASE.test(normalized) ? eff._ : "usePascalCase";
136
- }).otherwise(() => eff._);
137
- }
101
+ var RULE_NAME = "component-name";
138
102
  var component_name_default = createRule({
139
103
  meta: {
140
104
  type: "problem",
141
105
  defaultOptions: [...defaultOptions],
142
106
  docs: {
143
- description: "enforce component naming convention to 'PascalCase' or 'CONSTANT_CASE'"
107
+ description: "enforce naming convention for components"
144
108
  },
145
109
  messages: {
146
- useConstantCase: "Component name '{{name}}' must be in CONSTANT_CASE.",
147
- usePascalCase: "Component name '{{name}}' must be in PascalCase."
110
+ invalid: "A component name '{{name}}' does not match {{rule}}."
148
111
  },
149
112
  schema
150
113
  },
151
114
  name: RULE_NAME,
152
115
  create(context) {
153
116
  const options = normalizeOptions(context.options);
117
+ const { rule } = options;
154
118
  const collector = core.useComponentCollector(context);
155
119
  const collectorLegacy = core.useComponentCollectorLegacy();
156
120
  return {
157
121
  ...collector.listeners,
158
122
  ...collectorLegacy.listeners,
159
- JSXOpeningElement(node) {
160
- const name3 = JSX__namespace.getElementName(node.parent);
161
- if (/^[a-z]/u.test(name3)) {
162
- return;
163
- }
164
- const violation = getViolationMessage(name3, options);
165
- if (violation == null) return;
166
- context.report({
167
- messageId: violation,
168
- node,
169
- data: {
170
- name: name3
171
- }
172
- });
173
- },
174
123
  "Program:exit"(node) {
175
124
  const functionComponents = collector.ctx.getAllComponents(node);
176
125
  const classComponents = collectorLegacy.ctx.getAllComponents(node);
@@ -178,28 +127,22 @@ var component_name_default = createRule({
178
127
  const id = AST__namespace.getFunctionIdentifier(component);
179
128
  if (id?.name == null) continue;
180
129
  const name3 = id.name;
181
- const violation = getViolationMessage(name3, options);
182
- if (violation == null) continue;
130
+ if (isValidName(name3, options)) return;
183
131
  context.report({
184
- messageId: violation,
132
+ messageId: "invalid",
185
133
  node: id,
186
- data: {
187
- name: name3
188
- }
134
+ data: { name: name3, rule }
189
135
  });
190
136
  }
191
137
  for (const { node: component } of classComponents.values()) {
192
138
  const id = AST__namespace.getClassIdentifier(component);
193
139
  if (id?.name == null) continue;
194
140
  const name3 = id.name;
195
- const violation = getViolationMessage(name3, options);
196
- if (violation == null) continue;
141
+ if (isValidName(name3, options)) continue;
197
142
  context.report({
198
- messageId: violation,
143
+ messageId: "invalid",
199
144
  node: id,
200
- data: {
201
- case: options.rule
202
- }
145
+ data: { name: name3, rule }
203
146
  });
204
147
  }
205
148
  }
@@ -207,15 +150,41 @@ var component_name_default = createRule({
207
150
  },
208
151
  defaultOptions
209
152
  });
153
+ function normalizeOptions(options) {
154
+ const opts = options[0];
155
+ const defaultOpts = defaultOptions[0];
156
+ if (opts == null) return defaultOpts;
157
+ return {
158
+ ...defaultOpts,
159
+ ...typeof opts === "string" ? { rule: opts } : {
160
+ ...opts,
161
+ excepts: opts.excepts?.map((pattern) => new RegExp(pattern, "u")) ?? []
162
+ }
163
+ };
164
+ }
165
+ function isValidName(name3, options) {
166
+ if (name3 == null) return true;
167
+ if (options.excepts.some((regex) => regex.test(name3))) return true;
168
+ const normalized = name3.split(".").at(-1) ?? name3;
169
+ switch (options.rule) {
170
+ case "CONSTANT_CASE":
171
+ return shared.RE_CONSTANT_CASE.test(normalized);
172
+ case "PascalCase":
173
+ if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
174
+ return options.allowAllCaps;
175
+ }
176
+ return shared.RE_PASCAL_CASE.test(normalized);
177
+ }
178
+ }
210
179
  var RULE_NAME2 = "context-name";
211
180
  var context_name_default = createRule({
212
181
  meta: {
213
182
  type: "problem",
214
183
  docs: {
215
- description: "enforce context name to end with 'Context'"
184
+ description: "enforce context name to be a valid component name with the suffix 'Context'"
216
185
  },
217
186
  messages: {
218
- contextName: "Context name must end with 'Context'."
187
+ invalid: "A context name must be a valid component name with the suffix 'Context'."
219
188
  },
220
189
  schema: []
221
190
  },
@@ -228,10 +197,9 @@ var context_name_default = createRule({
228
197
  const id = core.getInstanceId(node);
229
198
  if (id == null) return;
230
199
  const name3 = tsPattern.match(id).with({ type: types.AST_NODE_TYPES.Identifier, name: tsPattern.P.select() }, eff.identity).with({ type: types.AST_NODE_TYPES.MemberExpression, property: { name: tsPattern.P.select(tsPattern.P.string) } }, eff.identity).otherwise(() => eff._);
231
- if (name3 == null) return;
232
- if (name3.endsWith("Context")) return;
200
+ if (name3 != null && /^[A-Z]/u.test(name3) && name3.endsWith("Context")) return;
233
201
  context.report({
234
- messageId: "contextName",
202
+ messageId: "invalid",
235
203
  node: id
236
204
  });
237
205
  }
@@ -284,8 +252,8 @@ var filename_default = createRule({
284
252
  description: "enforce naming convention for JSX filenames"
285
253
  },
286
254
  messages: {
287
- filenameCaseMismatch: "A file with name '{{name}}' does not match {{rule}}. Should rename to '{{suggestion}}'.",
288
- filenameEmpty: "A file must have non-empty name."
255
+ filenameEmpty: "A file must have non-empty name.",
256
+ filenameInvalid: "A file with name '{{name}}' does not match {{rule}}. Rename it to '{{suggestion}}'."
289
257
  },
290
258
  schema: schema2
291
259
  },
@@ -313,7 +281,7 @@ var filename_default = createRule({
313
281
  return;
314
282
  }
315
283
  context.report({
316
- messageId: "filenameCaseMismatch",
284
+ messageId: "filenameInvalid",
317
285
  node,
318
286
  data: {
319
287
  name: context.filename,
@@ -371,7 +339,7 @@ var filename_extension_default = createRule({
371
339
  },
372
340
  messages: {
373
341
  useJsxFileExtension: "Use {{extensions}} file extension for JSX files.",
374
- useJsxFileExtensionAsNeeded: "Do not use {{extensions}} file extension for files without JSX."
342
+ useNonJsxFileExtension: "Do not use {{extensions}} file extension for files without JSX."
375
343
  },
376
344
  schema: schema3
377
345
  },
@@ -410,7 +378,7 @@ var filename_extension_default = createRule({
410
378
  }
411
379
  if (!hasJSXNode && isJSXExt && allow === "as-needed") {
412
380
  context.report({
413
- messageId: "useJsxFileExtensionAsNeeded",
381
+ messageId: "useNonJsxFileExtension",
414
382
  node,
415
383
  data: {
416
384
  extensions: extensionsString
@@ -434,7 +402,7 @@ var use_state_default = createRule({
434
402
  [Symbol.for("rule_features")]: RULE_FEATURES
435
403
  },
436
404
  messages: {
437
- badValueOrSetterName: "An useState call is not destructured into value + setter pair."
405
+ invalid: "An useState call is not destructured into value + setter pair."
438
406
  },
439
407
  schema: []
440
408
  },
@@ -443,21 +411,21 @@ var use_state_default = createRule({
443
411
  return {
444
412
  "CallExpression[callee.name='useState']"(node) {
445
413
  if (node.parent.type !== types.AST_NODE_TYPES.VariableDeclarator) {
446
- context.report({ messageId: "badValueOrSetterName", node });
414
+ context.report({ messageId: "invalid", node });
447
415
  }
448
416
  const id = core.getInstanceId(node);
449
417
  if (id?.type !== types.AST_NODE_TYPES.ArrayPattern) {
450
- context.report({ messageId: "badValueOrSetterName", node });
418
+ context.report({ messageId: "invalid", node });
451
419
  return;
452
420
  }
453
421
  const [value, setter] = id.elements;
454
422
  if (value == null || setter == null) {
455
- context.report({ messageId: "badValueOrSetterName", node });
423
+ context.report({ messageId: "invalid", node });
456
424
  return;
457
425
  }
458
426
  const setterName = tsPattern.match(setter).with({ type: types.AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => eff._);
459
427
  if (setterName == null || !setterName.startsWith("set")) {
460
- context.report({ messageId: "badValueOrSetterName", node });
428
+ context.report({ messageId: "invalid", node });
461
429
  return;
462
430
  }
463
431
  const valueName = tsPattern.match(value).with({ type: types.AST_NODE_TYPES.Identifier }, (id2) => id2.name).with({ type: types.AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
@@ -470,7 +438,7 @@ var use_state_default = createRule({
470
438
  return values.join("_");
471
439
  }).otherwise(() => eff._);
472
440
  if (valueName == null || `set_${valueName}` !== stringTs.snakeCase(setterName)) {
473
- context.report({ messageId: "badValueOrSetterName", node });
441
+ context.report({ messageId: "invalid", node });
474
442
  return;
475
443
  }
476
444
  }
@@ -486,11 +454,11 @@ var plugin = {
486
454
  version
487
455
  },
488
456
  rules: {
489
- "component-name": component_name_default,
490
- "context-name": context_name_default,
491
- filename: filename_default,
492
- "filename-extension": filename_extension_default,
493
- "use-state": use_state_default
457
+ ["component-name"]: component_name_default,
458
+ ["context-name"]: context_name_default,
459
+ ["filename"]: filename_default,
460
+ ["filename-extension"]: filename_extension_default,
461
+ ["use-state"]: use_state_default
494
462
  }
495
463
  };
496
464
 
package/dist/index.mjs CHANGED
@@ -1,10 +1,9 @@
1
1
  import * as AST from '@eslint-react/ast';
2
2
  import { useComponentCollector, useComponentCollectorLegacy, isCreateContextCall, getInstanceId } from '@eslint-react/core';
3
+ import { createRuleForPlugin, RE_PASCAL_CASE, RE_CONSTANT_CASE, RE_CAMEL_CASE, RE_KEBAB_CASE, RE_SNAKE_CASE } from '@eslint-react/shared';
3
4
  import { identity, _, isObject } from '@eslint-react/eff';
4
- import * as JSX from '@eslint-react/jsx';
5
- import { createRuleForPlugin, RE_CONSTANT_CASE, RE_PASCAL_CASE, RE_CAMEL_CASE, RE_KEBAB_CASE, RE_SNAKE_CASE } from '@eslint-react/shared';
6
- import { match, P } from 'ts-pattern';
7
5
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
6
+ import { match, P } from 'ts-pattern';
8
7
  import path from 'node:path';
9
8
  import { snakeCase, pascalCase, camelCase, kebabCase } from 'string-ts';
10
9
 
@@ -28,16 +27,13 @@ var rules = {
28
27
 
29
28
  // package.json
30
29
  var name2 = "eslint-plugin-react-naming-convention";
31
- var version = "1.29.1-beta.3";
30
+ var version = "1.29.1-beta.7";
32
31
  var createRule = createRuleForPlugin("naming-convention");
33
32
 
34
33
  // src/rules/component-name.ts
35
- var RULE_NAME = "component-name";
36
34
  var defaultOptions = [
37
35
  {
38
36
  allowAllCaps: false,
39
- allowLeadingUnderscore: false,
40
- allowNamespace: false,
41
37
  excepts: [],
42
38
  rule: "PascalCase"
43
39
  }
@@ -54,7 +50,15 @@ var schema = [
54
50
  additionalProperties: false,
55
51
  properties: {
56
52
  allowAllCaps: { type: "boolean" },
53
+ /**
54
+ * @todo Remove in the next major version
55
+ * @deprecated
56
+ */
57
57
  allowLeadingUnderscore: { type: "boolean" },
58
+ /**
59
+ * @todo Remove in the next major version
60
+ * @deprecated
61
+ */
58
62
  allowNamespace: { type: "boolean" },
59
63
  excepts: {
60
64
  type: "array",
@@ -69,82 +73,28 @@ var schema = [
69
73
  ]
70
74
  }
71
75
  ];
72
- function normalizeOptions(options) {
73
- const opts = options[0];
74
- if (opts == null) {
75
- return defaultOptions[0];
76
- }
77
- if (typeof opts === "string") {
78
- return { ...defaultOptions[0], rule: opts };
79
- }
80
- return {
81
- ...opts,
82
- excepts: opts.excepts?.map((pattern) => new RegExp(pattern, "u")) ?? []
83
- };
84
- }
85
- function getViolationMessage(name3, options) {
86
- if (name3 == null) return _;
87
- const {
88
- allowAllCaps = false,
89
- allowLeadingUnderscore = false,
90
- allowNamespace = false,
91
- excepts,
92
- rule
93
- } = options;
94
- if (excepts.some((regex) => regex.test(name3))) {
95
- return _;
96
- }
97
- let normalized = name3.normalize("NFKD").replace(/[\u0300-\u036F]/g, "");
98
- normalized = normalized.split(".").at(-1) ?? normalized;
99
- if (allowNamespace) {
100
- normalized = normalized.replace(":", "");
101
- }
102
- if (allowLeadingUnderscore) {
103
- normalized = normalized.replace(/^_/, "");
104
- }
105
- return match(rule).with("CONSTANT_CASE", () => RE_CONSTANT_CASE.test(normalized) ? _ : "useConstantCase").with("PascalCase", () => {
106
- if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
107
- return allowAllCaps ? _ : "usePascalCase";
108
- }
109
- return RE_PASCAL_CASE.test(normalized) ? _ : "usePascalCase";
110
- }).otherwise(() => _);
111
- }
76
+ var RULE_NAME = "component-name";
112
77
  var component_name_default = createRule({
113
78
  meta: {
114
79
  type: "problem",
115
80
  defaultOptions: [...defaultOptions],
116
81
  docs: {
117
- description: "enforce component naming convention to 'PascalCase' or 'CONSTANT_CASE'"
82
+ description: "enforce naming convention for components"
118
83
  },
119
84
  messages: {
120
- useConstantCase: "Component name '{{name}}' must be in CONSTANT_CASE.",
121
- usePascalCase: "Component name '{{name}}' must be in PascalCase."
85
+ invalid: "A component name '{{name}}' does not match {{rule}}."
122
86
  },
123
87
  schema
124
88
  },
125
89
  name: RULE_NAME,
126
90
  create(context) {
127
91
  const options = normalizeOptions(context.options);
92
+ const { rule } = options;
128
93
  const collector = useComponentCollector(context);
129
94
  const collectorLegacy = useComponentCollectorLegacy();
130
95
  return {
131
96
  ...collector.listeners,
132
97
  ...collectorLegacy.listeners,
133
- JSXOpeningElement(node) {
134
- const name3 = JSX.getElementName(node.parent);
135
- if (/^[a-z]/u.test(name3)) {
136
- return;
137
- }
138
- const violation = getViolationMessage(name3, options);
139
- if (violation == null) return;
140
- context.report({
141
- messageId: violation,
142
- node,
143
- data: {
144
- name: name3
145
- }
146
- });
147
- },
148
98
  "Program:exit"(node) {
149
99
  const functionComponents = collector.ctx.getAllComponents(node);
150
100
  const classComponents = collectorLegacy.ctx.getAllComponents(node);
@@ -152,28 +102,22 @@ var component_name_default = createRule({
152
102
  const id = AST.getFunctionIdentifier(component);
153
103
  if (id?.name == null) continue;
154
104
  const name3 = id.name;
155
- const violation = getViolationMessage(name3, options);
156
- if (violation == null) continue;
105
+ if (isValidName(name3, options)) return;
157
106
  context.report({
158
- messageId: violation,
107
+ messageId: "invalid",
159
108
  node: id,
160
- data: {
161
- name: name3
162
- }
109
+ data: { name: name3, rule }
163
110
  });
164
111
  }
165
112
  for (const { node: component } of classComponents.values()) {
166
113
  const id = AST.getClassIdentifier(component);
167
114
  if (id?.name == null) continue;
168
115
  const name3 = id.name;
169
- const violation = getViolationMessage(name3, options);
170
- if (violation == null) continue;
116
+ if (isValidName(name3, options)) continue;
171
117
  context.report({
172
- messageId: violation,
118
+ messageId: "invalid",
173
119
  node: id,
174
- data: {
175
- case: options.rule
176
- }
120
+ data: { name: name3, rule }
177
121
  });
178
122
  }
179
123
  }
@@ -181,15 +125,41 @@ var component_name_default = createRule({
181
125
  },
182
126
  defaultOptions
183
127
  });
128
+ function normalizeOptions(options) {
129
+ const opts = options[0];
130
+ const defaultOpts = defaultOptions[0];
131
+ if (opts == null) return defaultOpts;
132
+ return {
133
+ ...defaultOpts,
134
+ ...typeof opts === "string" ? { rule: opts } : {
135
+ ...opts,
136
+ excepts: opts.excepts?.map((pattern) => new RegExp(pattern, "u")) ?? []
137
+ }
138
+ };
139
+ }
140
+ function isValidName(name3, options) {
141
+ if (name3 == null) return true;
142
+ if (options.excepts.some((regex) => regex.test(name3))) return true;
143
+ const normalized = name3.split(".").at(-1) ?? name3;
144
+ switch (options.rule) {
145
+ case "CONSTANT_CASE":
146
+ return RE_CONSTANT_CASE.test(normalized);
147
+ case "PascalCase":
148
+ if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
149
+ return options.allowAllCaps;
150
+ }
151
+ return RE_PASCAL_CASE.test(normalized);
152
+ }
153
+ }
184
154
  var RULE_NAME2 = "context-name";
185
155
  var context_name_default = createRule({
186
156
  meta: {
187
157
  type: "problem",
188
158
  docs: {
189
- description: "enforce context name to end with 'Context'"
159
+ description: "enforce context name to be a valid component name with the suffix 'Context'"
190
160
  },
191
161
  messages: {
192
- contextName: "Context name must end with 'Context'."
162
+ invalid: "A context name must be a valid component name with the suffix 'Context'."
193
163
  },
194
164
  schema: []
195
165
  },
@@ -202,10 +172,9 @@ var context_name_default = createRule({
202
172
  const id = getInstanceId(node);
203
173
  if (id == null) return;
204
174
  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(() => _);
205
- if (name3 == null) return;
206
- if (name3.endsWith("Context")) return;
175
+ if (name3 != null && /^[A-Z]/u.test(name3) && name3.endsWith("Context")) return;
207
176
  context.report({
208
- messageId: "contextName",
177
+ messageId: "invalid",
209
178
  node: id
210
179
  });
211
180
  }
@@ -258,8 +227,8 @@ var filename_default = createRule({
258
227
  description: "enforce naming convention for JSX filenames"
259
228
  },
260
229
  messages: {
261
- filenameCaseMismatch: "A file with name '{{name}}' does not match {{rule}}. Should rename to '{{suggestion}}'.",
262
- filenameEmpty: "A file must have non-empty name."
230
+ filenameEmpty: "A file must have non-empty name.",
231
+ filenameInvalid: "A file with name '{{name}}' does not match {{rule}}. Rename it to '{{suggestion}}'."
263
232
  },
264
233
  schema: schema2
265
234
  },
@@ -287,7 +256,7 @@ var filename_default = createRule({
287
256
  return;
288
257
  }
289
258
  context.report({
290
- messageId: "filenameCaseMismatch",
259
+ messageId: "filenameInvalid",
291
260
  node,
292
261
  data: {
293
262
  name: context.filename,
@@ -345,7 +314,7 @@ var filename_extension_default = createRule({
345
314
  },
346
315
  messages: {
347
316
  useJsxFileExtension: "Use {{extensions}} file extension for JSX files.",
348
- useJsxFileExtensionAsNeeded: "Do not use {{extensions}} file extension for files without JSX."
317
+ useNonJsxFileExtension: "Do not use {{extensions}} file extension for files without JSX."
349
318
  },
350
319
  schema: schema3
351
320
  },
@@ -384,7 +353,7 @@ var filename_extension_default = createRule({
384
353
  }
385
354
  if (!hasJSXNode && isJSXExt && allow === "as-needed") {
386
355
  context.report({
387
- messageId: "useJsxFileExtensionAsNeeded",
356
+ messageId: "useNonJsxFileExtension",
388
357
  node,
389
358
  data: {
390
359
  extensions: extensionsString
@@ -408,7 +377,7 @@ var use_state_default = createRule({
408
377
  [Symbol.for("rule_features")]: RULE_FEATURES
409
378
  },
410
379
  messages: {
411
- badValueOrSetterName: "An useState call is not destructured into value + setter pair."
380
+ invalid: "An useState call is not destructured into value + setter pair."
412
381
  },
413
382
  schema: []
414
383
  },
@@ -417,21 +386,21 @@ var use_state_default = createRule({
417
386
  return {
418
387
  "CallExpression[callee.name='useState']"(node) {
419
388
  if (node.parent.type !== AST_NODE_TYPES.VariableDeclarator) {
420
- context.report({ messageId: "badValueOrSetterName", node });
389
+ context.report({ messageId: "invalid", node });
421
390
  }
422
391
  const id = getInstanceId(node);
423
392
  if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
424
- context.report({ messageId: "badValueOrSetterName", node });
393
+ context.report({ messageId: "invalid", node });
425
394
  return;
426
395
  }
427
396
  const [value, setter] = id.elements;
428
397
  if (value == null || setter == null) {
429
- context.report({ messageId: "badValueOrSetterName", node });
398
+ context.report({ messageId: "invalid", node });
430
399
  return;
431
400
  }
432
401
  const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => _);
433
402
  if (setterName == null || !setterName.startsWith("set")) {
434
- context.report({ messageId: "badValueOrSetterName", node });
403
+ context.report({ messageId: "invalid", node });
435
404
  return;
436
405
  }
437
406
  const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, (id2) => id2.name).with({ type: AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
@@ -444,7 +413,7 @@ var use_state_default = createRule({
444
413
  return values.join("_");
445
414
  }).otherwise(() => _);
446
415
  if (valueName == null || `set_${valueName}` !== snakeCase(setterName)) {
447
- context.report({ messageId: "badValueOrSetterName", node });
416
+ context.report({ messageId: "invalid", node });
448
417
  return;
449
418
  }
450
419
  }
@@ -460,11 +429,11 @@ var plugin = {
460
429
  version
461
430
  },
462
431
  rules: {
463
- "component-name": component_name_default,
464
- "context-name": context_name_default,
465
- filename: filename_default,
466
- "filename-extension": filename_extension_default,
467
- "use-state": use_state_default
432
+ ["component-name"]: component_name_default,
433
+ ["context-name"]: context_name_default,
434
+ ["filename"]: filename_default,
435
+ ["filename-extension"]: filename_extension_default,
436
+ ["use-state"]: use_state_default
468
437
  }
469
438
  };
470
439
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-naming-convention",
3
- "version": "1.29.1-beta.3",
3
+ "version": "1.29.1-beta.7",
4
4
  "description": "ESLint React's ESLint plugin for naming convention related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -49,12 +49,12 @@
49
49
  "@typescript-eslint/utils": "^8.25.0",
50
50
  "string-ts": "^2.2.1",
51
51
  "ts-pattern": "^5.6.2",
52
- "@eslint-react/ast": "1.29.1-beta.3",
53
- "@eslint-react/core": "1.29.1-beta.3",
54
- "@eslint-react/eff": "1.29.1-beta.3",
55
- "@eslint-react/var": "1.29.1-beta.3",
56
- "@eslint-react/shared": "1.29.1-beta.3",
57
- "@eslint-react/jsx": "1.29.1-beta.3"
52
+ "@eslint-react/ast": "1.29.1-beta.7",
53
+ "@eslint-react/core": "1.29.1-beta.7",
54
+ "@eslint-react/eff": "1.29.1-beta.7",
55
+ "@eslint-react/jsx": "1.29.1-beta.7",
56
+ "@eslint-react/shared": "1.29.1-beta.7",
57
+ "@eslint-react/var": "1.29.1-beta.7"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/react": "^19.0.10",