@blumintinc/eslint-plugin-blumint 1.7.3 → 1.8.1

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.
Files changed (70) hide show
  1. package/README.md +83 -61
  2. package/lib/index.js +85 -1
  3. package/lib/rules/enforce-assert-throws.js +48 -3
  4. package/lib/rules/enforce-assertSafe-object-key.d.ts +2 -0
  5. package/lib/rules/enforce-assertSafe-object-key.js +284 -0
  6. package/lib/rules/enforce-centralized-mock-firestore.js +192 -14
  7. package/lib/rules/enforce-css-media-queries.d.ts +5 -0
  8. package/lib/rules/enforce-css-media-queries.js +87 -0
  9. package/lib/rules/enforce-dynamic-imports.d.ts +9 -0
  10. package/lib/rules/enforce-dynamic-imports.js +84 -0
  11. package/lib/rules/enforce-firestore-facade.js +8 -0
  12. package/lib/rules/enforce-id-capitalization.d.ts +6 -0
  13. package/lib/rules/enforce-id-capitalization.js +78 -0
  14. package/lib/rules/enforce-microdiff.d.ts +3 -0
  15. package/lib/rules/enforce-microdiff.js +379 -0
  16. package/lib/rules/enforce-mui-rounded-icons.d.ts +1 -0
  17. package/lib/rules/enforce-mui-rounded-icons.js +54 -0
  18. package/lib/rules/enforce-object-literal-as-const.d.ts +4 -0
  19. package/lib/rules/enforce-object-literal-as-const.js +88 -0
  20. package/lib/rules/enforce-positive-naming.d.ts +1 -0
  21. package/lib/rules/enforce-positive-naming.js +387 -0
  22. package/lib/rules/enforce-props-argument-name.d.ts +8 -0
  23. package/lib/rules/enforce-props-argument-name.js +182 -0
  24. package/lib/rules/enforce-react-type-naming.d.ts +3 -0
  25. package/lib/rules/enforce-react-type-naming.js +191 -0
  26. package/lib/rules/enforce-render-hits-memoization.js +155 -26
  27. package/lib/rules/enforce-singular-type-names.d.ts +2 -0
  28. package/lib/rules/enforce-singular-type-names.js +112 -0
  29. package/lib/rules/enforce-timestamp-now.d.ts +1 -0
  30. package/lib/rules/enforce-timestamp-now.js +223 -0
  31. package/lib/rules/enforce-verb-noun-naming.js +5 -2
  32. package/lib/rules/ensure-pointer-events-none.d.ts +1 -0
  33. package/lib/rules/ensure-pointer-events-none.js +211 -0
  34. package/lib/rules/extract-global-constants.d.ts +1 -1
  35. package/lib/rules/extract-global-constants.js +109 -1
  36. package/lib/rules/global-const-style.js +3 -2
  37. package/lib/rules/key-only-outermost-element.d.ts +3 -0
  38. package/lib/rules/key-only-outermost-element.js +152 -0
  39. package/lib/rules/no-always-true-false-conditions.d.ts +3 -0
  40. package/lib/rules/no-always-true-false-conditions.js +1221 -0
  41. package/lib/rules/no-circular-references.d.ts +1 -0
  42. package/lib/rules/no-circular-references.js +523 -0
  43. package/lib/rules/no-firestore-jest-mock.js +27 -4
  44. package/lib/rules/no-hungarian.d.ts +5 -0
  45. package/lib/rules/no-hungarian.js +223 -0
  46. package/lib/rules/no-mock-firebase-admin.js +20 -7
  47. package/lib/rules/no-object-values-on-strings.d.ts +2 -0
  48. package/lib/rules/no-object-values-on-strings.js +294 -0
  49. package/lib/rules/no-type-assertion-returns.d.ts +9 -0
  50. package/lib/rules/no-type-assertion-returns.js +299 -0
  51. package/lib/rules/no-unnecessary-destructuring.d.ts +5 -0
  52. package/lib/rules/no-unnecessary-destructuring.js +69 -0
  53. package/lib/rules/no-unnecessary-verb-suffix.d.ts +1 -0
  54. package/lib/rules/no-unnecessary-verb-suffix.js +203 -0
  55. package/lib/rules/no-unused-props.js +10 -5
  56. package/lib/rules/no-unused-usestate.d.ts +8 -0
  57. package/lib/rules/no-unused-usestate.js +84 -0
  58. package/lib/rules/omit-index-html.d.ts +7 -0
  59. package/lib/rules/omit-index-html.js +91 -0
  60. package/lib/rules/prefer-clone-deep.js +294 -22
  61. package/lib/rules/prefer-fragment-component.js +265 -34
  62. package/lib/rules/prefer-global-router-state-key.d.ts +5 -0
  63. package/lib/rules/prefer-global-router-state-key.js +89 -0
  64. package/lib/rules/prefer-usememo-over-useeffect-usestate.d.ts +5 -0
  65. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +129 -0
  66. package/lib/rules/prefer-utility-function-over-private-static.d.ts +1 -0
  67. package/lib/rules/prefer-utility-function-over-private-static.js +77 -0
  68. package/lib/rules/react-usememo-should-be-component.d.ts +1 -0
  69. package/lib/rules/react-usememo-should-be-component.js +623 -0
  70. package/package.json +10 -7
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enforceReactTypeNaming = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ // Types that should have lowercase variable names
7
+ const LOWERCASE_TYPES = ['ReactNode', 'JSX.Element'];
8
+ // Types that should have uppercase variable names
9
+ const UPPERCASE_TYPES = ['ComponentType', 'FC', 'FunctionComponent'];
10
+ exports.enforceReactTypeNaming = (0, createRule_1.createRule)({
11
+ name: 'enforce-react-type-naming',
12
+ meta: {
13
+ type: 'suggestion',
14
+ docs: {
15
+ description: 'Enforce naming conventions for React types',
16
+ recommended: 'error',
17
+ },
18
+ fixable: 'code',
19
+ schema: [],
20
+ messages: {
21
+ reactNodeShouldBeLowercase: 'Variables or parameters of type "{{type}}" should use lowercase naming (e.g., "{{suggestion}}").',
22
+ componentTypeShouldBeUppercase: 'Variables or parameters of type "{{type}}" should use uppercase naming (e.g., "{{suggestion}}").',
23
+ },
24
+ },
25
+ defaultOptions: [],
26
+ create(context) {
27
+ /**
28
+ * Checks if a string starts with an uppercase letter
29
+ */
30
+ function isUppercase(str) {
31
+ return /^[A-Z]/.test(str);
32
+ }
33
+ /**
34
+ * Converts a string to start with lowercase
35
+ */
36
+ function toLowercase(str) {
37
+ if (!str)
38
+ return str;
39
+ return str.charAt(0).toLowerCase() + str.slice(1);
40
+ }
41
+ /**
42
+ * Converts a string to start with uppercase
43
+ */
44
+ function toUppercase(str) {
45
+ if (!str)
46
+ return str;
47
+ return str.charAt(0).toUpperCase() + str.slice(1);
48
+ }
49
+ /**
50
+ * Extracts the type name from a type annotation
51
+ */
52
+ function getTypeName(typeAnnotation) {
53
+ if (!typeAnnotation)
54
+ return null;
55
+ // Handle TSTypeReference (e.g., ReactNode, ComponentType)
56
+ if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
57
+ if (typeAnnotation.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
58
+ return typeAnnotation.typeName.name;
59
+ }
60
+ // Handle qualified names like JSX.Element
61
+ if (typeAnnotation.typeName.type === utils_1.AST_NODE_TYPES.TSQualifiedName) {
62
+ const left = typeAnnotation.typeName.left.type === utils_1.AST_NODE_TYPES.Identifier
63
+ ? typeAnnotation.typeName.left.name
64
+ : '';
65
+ const right = typeAnnotation.typeName.right.name;
66
+ return `${left}.${right}`;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ /**
72
+ * Checks if a node is a destructured variable
73
+ */
74
+ function isDestructured(node) {
75
+ return (node.parent?.type === utils_1.AST_NODE_TYPES.Property ||
76
+ node.parent?.type === utils_1.AST_NODE_TYPES.ArrayPattern ||
77
+ (node.parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
78
+ (node.parent.id.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
79
+ node.parent.id.type === utils_1.AST_NODE_TYPES.ArrayPattern)));
80
+ }
81
+ /**
82
+ * Checks if a node is a default import
83
+ */
84
+ function isDefaultImport(node) {
85
+ return (node.parent?.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
86
+ (node.parent?.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
87
+ node.parent.local.name !== node.parent.imported?.name));
88
+ }
89
+ /**
90
+ * Check variable declarations for React type naming conventions
91
+ */
92
+ function checkVariableDeclaration(node) {
93
+ if (node.id.type !== utils_1.AST_NODE_TYPES.Identifier)
94
+ return;
95
+ // Skip destructured variables
96
+ if (isDestructured(node.id))
97
+ return;
98
+ const variableName = node.id.name;
99
+ // Get the type annotation
100
+ const typeAnnotation = node.id.typeAnnotation?.typeAnnotation;
101
+ const typeName = getTypeName(typeAnnotation);
102
+ if (!typeName)
103
+ return;
104
+ // Check if it's a ReactNode or JSX.Element (should be lowercase)
105
+ if (LOWERCASE_TYPES.includes(typeName) && isUppercase(variableName)) {
106
+ const suggestion = toLowercase(variableName);
107
+ context.report({
108
+ node: node.id,
109
+ messageId: 'reactNodeShouldBeLowercase',
110
+ data: {
111
+ type: typeName,
112
+ suggestion,
113
+ },
114
+ fix: (fixer) => fixer.replaceText(node.id, suggestion),
115
+ });
116
+ }
117
+ // Check if it's a ComponentType or FC (should be uppercase)
118
+ if (UPPERCASE_TYPES.includes(typeName) && !isUppercase(variableName)) {
119
+ const suggestion = toUppercase(variableName);
120
+ context.report({
121
+ node: node.id,
122
+ messageId: 'componentTypeShouldBeUppercase',
123
+ data: {
124
+ type: typeName,
125
+ suggestion,
126
+ },
127
+ fix: (fixer) => fixer.replaceText(node.id, suggestion),
128
+ });
129
+ }
130
+ }
131
+ /**
132
+ * Check function parameters for React type naming conventions
133
+ */
134
+ function checkParameter(node) {
135
+ if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
136
+ return;
137
+ // Skip destructured parameters
138
+ if (isDestructured(node))
139
+ return;
140
+ // Skip default imports
141
+ if (isDefaultImport(node))
142
+ return;
143
+ const paramName = node.name;
144
+ // Get the type annotation
145
+ const typeAnnotation = node.typeAnnotation?.typeAnnotation;
146
+ const typeName = getTypeName(typeAnnotation);
147
+ if (!typeName)
148
+ return;
149
+ // Check if it's a ReactNode or JSX.Element (should be lowercase)
150
+ if (LOWERCASE_TYPES.includes(typeName) && isUppercase(paramName)) {
151
+ const suggestion = toLowercase(paramName);
152
+ context.report({
153
+ node,
154
+ messageId: 'reactNodeShouldBeLowercase',
155
+ data: {
156
+ type: typeName,
157
+ suggestion,
158
+ },
159
+ fix: (fixer) => fixer.replaceText(node, suggestion),
160
+ });
161
+ }
162
+ // Check if it's a ComponentType or FC (should be uppercase)
163
+ if (UPPERCASE_TYPES.includes(typeName) && !isUppercase(paramName)) {
164
+ const suggestion = toUppercase(paramName);
165
+ context.report({
166
+ node,
167
+ messageId: 'componentTypeShouldBeUppercase',
168
+ data: {
169
+ type: typeName,
170
+ suggestion,
171
+ },
172
+ fix: (fixer) => fixer.replaceText(node, suggestion),
173
+ });
174
+ }
175
+ }
176
+ return {
177
+ VariableDeclarator: checkVariableDeclaration,
178
+ Identifier(node) {
179
+ // Check parameter names in function declarations
180
+ if (node.parent &&
181
+ (node.parent.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
182
+ node.parent.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
183
+ node.parent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) &&
184
+ node.parent.params.includes(node)) {
185
+ checkParameter(node);
186
+ }
187
+ },
188
+ };
189
+ },
190
+ });
191
+ //# sourceMappingURL=enforce-react-type-naming.js.map
@@ -21,63 +21,182 @@ exports.enforceRenderHitsMemoization = (0, createRule_1.createRule)({
21
21
  },
22
22
  defaultOptions: [],
23
23
  create(context) {
24
+ const isReactComponent = (node) => {
25
+ if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
26
+ return false;
27
+ return /^[A-Z]/.test(node.name);
28
+ };
24
29
  const isMemoizedCall = (node) => {
25
30
  if (node.type !== utils_1.AST_NODE_TYPES.CallExpression)
26
31
  return false;
27
- const callee = node.callee;
28
- if (callee.type !== utils_1.AST_NODE_TYPES.Identifier)
29
- return false;
30
- return callee.name === 'useCallback' || callee.name === 'useMemo';
31
- };
32
- const isReactComponent = (node) => {
33
- if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
32
+ if (!node.callee || node.callee.type !== utils_1.AST_NODE_TYPES.Identifier)
34
33
  return false;
35
- const name = node.name;
36
- return /^[A-Z]/.test(name);
34
+ return (node.callee.name === 'useCallback' || node.callee.name === 'useMemo');
37
35
  };
38
36
  const isMemoizedVariable = (node) => {
39
37
  if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
40
38
  return false;
41
39
  // Get the variable declaration for this identifier
42
- const variable = context.getScope().variables.find(v => v.name === node.name);
40
+ const variable = context
41
+ .getScope()
42
+ .variables.find((v) => v.name === node.name);
43
43
  if (!variable)
44
44
  return false;
45
45
  // Check if the variable is initialized with a memoized call
46
- const def = variable.defs[0];
47
- if (!def || !def.node)
48
- return false;
49
- if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator && def.node.init) {
50
- return isMemoizedCall(def.node.init);
46
+ for (const def of variable.defs) {
47
+ if (!def || !def.node)
48
+ continue;
49
+ if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
50
+ def.node.init) {
51
+ if (isMemoizedCall(def.node.init)) {
52
+ return true;
53
+ }
54
+ }
51
55
  }
52
56
  return false;
53
57
  };
54
58
  const isInsideMemoizedCall = (node) => {
59
+ // Handle the case when node is already a memoized call
60
+ if (isMemoizedCall(node))
61
+ return true;
55
62
  // Check if the node is a reference to a memoized variable
56
63
  if (isMemoizedVariable(node))
57
64
  return true;
58
65
  // Check if the node is inside a memoization hook call
59
66
  let current = node;
60
67
  while (current?.parent) {
61
- if (isMemoizedCall(current.parent))
62
- return true;
68
+ if (current.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
69
+ const callee = current.parent.callee;
70
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
71
+ (callee.name === 'useCallback' || callee.name === 'useMemo')) {
72
+ return true;
73
+ }
74
+ }
63
75
  current = current.parent;
64
76
  }
77
+ // Check if the node is a reference to a memoized value
78
+ const scope = context.getScope();
79
+ // Make sure node is an Identifier before accessing name property
80
+ if (node.type !== utils_1.AST_NODE_TYPES.Identifier) {
81
+ return false;
82
+ }
83
+ const variable = scope.variables.find((v) => v.name === node.name);
84
+ if (!variable) {
85
+ return false;
86
+ }
87
+ // Check if any definition is a memoized value
88
+ for (const def of variable.defs) {
89
+ const parent = def.node.parent;
90
+ if (parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
91
+ parent.init?.type === utils_1.AST_NODE_TYPES.CallExpression) {
92
+ const callee = parent.init.callee;
93
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
94
+ (callee.name === 'useCallback' || callee.name === 'useMemo')) {
95
+ return true;
96
+ }
97
+ }
98
+ }
99
+ // Check if any reference is inside a memoized call
100
+ for (const ref of variable.references) {
101
+ let current = ref.identifier;
102
+ while (current?.parent) {
103
+ if (current.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
104
+ const callee = current.parent.callee;
105
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
106
+ (callee.name === 'useCallback' || callee.name === 'useMemo')) {
107
+ return true;
108
+ }
109
+ }
110
+ current = current.parent;
111
+ }
112
+ }
113
+ // Check if the node is a property of an object that is memoized
114
+ const parent = node.parent;
115
+ if (parent?.type === utils_1.AST_NODE_TYPES.Property &&
116
+ parent.parent?.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
117
+ const objectExpression = parent.parent;
118
+ let current = objectExpression;
119
+ while (current?.parent) {
120
+ if (current.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
121
+ const callee = current.parent.callee;
122
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
123
+ (callee.name === 'useCallback' || callee.name === 'useMemo')) {
124
+ return true;
125
+ }
126
+ }
127
+ current = current.parent;
128
+ }
129
+ }
65
130
  return false;
66
131
  };
132
+ let useRenderHitsName = 'useRenderHits';
133
+ let renderHitsName = 'renderHits';
67
134
  return {
135
+ ImportDeclaration(node) {
136
+ if (node.source.value.endsWith('useRenderHits')) {
137
+ for (const specifier of node.specifiers) {
138
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
139
+ specifier.imported.name === 'useRenderHits') {
140
+ useRenderHitsName = specifier.local.name;
141
+ break;
142
+ }
143
+ }
144
+ }
145
+ else if (node.source.value.endsWith('renderHits')) {
146
+ for (const specifier of node.specifiers) {
147
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
148
+ specifier.imported.name === 'renderHits') {
149
+ renderHitsName = specifier.local.name;
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ },
68
155
  CallExpression(node) {
69
- if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier && node.callee.name === 'useRenderHits') {
156
+ if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
157
+ node.callee.name === useRenderHitsName) {
70
158
  if (node.arguments.length === 0)
71
159
  return;
72
160
  const options = node.arguments[0];
73
161
  if (options.type !== utils_1.AST_NODE_TYPES.ObjectExpression)
74
162
  return;
163
+ // Variable to track if we need to check properties (check both by default)
164
+ const checkProps = {
165
+ transformBefore: true,
166
+ render: true,
167
+ };
168
+ // First pass: Check if transformBefore or render properties exist as shorthand
75
169
  for (const prop of options.properties) {
76
170
  if (prop.type !== utils_1.AST_NODE_TYPES.Property)
77
171
  continue;
78
172
  if (prop.key.type !== utils_1.AST_NODE_TYPES.Identifier)
79
173
  continue;
80
- if (prop.key.name === 'transformBefore') {
174
+ // If it's shorthand property syntax like { transformBefore } and already a memoized variable
175
+ if (prop.key.name === 'transformBefore' &&
176
+ prop.shorthand &&
177
+ prop.key.type === utils_1.AST_NODE_TYPES.Identifier) {
178
+ checkProps.transformBefore = !isMemoizedVariable(prop.key);
179
+ }
180
+ else if (prop.key.name === 'render' &&
181
+ prop.shorthand &&
182
+ prop.key.type === utils_1.AST_NODE_TYPES.Identifier) {
183
+ checkProps.render = !isMemoizedVariable(prop.key);
184
+ }
185
+ }
186
+ // Second pass: Check non-shorthand properties
187
+ for (const prop of options.properties) {
188
+ if (prop.type !== utils_1.AST_NODE_TYPES.Property)
189
+ continue;
190
+ if (prop.key.type !== utils_1.AST_NODE_TYPES.Identifier)
191
+ continue;
192
+ // Skip shorthand properties that we already checked
193
+ if (prop.shorthand)
194
+ continue;
195
+ if (prop.key.name === 'transformBefore' &&
196
+ checkProps.transformBefore) {
197
+ // Skip if the value is already a memoized call
198
+ if (isMemoizedCall(prop.value))
199
+ continue;
81
200
  if (!isInsideMemoizedCall(prop.value)) {
82
201
  context.report({
83
202
  node: prop.value,
@@ -85,7 +204,7 @@ exports.enforceRenderHitsMemoization = (0, createRule_1.createRule)({
85
204
  });
86
205
  }
87
206
  }
88
- if (prop.key.name === 'render') {
207
+ else if (prop.key.name === 'render' && checkProps.render) {
89
208
  if (isReactComponent(prop.value)) {
90
209
  context.report({
91
210
  node: prop.value,
@@ -101,13 +220,23 @@ exports.enforceRenderHitsMemoization = (0, createRule_1.createRule)({
101
220
  }
102
221
  }
103
222
  }
104
- if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier && node.callee.name === 'renderHits') {
105
- if (!isInsideMemoizedCall(node)) {
106
- context.report({
107
- node,
108
- messageId: 'requireMemoizedRenderHits',
109
- });
223
+ if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
224
+ node.callee.name === renderHitsName) {
225
+ let current = node;
226
+ while (current?.parent) {
227
+ if (current.parent.type === utils_1.AST_NODE_TYPES.CallExpression) {
228
+ const callee = current.parent.callee;
229
+ if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
230
+ (callee.name === 'useCallback' || callee.name === 'useMemo')) {
231
+ return;
232
+ }
233
+ }
234
+ current = current.parent;
110
235
  }
236
+ context.report({
237
+ node,
238
+ messageId: 'requireMemoizedRenderHits',
239
+ });
111
240
  }
112
241
  },
113
242
  };
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const enforceSingularTypeNames: TSESLint.RuleModule<'typeShouldBeSingular', never[]>;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.enforceSingularTypeNames = void 0;
27
+ const createRule_1 = require("../utils/createRule");
28
+ const pluralize = __importStar(require("pluralize"));
29
+ exports.enforceSingularTypeNames = (0, createRule_1.createRule)({
30
+ create(context) {
31
+ /**
32
+ * Check if a name is plural
33
+ * @param name The name to check
34
+ * @returns true if the name is plural, false otherwise
35
+ */
36
+ function isPlural(name) {
37
+ // Skip checking if name is too short (less than 3 characters)
38
+ if (name.length < 3)
39
+ return false;
40
+ // Skip checking if name ends with 'Props' or 'Params'
41
+ if (name.endsWith('Props') || name.endsWith('Params'))
42
+ return false;
43
+ // Skip checking if name is already singular according to pluralize
44
+ if (pluralize.isSingular(name))
45
+ return false;
46
+ // Check if the singular form is different from the name
47
+ const singular = pluralize.singular(name);
48
+ return singular !== name;
49
+ }
50
+ /**
51
+ * Get the singular form of a name
52
+ * @param name The name to get the singular form of
53
+ * @returns The singular form of the name
54
+ */
55
+ function getSingularForm(name) {
56
+ return pluralize.singular(name);
57
+ }
58
+ /**
59
+ * Report a plural type name
60
+ * @param node The node to report
61
+ * @param name The plural name
62
+ * @param suggestedName The suggested singular name
63
+ */
64
+ function reportPluralName(node, name, suggestedName) {
65
+ context.report({
66
+ node,
67
+ messageId: 'typeShouldBeSingular',
68
+ data: {
69
+ name,
70
+ suggestedName,
71
+ },
72
+ });
73
+ }
74
+ return {
75
+ // Check type aliases
76
+ TSTypeAliasDeclaration(node) {
77
+ const name = node.id.name;
78
+ if (isPlural(name)) {
79
+ reportPluralName(node.id, name, getSingularForm(name));
80
+ }
81
+ },
82
+ // Check interfaces
83
+ TSInterfaceDeclaration(node) {
84
+ const name = node.id.name;
85
+ if (isPlural(name)) {
86
+ reportPluralName(node.id, name, getSingularForm(name));
87
+ }
88
+ },
89
+ // Check enums
90
+ TSEnumDeclaration(node) {
91
+ const name = node.id.name;
92
+ if (isPlural(name)) {
93
+ reportPluralName(node.id, name, getSingularForm(name));
94
+ }
95
+ },
96
+ };
97
+ },
98
+ name: 'enforce-singular-type-names',
99
+ meta: {
100
+ type: 'suggestion',
101
+ docs: {
102
+ description: 'Enforce TypeScript type names to be singular',
103
+ recommended: 'error',
104
+ },
105
+ schema: [],
106
+ messages: {
107
+ typeShouldBeSingular: "Type name '{{name}}' should be singular. Consider using '{{suggestedName}}' instead.",
108
+ },
109
+ },
110
+ defaultOptions: [],
111
+ });
112
+ //# sourceMappingURL=enforce-singular-type-names.js.map
@@ -0,0 +1 @@
1
+ export declare const enforceTimestampNow: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"preferTimestampNow", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;