eslint-plugin-absolute 0.1.6 → 0.2.0

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 (40) hide show
  1. package/.claude/settings.local.json +5 -0
  2. package/dist/index.js +1226 -798
  3. package/package.json +12 -11
  4. package/src/index.ts +45 -0
  5. package/src/rules/explicit-object-types.ts +73 -0
  6. package/src/rules/{inline-style-limit.js → inline-style-limit.ts} +16 -7
  7. package/src/rules/localize-react-props.ts +459 -0
  8. package/src/rules/max-depth-extended.ts +164 -0
  9. package/src/rules/{max-jsx-nesting.js → max-jsx-nesting.ts} +15 -8
  10. package/src/rules/{min-var-length.js → min-var-length.ts} +75 -45
  11. package/src/rules/no-button-navigation.ts +312 -0
  12. package/src/rules/no-explicit-return-types.ts +87 -0
  13. package/src/rules/{no-inline-prop-types.js → no-inline-prop-types.ts} +22 -9
  14. package/src/rules/no-multi-style-objects.ts +87 -0
  15. package/src/rules/no-nested-jsx-return.ts +210 -0
  16. package/src/rules/no-or-none-component.ts +65 -0
  17. package/src/rules/{no-transition-cssproperties.js → no-transition-cssproperties.ts} +50 -27
  18. package/src/rules/no-unnecessary-div.ts +73 -0
  19. package/src/rules/{no-unnecessary-key.js → no-unnecessary-key.ts} +43 -26
  20. package/src/rules/no-useless-function.ts +58 -0
  21. package/src/rules/seperate-style-files.ts +81 -0
  22. package/src/rules/sort-exports.ts +420 -0
  23. package/src/rules/sort-keys-fixable.ts +621 -0
  24. package/src/rules/spring-naming-convention.ts +145 -0
  25. package/tsconfig.json +2 -1
  26. package/src/index.js +0 -45
  27. package/src/rules/explicit-object-types.js +0 -54
  28. package/src/rules/localize-react-props.js +0 -418
  29. package/src/rules/max-depth-extended.js +0 -124
  30. package/src/rules/no-button-navigation.js +0 -232
  31. package/src/rules/no-explicit-return-types.js +0 -64
  32. package/src/rules/no-multi-style-objects.js +0 -70
  33. package/src/rules/no-nested-jsx-return.js +0 -154
  34. package/src/rules/no-or-none-component.js +0 -50
  35. package/src/rules/no-unnecessary-div.js +0 -40
  36. package/src/rules/no-useless-function.js +0 -43
  37. package/src/rules/seperate-style-files.js +0 -62
  38. package/src/rules/sort-exports.js +0 -397
  39. package/src/rules/sort-keys-fixable.js +0 -459
  40. package/src/rules/spring-naming-convention.js +0 -111
@@ -0,0 +1,164 @@
1
+ import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ type Options = [number?];
4
+ type MessageIds = "tooDeep";
5
+
6
+ export const maxDepthExtended: TSESLint.RuleModule<MessageIds, Options> = {
7
+ meta: {
8
+ type: "suggestion",
9
+ docs: {
10
+ description:
11
+ "disallow too many nested blocks except when the block only contains an early exit (return or throw)"
12
+ },
13
+ schema: [
14
+ {
15
+ // Accepts a single number as the maximum allowed depth.
16
+ type: "number"
17
+ }
18
+ ],
19
+ messages: {
20
+ tooDeep:
21
+ "Blocks are nested too deeply ({{depth}}). Maximum allowed is {{maxDepth}} or an early exit."
22
+ }
23
+ },
24
+
25
+ defaultOptions: [1],
26
+
27
+ create(context) {
28
+ const option = context.options[0];
29
+ const maxDepth = typeof option === "number" ? option : 1;
30
+ const functionStack: number[] = [];
31
+
32
+ // Helper to get ancestors of a node by walking its parent chain.
33
+ function getAncestors(node: TSESTree.Node) {
34
+ const ancestors: TSESTree.Node[] = [];
35
+ let current: TSESTree.Node | null | undefined = node.parent;
36
+ while (current) {
37
+ ancestors.push(current);
38
+ current = current.parent;
39
+ }
40
+ return ancestors;
41
+ }
42
+
43
+ // Check if a block only contains a single early exit: return or throw.
44
+ function isEarlyExitBlock(node: TSESTree.BlockStatement) {
45
+ if (node.body.length !== 1) {
46
+ return false;
47
+ }
48
+ const first = node.body[0];
49
+ if (!first) {
50
+ return false;
51
+ }
52
+ return (
53
+ first.type === "ReturnStatement" ||
54
+ first.type === "ThrowStatement"
55
+ );
56
+ }
57
+
58
+ function incrementCurrentDepth(): number | null {
59
+ if (functionStack.length === 0) {
60
+ return null;
61
+ }
62
+ const index = functionStack.length - 1;
63
+ const currentDepth = functionStack[index];
64
+ if (typeof currentDepth !== "number") {
65
+ return null;
66
+ }
67
+ const nextDepth = currentDepth + 1;
68
+ functionStack[index] = nextDepth;
69
+ return nextDepth;
70
+ }
71
+
72
+ function decrementCurrentDepth(): void {
73
+ if (functionStack.length === 0) {
74
+ return;
75
+ }
76
+ const index = functionStack.length - 1;
77
+ const currentDepth = functionStack[index];
78
+ if (typeof currentDepth !== "number") {
79
+ return;
80
+ }
81
+ functionStack[index] = currentDepth - 1;
82
+ }
83
+
84
+ // Report if the current depth exceeds the allowed maximum.
85
+ function checkDepth(node: TSESTree.BlockStatement, depth: number) {
86
+ if (depth > maxDepth) {
87
+ context.report({
88
+ node,
89
+ messageId: "tooDeep",
90
+ data: { depth, maxDepth }
91
+ });
92
+ }
93
+ }
94
+
95
+ return {
96
+ FunctionDeclaration() {
97
+ functionStack.push(0);
98
+ },
99
+ FunctionExpression() {
100
+ functionStack.push(0);
101
+ },
102
+ ArrowFunctionExpression() {
103
+ functionStack.push(0);
104
+ },
105
+
106
+ BlockStatement(node: TSESTree.BlockStatement) {
107
+ const ancestors = getAncestors(node);
108
+ const parent = ancestors.length > 0 ? ancestors[0] : undefined;
109
+
110
+ // Do not count if this block is the body of a function.
111
+ if (
112
+ parent &&
113
+ (parent.type === "FunctionDeclaration" ||
114
+ parent.type === "FunctionExpression" ||
115
+ parent.type === "ArrowFunctionExpression") &&
116
+ node === parent.body
117
+ ) {
118
+ return;
119
+ }
120
+
121
+ // Skip blocks that only have an early exit.
122
+ if (isEarlyExitBlock(node)) {
123
+ return;
124
+ }
125
+
126
+ const depth = incrementCurrentDepth();
127
+ if (depth !== null) {
128
+ checkDepth(node, depth);
129
+ }
130
+ },
131
+
132
+ "BlockStatement:exit"(node: TSESTree.BlockStatement) {
133
+ const ancestors = getAncestors(node);
134
+ const parent = ancestors.length > 0 ? ancestors[0] : undefined;
135
+
136
+ if (
137
+ parent &&
138
+ (parent.type === "FunctionDeclaration" ||
139
+ parent.type === "FunctionExpression" ||
140
+ parent.type === "ArrowFunctionExpression") &&
141
+ node === parent.body
142
+ ) {
143
+ return;
144
+ }
145
+
146
+ if (isEarlyExitBlock(node)) {
147
+ return;
148
+ }
149
+
150
+ decrementCurrentDepth();
151
+ },
152
+
153
+ "FunctionDeclaration:exit"() {
154
+ functionStack.pop();
155
+ },
156
+ "FunctionExpression:exit"() {
157
+ functionStack.pop();
158
+ },
159
+ "ArrowFunctionExpression:exit"() {
160
+ functionStack.pop();
161
+ }
162
+ };
163
+ }
164
+ };
@@ -1,10 +1,14 @@
1
- export default {
1
+ import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ type Options = [number];
4
+ type MessageIds = "tooDeeplyNested";
5
+
6
+ export const maxJSXNesting: TSESLint.RuleModule<MessageIds, Options> = {
2
7
  meta: {
3
8
  type: "suggestion",
4
9
  docs: {
5
10
  description:
6
- "Warn when JSX elements are nested too deeply, suggesting refactoring into a separate component.",
7
- recommended: false
11
+ "Warn when JSX elements are nested too deeply, suggesting refactoring into a separate component."
8
12
  },
9
13
  // The rule accepts a single numeric option (minimum 1)
10
14
  schema: [
@@ -18,9 +22,12 @@ export default {
18
22
  "JSX element is nested too deeply ({{level}} levels, allowed is {{maxAllowed}} levels). Consider refactoring into a separate component."
19
23
  }
20
24
  },
25
+
26
+ defaultOptions: [1],
27
+
21
28
  create(context) {
22
- // At this point, the provided option is guaranteed to be a number >= 1.
23
- const maxAllowed = context.options[0];
29
+ const option = context.options[0];
30
+ const maxAllowed = typeof option === "number" ? option : 1;
24
31
 
25
32
  /**
26
33
  * Calculates the JSX nesting level for the given node by traversing the node.parent chain.
@@ -29,9 +36,9 @@ export default {
29
36
  * @param {ASTNode} node The JSX element node.
30
37
  * @returns {number} The nesting level.
31
38
  */
32
- function getJSXNestingLevel(node) {
39
+ function getJSXNestingLevel(node: TSESTree.Node): number {
33
40
  let level = 1; // count the current node as level 1
34
- let current = node.parent;
41
+ let current: TSESTree.Node | null | undefined = node.parent;
35
42
  while (current) {
36
43
  if (
37
44
  current.type === "JSXElement" ||
@@ -45,7 +52,7 @@ export default {
45
52
  }
46
53
 
47
54
  return {
48
- JSXElement(node) {
55
+ JSXElement(node: TSESTree.JSXElement) {
49
56
  const level = getJSXNestingLevel(node);
50
57
  if (level > maxAllowed) {
51
58
  context.report({
@@ -1,23 +1,19 @@
1
- /**
2
- * @fileoverview Disallow variable names shorter than a specified minimum length unless an outer variable
3
- * with a corresponding longer name exists, with an option to exempt specific variable names.
4
- *
5
- * Options:
6
- * - minLength: a number specifying the minimum allowed length for variable names. Defaults to 1.
7
- * - allowedVars: an array of variable names that are exempt from the minimum length rule.
8
- * Each allowed variable name should have a length of at least 1 and at most minLength.
9
- *
10
- * This rule checks variable declarations, function parameters, catch clauses,
11
- * and destructuring patterns. It uses the ESLint v9 APIs (via the scopeManager on the
12
- * SourceCode object) and a custom helper to get ancestors.
13
- */
14
- export default {
1
+ import { TSESLint, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ type MinVarLengthOption = {
4
+ minLength?: number;
5
+ allowedVars?: string[];
6
+ };
7
+
8
+ type Options = [MinVarLengthOption?];
9
+ type MessageIds = "variableNameTooShort";
10
+
11
+ export const minVarLength: TSESLint.RuleModule<MessageIds, Options> = {
15
12
  meta: {
16
13
  type: "problem",
17
14
  docs: {
18
15
  description:
19
- "Disallow variable names shorter than the configured minimum length unless an outer variable with a longer name starting with the same characters exists. You can exempt specific variable names using the allowedVars option.",
20
- recommended: false
16
+ "Disallow variable names shorter than the configured minimum length unless an outer variable with a longer name starting with the same characters exists. You can exempt specific variable names using the allowedVars option."
21
17
  },
22
18
  schema: [
23
19
  {
@@ -46,17 +42,27 @@ export default {
46
42
  }
47
43
  },
48
44
 
45
+ defaultOptions: [{}],
46
+
49
47
  create(context) {
50
- const sourceCode = context.getSourceCode();
51
- const options = context.options[0] || {};
52
- const minLength =
53
- typeof options.minLength === "number" ? options.minLength : 1;
54
- const allowedVars = options.allowedVars || [];
48
+ const sourceCode = context.sourceCode;
49
+ const options = context.options[0];
50
+ const configuredMinLength =
51
+ options && typeof options.minLength === "number"
52
+ ? options.minLength
53
+ : 1;
54
+ const configuredAllowedVars =
55
+ options && Array.isArray(options.allowedVars)
56
+ ? options.allowedVars
57
+ : [];
58
+
59
+ const minLength = configuredMinLength;
60
+ const allowedVars = configuredAllowedVars;
55
61
 
56
62
  // Helper: walk up the node.parent chain to get ancestors.
57
- function getAncestors(node) {
58
- const ancestors = [];
59
- let current = node.parent;
63
+ function getAncestors(node: TSESTree.Node) {
64
+ const ancestors: TSESTree.Node[] = [];
65
+ let current: TSESTree.Node | null | undefined = node.parent;
60
66
  while (current) {
61
67
  ancestors.push(current);
62
68
  current = current.parent;
@@ -65,21 +71,30 @@ export default {
65
71
  }
66
72
 
67
73
  // Helper: retrieve the scope for a given node using the scopeManager.
68
- function getScope(node) {
69
- return (
70
- sourceCode.scopeManager.acquire(node) ||
71
- sourceCode.scopeManager.globalScope
72
- );
74
+ function getScope(node: TSESTree.Node): TSESLint.Scope.Scope | null {
75
+ const scopeManager = sourceCode.scopeManager;
76
+ if (!scopeManager) {
77
+ return null;
78
+ }
79
+ const acquired = scopeManager.acquire(node);
80
+ if (acquired) {
81
+ return acquired;
82
+ }
83
+ return scopeManager.globalScope ?? null;
73
84
  }
74
85
 
75
86
  // Fallback: get declared variable names in the nearest BlockStatement.
76
- function getVariablesInNearestBlock(node) {
77
- let current = node.parent;
87
+ function getVariablesInNearestBlock(node: TSESTree.Node) {
88
+ let current: TSESTree.Node | null | undefined = node.parent;
78
89
  while (current && current.type !== "BlockStatement") {
79
90
  current = current.parent;
80
91
  }
81
- const names = [];
82
- if (current && Array.isArray(current.body)) {
92
+ const names: string[] = [];
93
+ if (
94
+ current &&
95
+ current.type === "BlockStatement" &&
96
+ Array.isArray(current.body)
97
+ ) {
83
98
  for (const stmt of current.body) {
84
99
  if (stmt.type === "VariableDeclaration") {
85
100
  for (const decl of stmt.declarations) {
@@ -99,7 +114,10 @@ export default {
99
114
  * @param {string[]} identifiers Array to accumulate names.
100
115
  * @returns {string[]} Array of identifier names.
101
116
  */
102
- function extractIdentifiersFromPattern(pattern, identifiers = []) {
117
+ function extractIdentifiersFromPattern(
118
+ pattern: TSESTree.Node | null,
119
+ identifiers: string[] = []
120
+ ): string[] {
103
121
  if (!pattern) return identifiers;
104
122
  switch (pattern.type) {
105
123
  case "Identifier":
@@ -122,8 +140,9 @@ export default {
122
140
  break;
123
141
  case "ArrayPattern":
124
142
  for (const element of pattern.elements) {
125
- if (element)
143
+ if (element) {
126
144
  extractIdentifiersFromPattern(element, identifiers);
145
+ }
127
146
  }
128
147
  break;
129
148
  case "AssignmentPattern":
@@ -144,10 +163,16 @@ export default {
144
163
  * @param {ASTNode} node The current identifier node.
145
164
  * @returns {boolean} True if an outer variable is found.
146
165
  */
147
- function hasOuterCorrespondingIdentifier(shortName, node) {
166
+ function hasOuterCorrespondingIdentifier(
167
+ shortName: string,
168
+ node: TSESTree.Identifier
169
+ ) {
148
170
  // First, try using the scope manager.
149
- let currentScope = getScope(node);
150
- let outer = currentScope.upper;
171
+ const startingScope = getScope(node);
172
+ let outer =
173
+ startingScope && startingScope.upper
174
+ ? startingScope.upper
175
+ : null;
151
176
  while (outer) {
152
177
  for (const variable of outer.variables) {
153
178
  if (
@@ -228,9 +253,9 @@ export default {
228
253
  * and no outer variable with a longer name starting with the short name is found, it reports an error.
229
254
  * @param {ASTNode} node The Identifier node.
230
255
  */
231
- function checkIdentifier(node) {
256
+ function checkIdentifier(node: TSESTree.Identifier) {
232
257
  const name = node.name;
233
- if (typeof name === "string" && name.length < minLength) {
258
+ if (name.length < minLength) {
234
259
  // If the name is in the allowed list, skip.
235
260
  if (allowedVars.includes(name)) {
236
261
  return;
@@ -249,7 +274,7 @@ export default {
249
274
  * Recursively checks a pattern node for identifiers.
250
275
  * @param {ASTNode} pattern The pattern node.
251
276
  */
252
- function checkPattern(pattern) {
277
+ function checkPattern(pattern: TSESTree.Node | null) {
253
278
  if (!pattern) return;
254
279
  switch (pattern.type) {
255
280
  case "Identifier":
@@ -266,7 +291,9 @@ export default {
266
291
  break;
267
292
  case "ArrayPattern":
268
293
  for (const element of pattern.elements) {
269
- if (element) checkPattern(element);
294
+ if (element) {
295
+ checkPattern(element);
296
+ }
270
297
  }
271
298
  break;
272
299
  case "AssignmentPattern":
@@ -278,19 +305,22 @@ export default {
278
305
  }
279
306
 
280
307
  return {
281
- VariableDeclarator(node) {
308
+ VariableDeclarator(node: TSESTree.VariableDeclarator) {
282
309
  if (node.id) {
283
310
  checkPattern(node.id);
284
311
  }
285
312
  },
286
313
  "FunctionDeclaration, FunctionExpression, ArrowFunctionExpression"(
287
- node
314
+ node:
315
+ | TSESTree.FunctionDeclaration
316
+ | TSESTree.FunctionExpression
317
+ | TSESTree.ArrowFunctionExpression
288
318
  ) {
289
319
  for (const param of node.params) {
290
320
  checkPattern(param);
291
321
  }
292
322
  },
293
- CatchClause(node) {
323
+ CatchClause(node: TSESTree.CatchClause) {
294
324
  if (node.param) {
295
325
  checkPattern(node.param);
296
326
  }