eslint-plugin-th-rules 1.12.0 → 1.13.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.13.1](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.13.0...v1.13.1) (2024-08-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Update named-functions rule to enforce named function declarations ([e2c9b5d](https://github.com/tomerh2001/eslint-plugin-th-rules/commit/e2c9b5d5f96030278b2900adbf940363c4648bdd))
7
+
8
+ # [1.13.0](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.12.0...v1.13.0) (2024-08-19)
9
+
10
+
11
+ ### Features
12
+
13
+ * Add named-functions rule to recommended and recommended-typescript configs ([3f88f76](https://github.com/tomerh2001/eslint-plugin-th-rules/commit/3f88f76460d7bce934f83da68c555c9795fdfe92))
14
+
1
15
  # [1.12.0](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.11.4...v1.12.0) (2024-08-19)
2
16
 
3
17
 
package/README.md CHANGED
@@ -12,82 +12,17 @@ This repository contains custom ESLint rules to enhance code quality and consist
12
12
  This repository contains custom ESLint rules to enhance code quality and consistency across projects, created by Tomer Horowitz.
13
13
 
14
14
  ## Rules
15
+ <!-- begin auto-generated rules list -->
15
16
 
16
- ### 1. No-destructuring Rule
17
+ 💼 Configurations enabled in.\
18
+ ✅ Set in the `recommended` configuration.\
19
+ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
17
20
 
18
- **Rule ID:** `th-rules/no-destructuring`
21
+ | Name              | Description | 💼 | 🔧 |
22
+ | :--------------------------------------------------- | :------------------------------------------------------------------------------- | :---------------------------------- | :- |
23
+ | [named-functions](docs/rules/named-functions.md) | Enforce top-level functions to be named function declarations | ✅ ![badge-recommended-typescript][] | 🔧 |
24
+ | [no-comments](docs/rules/no-comments.md) | Disallow comments except for specified allowed patterns. | ✅ ![badge-recommended-typescript][] | 🔧 |
25
+ | [no-default-export](docs/rules/no-default-export.md) | Convert unnamed default exports to named default exports based on the file name. | ✅ ![badge-recommended-typescript][] | 🔧 |
26
+ | [no-destructuring](docs/rules/no-destructuring.md) | Disallow destructuring that does not meet certain conditions | ✅ ![badge-recommended-typescript][] | |
19
27
 
20
- #### Description
21
-
22
- This rule disallows destructuring that does not meet certain conditions, aiming to prevent overly complex destructuring patterns and ensure code readability.
23
-
24
- #### Rule Details
25
-
26
- This rule checks for:
27
-
28
- - Destructuring at a nesting level above 3.
29
- - Destructuring of more than the specified maximum number of variables (default is 2).
30
- - Destructuring on a line exceeding the specified maximum line length (default is 100 characters).
31
-
32
- #### Configuration
33
-
34
- ```json
35
- {
36
- "rules": {
37
- "th-rules/no-destructuring": ["error", { "maximumDestructuredVariables": 2, "maximumLineLength": 100 }]
38
- }
39
- }
40
- ```
41
-
42
- ### 2. Name-Export Rule
43
-
44
- **Rule ID:** `th-rules/no-default-export`
45
-
46
- #### Description
47
-
48
- Converts unnamed default exports to named default exports based on the file name. This rule helps maintain consistency in export names and facilitates easier identification of components or modules.
49
-
50
- #### Rule Details
51
-
52
- This rule targets unnamed default exports and automatically generates a named export based on the file name.
53
-
54
- #### Configuration
55
- ```json
56
- {
57
- "rules": {
58
- "no-default-export": "error"
59
- }
60
- }
61
- ```
62
- ### 3. No-Disallowed-Comments Rule
63
-
64
- **Rule ID:** `th-rules/no-disallowed-comments`
65
-
66
- #### Description
67
-
68
- This rule disallows comments unless they match specified allowed patterns. It ensures that only relevant and permitted comments are present in the codebase, such as TODOs, warnings, JSDoc comments, ESLint directives, etc.
69
-
70
- #### Rule Details
71
-
72
- By default, the following comments are allowed:
73
-
74
- - TODO, WARNING, ERROR, INFO (case-insensitive).
75
- - ESLint directives like `/* eslint-disable */`.
76
- - JSDoc comments (any comment starting with `/**`).
77
-
78
- You can also configure additional patterns to allow or disallow specific types of comments.
79
-
80
- #### Configuration
81
-
82
- ```json
83
- {
84
- "rules": {
85
- "th-rules/no-disallowed-comments": [
86
- "error",
87
- {
88
- "allow": ["keep", "important"],
89
- "disallow": ["deprecated", "hack"]
90
- }
91
- ]
92
- }
93
- }
28
+ <!-- end auto-generated rules list -->
package/bun.lockb CHANGED
Binary file
@@ -0,0 +1,7 @@
1
+ # Enforce top-level functions to be named function declarations (`th-rules/named-functions`)
2
+
3
+ 💼 This rule is enabled in the following configs: ✅ `recommended`, `recommended-typescript`.
4
+
5
+ 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ <!-- end auto-generated rule header -->
@@ -0,0 +1,48 @@
1
+ # Disallow comments except for specified allowed patterns (`th-rules/no-comments`)
2
+
3
+ 💼 This rule is enabled in the following configs: ✅ `recommended`, `recommended-typescript`.
4
+
5
+ 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ <!-- end auto-generated rule header -->
8
+
9
+ ## Options
10
+
11
+ <!-- begin auto-generated rule options list -->
12
+
13
+ | Name | Description | Type |
14
+ | :--------- | :------------------------------------------- | :------- |
15
+ | `allow` | Additional patterns to allow in comments. | String[] |
16
+ | `disallow` | Additional patterns to disallow in comments. | String[] |
17
+
18
+ <!-- end auto-generated rule options list -->
19
+
20
+ ## Description
21
+
22
+ This rule disallows comments unless they match specified allowed patterns. It ensures that only relevant and permitted comments are present in the codebase, such as TODOs, warnings, JSDoc comments, ESLint directives, etc.
23
+
24
+ ## Rule Details
25
+
26
+ By default, the following comments are allowed:
27
+
28
+ - TODO, WARNING, ERROR, INFO (case-insensitive).
29
+ - ESLint directives like `/* eslint-disable */`.
30
+ - JSDoc comments (any comment starting with `/**`).
31
+
32
+ You can also configure additional patterns to allow or disallow specific types of comments.
33
+
34
+ ## Usage
35
+
36
+ ```json
37
+ {
38
+ "rules": {
39
+ "th-rules/no-comments": [
40
+ "error",
41
+ {
42
+ "allow": ["keep", "important"],
43
+ "disallow": ["deprecated", "hack"]
44
+ }
45
+ ]
46
+ }
47
+ }
48
+ ```
@@ -0,0 +1,24 @@
1
+ # Convert unnamed default exports to named default exports based on the file name (`th-rules/no-default-export`)
2
+
3
+ 💼 This rule is enabled in the following configs: ✅ `recommended`, `recommended-typescript`.
4
+
5
+ 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ <!-- end auto-generated rule header -->
8
+
9
+ ## Description
10
+
11
+ Converts unnamed default exports to named default exports based on the file name. This rule helps maintain consistency in export names and facilitates easier identification of components or modules.
12
+
13
+ ## Rule Details
14
+
15
+ This rule targets unnamed default exports and automatically generates a named export based on the file name.
16
+
17
+ ## Usage
18
+ ```json
19
+ {
20
+ "rules": {
21
+ "no-default-export": "error"
22
+ }
23
+ }
24
+ ```
@@ -0,0 +1,38 @@
1
+ # Disallow destructuring that does not meet certain conditions (`th-rules/no-destructuring`)
2
+
3
+ 💼 This rule is enabled in the following configs: ✅ `recommended`, `recommended-typescript`.
4
+
5
+ <!-- end auto-generated rule header -->
6
+
7
+ ## Options
8
+
9
+ <!-- begin auto-generated rule options list -->
10
+
11
+ | Name | Type |
12
+ | :----------------------------- | :------ |
13
+ | `maximumDestructuredVariables` | Integer |
14
+ | `maximumLineLength` | Integer |
15
+
16
+ <!-- end auto-generated rule options list -->
17
+
18
+ ## Description
19
+
20
+ This rule disallows destructuring that does not meet certain conditions, aiming to prevent overly complex destructuring patterns and ensure code readability.
21
+
22
+ ## Rule Details
23
+
24
+ This rule checks for:
25
+
26
+ - Destructuring at a nesting level above 3.
27
+ - Destructuring of more than the specified maximum number of variables (default is 2).
28
+ - Destructuring on a line exceeding the specified maximum line length (default is 100 characters).
29
+
30
+ ## Usage
31
+
32
+ ```json
33
+ {
34
+ "rules": {
35
+ "th-rules/no-destructuring": ["error", { "maximumDestructuredVariables": 2, "maximumLineLength": 100 }]
36
+ }
37
+ }
38
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-th-rules",
3
- "version": "1.12.0",
3
+ "version": "1.13.1",
4
4
  "description": "A List of custom ESLint rules created by Tomer Horowitz",
5
5
  "keywords": [
6
6
  "eslint",
@@ -28,7 +28,7 @@
28
28
  "eslint-plugin-react-native": "^4.1.0",
29
29
  "eslint-plugin-security": "^3.0.1",
30
30
  "eslint-plugin-sonarjs": "^1.0.4",
31
- "eslint-plugin-th-rules": "^1.11.4",
31
+ "eslint-plugin-th-rules": "^1.12.0",
32
32
  "requireindex": "^1.2.0"
33
33
  },
34
34
  "devDependencies": {
package/src/index.js CHANGED
@@ -19,6 +19,7 @@ configs.recommended = {
19
19
  'th-rules/no-destructuring': 'error',
20
20
  'th-rules/no-default-export': 'error',
21
21
  'th-rules/no-comments': 'error',
22
+ 'th-rules/named-functions': 'error',
22
23
  'unicorn/prefer-module': 'warn',
23
24
  'unicorn/filename-case': 'off',
24
25
  'unicorn/no-array-callback-reference': 'off',
@@ -0,0 +1,84 @@
1
+ module.exports = {
2
+ meta: {
3
+ type: 'problem',
4
+ docs: {
5
+ description: 'Enforce top-level functions to be named function declarations',
6
+ url: 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/named-functions.md',
7
+ },
8
+ fixable: 'code',
9
+ schema: [],
10
+ },
11
+
12
+ create(context) {
13
+ function reportAndFix(node, varName) {
14
+ context.report({
15
+ node,
16
+ message: 'Top-level functions must be named function declarations.',
17
+ fix(fixer) {
18
+ const sourceCode = context.getSourceCode();
19
+
20
+ if (node.type === 'ArrowFunctionExpression') {
21
+ // Convert arrow function to a named function declaration
22
+ const functionBody = sourceCode.getText(node.body);
23
+ const functionParams = sourceCode.getText(node.params);
24
+ const asyncKeyword = node.async ? 'async ' : '';
25
+
26
+ let functionDeclaration;
27
+
28
+ if (node.body.type === 'BlockStatement') {
29
+ functionDeclaration = `${asyncKeyword}function ${varName}(${functionParams}) ${functionBody}`;
30
+ } else {
31
+ // For concise body (single expression)
32
+ functionDeclaration = `${asyncKeyword}function ${varName}(${functionParams}) { return ${functionBody}; }`;
33
+ }
34
+
35
+ return fixer.replaceText(node.parent, functionDeclaration);
36
+ }
37
+
38
+ if (node.type === 'FunctionExpression') {
39
+ // Convert anonymous function expression to named function declaration
40
+ const functionBody = sourceCode.getText(node.body);
41
+ const functionParams = sourceCode.getText(node.params);
42
+ const asyncKeyword = node.async ? 'async ' : '';
43
+ const generatorKeyword = node.generator ? '*' : '';
44
+
45
+ const functionDeclaration = `${asyncKeyword}function ${generatorKeyword}${varName}(${functionParams}) ${functionBody}`;
46
+ return fixer.replaceText(node.parent, functionDeclaration);
47
+ }
48
+
49
+ return null;
50
+ },
51
+ });
52
+ }
53
+
54
+ return {
55
+ Program(programNode) {
56
+ programNode.body.forEach((node) => {
57
+ // Handle VariableDeclaration (e.g. const function_ = () => {})
58
+ if (node.type === 'VariableDeclaration') {
59
+ node.declarations.forEach((declaration) => {
60
+ // Ensure that declaration.init is defined and that it's a function expression or arrow function
61
+ if (
62
+ declaration.init &&
63
+ (declaration.init.type === 'ArrowFunctionExpression' || declaration.init.type === 'FunctionExpression')
64
+ ) {
65
+ const varName = declaration.id.name;
66
+ reportAndFix(declaration.init, varName);
67
+ }
68
+ });
69
+ }
70
+
71
+ // Handle anonymous top-level function declarations
72
+ if (node.type === 'FunctionDeclaration' && !node.id) {
73
+ reportAndFix(node, 'Anonymous');
74
+ }
75
+
76
+ // Handle ExpressionStatement for top-level arrow function (though uncommon)
77
+ if (node.type === 'ExpressionStatement' && node.expression.type === 'ArrowFunctionExpression') {
78
+ reportAndFix(node.expression, 'Anonymous');
79
+ }
80
+ });
81
+ },
82
+ };
83
+ },
84
+ };
@@ -12,6 +12,7 @@ const meta = {
12
12
  type: 'problem',
13
13
  docs: {
14
14
  description: 'Disallow comments except for specified allowed patterns.',
15
+ url: 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/no-comments.md'
15
16
  },
16
17
  fixable: 'code',
17
18
  schema: [
@@ -3,9 +3,10 @@
3
3
  const path = require('node:path');
4
4
 
5
5
  const meta = {
6
- type: 'suggestion',
6
+ type: 'problem',
7
7
  docs: {
8
8
  description: 'Convert unnamed default exports to named default exports based on the file name.',
9
+ url: 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/no-default-export.md'
9
10
  },
10
11
  fixable: 'code',
11
12
  schema: [],
@@ -20,6 +20,7 @@ const meta = {
20
20
  description: 'Disallow destructuring that does not meet certain conditions',
21
21
  category: 'Possible Errors',
22
22
  recommended: true,
23
+ url: 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/no-destructuring.md'
23
24
  },
24
25
  schema: [
25
26
  {
@@ -1,115 +0,0 @@
1
- /* eslint-disable unicorn/prefer-module */
2
-
3
- const { RuleTester } = require('eslint');
4
- const rule = require('../rules/no-comments.js');
5
-
6
- // Initialize RuleTester without the old parserOptions, using the new format
7
- const ruleTester = new RuleTester({
8
- parser: require.resolve('@babel/eslint-parser'),
9
- });
10
-
11
- ruleTester.run('no-comments', rule, {
12
- valid: [
13
- {
14
- code: `
15
- /**
16
- * JSDoc comment
17
- * @param {string} name - The name of the person.
18
- */
19
- function foo(name) {}
20
- `,
21
- },
22
- {
23
- code: `
24
- // TODO: this needs to be refactored
25
- const x = 5;
26
- `,
27
- },
28
- {
29
- code: `
30
- /* WARNING: temporary fix */
31
- const y = 10;
32
- `,
33
- },
34
- {
35
- code: `
36
- // eslint-disable-next-line no-console
37
- console.log("hello");
38
- `,
39
- },
40
- {
41
- code: `
42
- // keep this comment
43
- const z = 15;
44
- `,
45
- options: [{ allow: ['keep'] }],
46
- },
47
- ],
48
-
49
- invalid: [
50
- {
51
- code: `
52
- // Regular comment
53
- const a = 5;
54
- `,
55
- errors: [{ message: 'Comment not allowed.' }],
56
- output: `
57
- const a = 5;
58
- `,
59
- },
60
- {
61
- code: `
62
- // Some disallowed comment
63
- const b = 10;
64
- `,
65
- options: [{ disallow: ['disallowed'] }],
66
- errors: [{ message: 'Comment not allowed.' }],
67
- output: `
68
- const b = 10;
69
- `,
70
- },
71
- {
72
- code: `
73
- // DEPRECATED: Remove this function in the next version
74
- function deprecatedFunc() {}
75
- `,
76
- options: [{ disallow: ['deprecated'] }],
77
- errors: [{ message: 'Comment not allowed.' }],
78
- output: `
79
- function deprecatedFunc() {}
80
- `,
81
- },
82
- {
83
- code: `
84
- // important comment
85
- const c = 20;
86
- `,
87
- errors: [{ message: 'Comment not allowed.' }],
88
- output: `
89
- const c = 20;
90
- `,
91
- },
92
- {
93
- code: `
94
- // A completely random comment
95
- const d = 25;
96
- `,
97
- options: [{ allow: ['keep'] }],
98
- errors: [{ message: 'Comment not allowed.' }],
99
- output: `
100
- const d = 25;
101
- `,
102
- },
103
- {
104
- code: `
105
- // @ts-ignore
106
- const e = "typescript";
107
- `,
108
- options: [{ disallow: ['@ts-ignore'] }],
109
- errors: [{ message: 'Comment not allowed.' }],
110
- output: `
111
- const e = "typescript";
112
- `,
113
- },
114
- ],
115
- });
@@ -1,56 +0,0 @@
1
- const {RuleTester} = require('eslint');
2
- const rule = require('../../../lib/rules/no-default-export.js');
3
-
4
- const ruleTester = new RuleTester({
5
- parserOptions: {
6
- ecmaVersion: 2020,
7
- sourceType: 'module',
8
- },
9
- });
10
-
11
- ruleTester.run('no-unamed-default-export', rule, {
12
- valid: [
13
- // Already named exports should pass
14
- 'const a = 1; export default a;',
15
- 'export default function foo() {}',
16
- 'export default class Foo {}',
17
- ],
18
- invalid: [
19
- // Function exports without a name
20
- {
21
- code: 'export default function () {}',
22
- output: 'const Input = function () {};\nexport default Input;',
23
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
24
- },
25
- // Class exports without a name
26
- {
27
- code: 'export default class {}',
28
- output: 'const Input = class {};\nexport default Input;',
29
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
30
- },
31
- // Object literal exports
32
- {
33
- code: 'export default {}',
34
- output: 'const Input = {};\nexport default Input;',
35
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
36
- },
37
- // Primitive value exports
38
- {
39
- code: 'export default 42',
40
- output: 'const Input = 42;\nexport default Input;',
41
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
42
- },
43
- // Null exports
44
- {
45
- code: 'export default null',
46
- output: 'const Input = null;\nexport default Input;',
47
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
48
- },
49
- // Arrow function exports
50
- {
51
- code: 'export default () => {}',
52
- output: 'const Input = () => {};\nexport default Input;',
53
- errors: [{message: 'Unnamed default export should be named based on the file name.'}],
54
- },
55
- ],
56
- });
@@ -1,51 +0,0 @@
1
- const {RuleTester} = require('eslint');
2
- const rule = require('../../../lib/rules/no-destructuring.js');
3
-
4
- const ruleTester = new RuleTester({
5
- parserOptions: {
6
- ecmaVersion: 2020, // ES6 syntax
7
- sourceType: 'module', // Allows the use of imports
8
- },
9
- });
10
-
11
- ruleTester.run('no-destructuring', rule, {
12
- valid: [
13
- {
14
- code: 'const { a, b } = obj;',
15
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 80}],
16
- },
17
- {
18
- code: 'const { a } = obj;',
19
- options: [{maximumDestructuredVariables: 2, maximumLineLength: 80}],
20
- },
21
- {
22
- code: 'const { a, b, c } = obj;',
23
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 30}],
24
- },
25
- {
26
- code: 'function foo() {\n\tconst { a, b } = obj;\n}',
27
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 80}],
28
- },
29
- {
30
- code: '\tconst { a, b } = obj;',
31
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 80}],
32
- },
33
- ],
34
- invalid: [
35
- {
36
- code: 'const { a, b, c } = obj;',
37
- options: [{maximumDestructuredVariables: 2, maximumLineLength: 80}],
38
- errors: [{message: 'destructuring of more than 2 variables is not allowed'}],
39
- },
40
- {
41
- code: 'const { a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z } = obj;',
42
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 80}],
43
- errors: [{message: 'destructuring of more than 3 variables is not allowed'}, {message: 'destructuring on a line exceeding 80 characters is not allowed'}],
44
- },
45
- {
46
- code: 'function foo() {\n\t\t\t\t\t\t\tconst { a, b } = obj;\n}',
47
- options: [{maximumDestructuredVariables: 3, maximumLineLength: 80}],
48
- errors: [{message: 'destructuring at a nesting level above 3 is not allowed, instead saw 7 levels of nesting'}],
49
- },
50
- ],
51
- });