eslint-plugin-react-naming-convention 2.0.0-next.0 → 2.0.0-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/dist/index.js CHANGED
@@ -1,39 +1,13 @@
1
- 'use strict';
2
-
3
- var AST = require('@eslint-react/ast');
4
- var ER2 = require('@eslint-react/core');
5
- var kit = require('@eslint-react/kit');
6
- var shared = require('@eslint-react/shared');
7
- var utils = require('@typescript-eslint/utils');
8
- var eff = require('@eslint-react/eff');
9
- var types = require('@typescript-eslint/types');
10
- var tsPattern = require('ts-pattern');
11
- var path = require('path');
12
- var stringTs = require('string-ts');
13
-
14
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
-
16
- function _interopNamespace(e) {
17
- if (e && e.__esModule) return e;
18
- var n = Object.create(null);
19
- if (e) {
20
- Object.keys(e).forEach(function (k) {
21
- if (k !== 'default') {
22
- var d = Object.getOwnPropertyDescriptor(e, k);
23
- Object.defineProperty(n, k, d.get ? d : {
24
- enumerable: true,
25
- get: function () { return e[k]; }
26
- });
27
- }
28
- });
29
- }
30
- n.default = e;
31
- return Object.freeze(n);
32
- }
33
-
34
- var AST__namespace = /*#__PURE__*/_interopNamespace(AST);
35
- var ER2__namespace = /*#__PURE__*/_interopNamespace(ER2);
36
- var path__default = /*#__PURE__*/_interopDefault(path);
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';
37
11
 
38
12
  var __defProp = Object.defineProperty;
39
13
  var __export = (target, all) => {
@@ -55,8 +29,8 @@ var rules = {
55
29
 
56
30
  // package.json
57
31
  var name2 = "eslint-plugin-react-naming-convention";
58
- var version = "2.0.0-next.0";
59
- var createRule = utils.ESLintUtils.RuleCreator(shared.getDocsUrl("naming-convention"));
32
+ var version = "2.0.0-next.10";
33
+ var createRule = ESLintUtils.RuleCreator(getDocsUrl("naming-convention"));
60
34
 
61
35
  // src/rules/component-name.ts
62
36
  var defaultOptions = [
@@ -121,8 +95,8 @@ var component_name_default = createRule({
121
95
  function create(context) {
122
96
  const options = normalizeOptions(context.options);
123
97
  const { rule } = options;
124
- const collector = ER2__namespace.useComponentCollector(context);
125
- const collectorLegacy = ER2__namespace.useComponentCollectorLegacy();
98
+ const collector = ER2.useComponentCollector(context);
99
+ const collectorLegacy = ER2.useComponentCollectorLegacy();
126
100
  return {
127
101
  ...collector.listeners,
128
102
  ...collectorLegacy.listeners,
@@ -130,7 +104,7 @@ function create(context) {
130
104
  const functionComponents = collector.ctx.getAllComponents(program);
131
105
  const classComponents = collectorLegacy.ctx.getAllComponents(program);
132
106
  for (const { node: component } of functionComponents.values()) {
133
- const id = AST__namespace.getFunctionId(component);
107
+ const id = AST.getFunctionId(component);
134
108
  if (id?.name == null) continue;
135
109
  const name3 = id.name;
136
110
  if (isValidName(name3, options)) return;
@@ -141,7 +115,7 @@ function create(context) {
141
115
  });
142
116
  }
143
117
  for (const { node: component } of classComponents.values()) {
144
- const id = AST__namespace.getClassId(component);
118
+ const id = AST.getClassId(component);
145
119
  if (id?.name == null) continue;
146
120
  const name3 = id.name;
147
121
  if (isValidName(name3, options)) continue;
@@ -162,7 +136,7 @@ function normalizeOptions(options) {
162
136
  ...defaultOpts,
163
137
  ...typeof opts === "string" ? { rule: opts } : {
164
138
  ...opts,
165
- excepts: opts.excepts?.map((s) => kit.RegExp.toRegExp(s)) ?? []
139
+ excepts: opts.excepts?.map((s) => RegExp.toRegExp(s)) ?? []
166
140
  }
167
141
  };
168
142
  }
@@ -172,12 +146,12 @@ function isValidName(name3, options) {
172
146
  const normalized = name3.split(".").at(-1) ?? name3;
173
147
  switch (options.rule) {
174
148
  case "CONSTANT_CASE":
175
- return kit.RegExp.CONSTANT_CASE.test(normalized);
149
+ return RegExp.CONSTANT_CASE.test(normalized);
176
150
  case "PascalCase":
177
151
  if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
178
152
  return options.allowAllCaps;
179
153
  }
180
- return kit.RegExp.PASCAL_CASE.test(normalized);
154
+ return RegExp.PASCAL_CASE.test(normalized);
181
155
  }
182
156
  }
183
157
  var RULE_NAME2 = "context-name";
@@ -200,11 +174,11 @@ function create2(context) {
200
174
  if (!context.sourceCode.text.includes("createContext")) return {};
201
175
  return {
202
176
  CallExpression(node) {
203
- if (!ER2__namespace.isCreateContextCall(context, node)) return;
204
- const id = ER2__namespace.getInstanceId(node);
177
+ if (!ER2.isCreateContextCall(context, node)) return;
178
+ const id = ER2.getInstanceId(node);
205
179
  if (id == null) return;
206
- 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(() => null);
207
- if (name3 != null && ER2__namespace.isComponentName(name3) && name3.endsWith("Context")) 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;
208
182
  context.report({
209
183
  messageId: "invalid",
210
184
  node: id
@@ -271,16 +245,16 @@ function create3(context) {
271
245
  const rule = typeof options === "string" ? options : options.rule ?? "PascalCase";
272
246
  const excepts = typeof options === "string" ? [] : options.excepts ?? [];
273
247
  function validate(name3, casing = rule, ignores = excepts) {
274
- const shouldIgnore = ignores.map((s) => kit.RegExp.toRegExp(s)).some((pattern) => pattern.test(name3));
248
+ const shouldIgnore = ignores.map((s) => RegExp.toRegExp(s)).some((pattern) => pattern.test(name3));
275
249
  if (shouldIgnore) return true;
276
- return tsPattern.match(casing).with("PascalCase", () => kit.RegExp.PASCAL_CASE.test(name3)).with("camelCase", () => kit.RegExp.CAMEL_CASE.test(name3)).with("kebab-case", () => kit.RegExp.KEBAB_CASE.test(name3)).with("snake_case", () => kit.RegExp.SNAKE_CASE.test(name3)).exhaustive();
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();
277
251
  }
278
252
  function getSuggestion(name3, casing = rule) {
279
- return tsPattern.match(casing).with("PascalCase", () => stringTs.pascalCase(name3)).with("camelCase", () => stringTs.camelCase(name3)).with("kebab-case", () => stringTs.kebabCase(name3)).with("snake_case", () => stringTs.snakeCase(name3)).exhaustive();
253
+ return match(casing).with("PascalCase", () => pascalCase(name3)).with("camelCase", () => camelCase(name3)).with("kebab-case", () => kebabCase(name3)).with("snake_case", () => snakeCase(name3)).exhaustive();
280
254
  }
281
255
  return {
282
256
  Program(node) {
283
- const [basename = "", ...rest] = path__default.default.basename(context.filename).split(".");
257
+ const [basename = "", ...rest] = path.basename(context.filename).split(".");
284
258
  if (basename.length === 0) {
285
259
  context.report({ messageId: "filenameEmpty", node });
286
260
  return;
@@ -355,8 +329,8 @@ var filename_extension_default = createRule({
355
329
  });
356
330
  function create4(context) {
357
331
  const options = context.options[0] ?? defaultOptions3[0];
358
- const allow = eff.isObject(options) ? options.allow : options;
359
- const extensions = eff.isObject(options) && "extensions" in options ? options.extensions : defaultOptions3[0].extensions;
332
+ const allow = isObject(options) ? options.allow : options;
333
+ const extensions = isObject(options) && "extensions" in options ? options.extensions : defaultOptions3[0].extensions;
360
334
  const extensionsString = extensions.map((ext) => `'${ext}'`).join(", ");
361
335
  const filename = context.filename;
362
336
  let hasJSXNode = false;
@@ -381,7 +355,7 @@ function create4(context) {
381
355
  return;
382
356
  }
383
357
  const hasCode = program.body.length > 0;
384
- const ignoreFilesWithoutCode = eff.isObject(options) && options.ignoreFilesWithoutCode === true;
358
+ const ignoreFilesWithoutCode = isObject(options) && options.ignoreFilesWithoutCode === true;
385
359
  if (!hasCode && ignoreFilesWithoutCode) {
386
360
  return;
387
361
  }
@@ -417,22 +391,22 @@ var use_state_default = createRule({
417
391
  defaultOptions: []
418
392
  });
419
393
  function create5(context) {
420
- const alias = shared.getSettingsFromContext(context).additionalHooks.useState ?? [];
421
- const isUseStateCall = ER2__namespace.isReactHookCallWithNameAlias(context, "useState", alias);
394
+ const alias = getSettingsFromContext(context).additionalHooks.useState ?? [];
395
+ const isUseStateCall = ER2.isReactHookCallWithNameAlias(context, "useState", alias);
422
396
  return {
423
397
  CallExpression(node) {
424
398
  if (!isUseStateCall(node)) {
425
399
  return;
426
400
  }
427
- if (node.parent.type !== types.AST_NODE_TYPES.VariableDeclarator) {
401
+ if (node.parent.type !== AST_NODE_TYPES.VariableDeclarator) {
428
402
  context.report({
429
403
  messageId: "missingDestructuring",
430
404
  node
431
405
  });
432
406
  return;
433
407
  }
434
- const id = ER2__namespace.getInstanceId(node);
435
- if (id?.type !== types.AST_NODE_TYPES.ArrayPattern) {
408
+ const id = ER2.getInstanceId(node);
409
+ if (id?.type !== AST_NODE_TYPES.ArrayPattern) {
436
410
  context.report({
437
411
  messageId: "missingDestructuring",
438
412
  node: id ?? node
@@ -447,7 +421,7 @@ function create5(context) {
447
421
  });
448
422
  return;
449
423
  }
450
- const setterName = tsPattern.match(setter).with({ type: types.AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => null);
424
+ const setterName = match(setter).with({ type: AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => null);
451
425
  if (setterName == null || !setterName.startsWith("set")) {
452
426
  context.report({
453
427
  messageId: "invalidSetterNaming",
@@ -455,9 +429,9 @@ function create5(context) {
455
429
  });
456
430
  return;
457
431
  }
458
- const valueName = tsPattern.match(value).with({ type: types.AST_NODE_TYPES.Identifier }, ({ name: name3 }) => stringTs.snakeCase(name3)).with({ type: types.AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
432
+ const valueName = match(value).with({ type: AST_NODE_TYPES.Identifier }, ({ name: name3 }) => snakeCase(name3)).with({ type: AST_NODE_TYPES.ObjectPattern }, ({ properties }) => {
459
433
  const values = properties.reduce((acc, prop) => {
460
- if (prop.type === types.AST_NODE_TYPES.Property && prop.key.type === types.AST_NODE_TYPES.Identifier) {
434
+ if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) {
461
435
  return [...acc, prop.key.name];
462
436
  }
463
437
  return acc;
@@ -471,7 +445,7 @@ function create5(context) {
471
445
  });
472
446
  return;
473
447
  }
474
- if (stringTs.snakeCase(setterName) !== `set_${valueName}`) {
448
+ if (snakeCase(setterName) !== `set_${valueName}`) {
475
449
  context.report({
476
450
  messageId: "invalidSetterNaming",
477
451
  node: setter
@@ -520,4 +494,4 @@ var index_default = {
520
494
  }
521
495
  };
522
496
 
523
- module.exports = index_default;
497
+ export { index_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.0",
3
+ "version": "2.0.0-next.10",
4
4
  "description": "ESLint React's ESLint plugin for naming convention related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -22,39 +22,31 @@
22
22
  "license": "MIT",
23
23
  "author": "Rel1cx<rel1cx@proton.me>",
24
24
  "sideEffects": false,
25
+ "type": "module",
25
26
  "exports": {
26
27
  ".": {
27
- "import": {
28
- "types": "./dist/index.d.mts",
29
- "default": "./dist/index.mjs"
30
- },
31
- "require": {
32
- "types": "./dist/index.d.ts",
33
- "default": "./dist/index.js"
34
- }
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
35
30
  },
36
31
  "./package.json": "./package.json"
37
32
  },
38
- "main": "dist/index.js",
39
- "module": "dist/index.mjs",
40
- "types": "dist/index.d.ts",
41
33
  "files": [
42
34
  "dist",
43
35
  "./package.json"
44
36
  ],
45
37
  "dependencies": {
46
- "@typescript-eslint/scope-manager": "^8.30.1",
47
- "@typescript-eslint/type-utils": "^8.30.1",
48
- "@typescript-eslint/types": "^8.30.1",
49
- "@typescript-eslint/utils": "^8.30.1",
38
+ "@typescript-eslint/scope-manager": "^8.31.1",
39
+ "@typescript-eslint/type-utils": "^8.31.1",
40
+ "@typescript-eslint/types": "^8.31.1",
41
+ "@typescript-eslint/utils": "^8.31.1",
50
42
  "string-ts": "^2.2.1",
51
43
  "ts-pattern": "^5.7.0",
52
- "@eslint-react/core": "2.0.0-next.0",
53
- "@eslint-react/ast": "2.0.0-next.0",
54
- "@eslint-react/eff": "2.0.0-next.0",
55
- "@eslint-react/kit": "2.0.0-next.0",
56
- "@eslint-react/shared": "2.0.0-next.0",
57
- "@eslint-react/var": "2.0.0-next.0"
44
+ "@eslint-react/ast": "2.0.0-next.10",
45
+ "@eslint-react/core": "2.0.0-next.10",
46
+ "@eslint-react/kit": "2.0.0-next.10",
47
+ "@eslint-react/shared": "2.0.0-next.10",
48
+ "@eslint-react/eff": "2.0.0-next.10",
49
+ "@eslint-react/var": "2.0.0-next.10"
58
50
  },
59
51
  "devDependencies": {
60
52
  "@types/react": "^19.1.2",
@@ -63,7 +55,7 @@
63
55
  "@local/configs": "0.0.0"
64
56
  },
65
57
  "peerDependencies": {
66
- "eslint": "^9.24.0",
58
+ "eslint": "^9.25.1",
67
59
  "typescript": "^4.9.5 || ^5.4.5"
68
60
  },
69
61
  "peerDependenciesMeta": {
package/dist/index.d.mts DELETED
@@ -1,77 +0,0 @@
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";
9
-
10
- 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>;
74
- };
75
- };
76
-
77
- export { _default as default };
package/dist/index.mjs DELETED
@@ -1,497 +0,0 @@
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';
11
-
12
- var __defProp = Object.defineProperty;
13
- var __export = (target, all) => {
14
- for (var name3 in all)
15
- __defProp(target, name3, { get: all[name3], enumerable: true });
16
- };
17
-
18
- // src/configs/recommended.ts
19
- var recommended_exports = {};
20
- __export(recommended_exports, {
21
- name: () => name,
22
- rules: () => rules
23
- });
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
-
30
- // package.json
31
- var name2 = "eslint-plugin-react-naming-convention";
32
- var version = "2.0.0-next.0";
33
- var createRule = ESLintUtils.RuleCreator(getDocsUrl("naming-convention"));
34
-
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";
79
- 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
94
- });
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
- };
130
- }
131
- 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
- };
142
- }
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
- }
156
- }
157
- var RULE_NAME2 = "context-name";
158
- 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: []
172
- });
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
- };
188
- }
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
- ];
226
- 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
242
- });
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
- };
276
- }
277
- var RULE_NAME4 = "filename-extension";
278
- var defaultOptions3 = [{
279
- allow: "as-needed",
280
- extensions: [".jsx", ".tsx"],
281
- ignoreFilesWithoutCode: false
282
- }];
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
- ];
313
- 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
329
- });
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
- };
373
- }
374
- var RULE_NAME5 = "use-state";
375
- var RULE_FEATURES = [];
376
- 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: []
392
- });
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
- };
457
- }
458
-
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
- }
472
- };
473
-
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
- }
495
- };
496
-
497
- export { index_default as default };