eslint-plugin-th-rules 1.11.4 → 1.12.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.
@@ -1 +1,5 @@
1
- {}
1
+ {
2
+ "cSpell.words": [
3
+ "sonarjs"
4
+ ]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "plugin:th-rules/recommended-typescript"
4
+ ]
5
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.12.0](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.11.4...v1.12.0) (2024-08-19)
2
+
3
+
4
+ ### Features
5
+
6
+ * created no-comments rule ([82dda49](https://github.com/tomerh2001/eslint-plugin-th-rules/commit/82dda49f7f4708b68b8a4bd81e5af3ca84519a43))
7
+
1
8
  ## [1.11.4](https://github.com/tomerh2001/eslint-plugin-th-rules/compare/v1.11.3...v1.11.4) (2024-08-19)
2
9
 
3
10
 
package/README.md CHANGED
@@ -59,3 +59,35 @@ This rule targets unnamed default exports and automatically generates a named ex
59
59
  }
60
60
  }
61
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
+ }
package/bun.lockb CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-th-rules",
3
- "version": "1.11.4",
3
+ "version": "1.12.0",
4
4
  "description": "A List of custom ESLint rules created by Tomer Horowitz",
5
5
  "keywords": [
6
6
  "eslint",
@@ -18,16 +18,17 @@
18
18
  "update:eslint-docs": "eslint-doc-generator"
19
19
  },
20
20
  "dependencies": {
21
+ "@babel/eslint-parser": "^7.25.1",
21
22
  "eslint-config-jsdoc": "^15.4.0",
22
23
  "eslint-config-xo": "^0.46.0",
23
24
  "eslint-config-xo-react": "^0.27.0",
24
25
  "eslint-plugin-jsdoc": "^50.2.2",
25
- "eslint-plugin-no-comments": "^1.1.10",
26
26
  "eslint-plugin-react": "^7.35.0",
27
27
  "eslint-plugin-react-hooks": "^4.6.2",
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
32
  "requireindex": "^1.2.0"
32
33
  },
33
34
  "devDependencies": {
package/src/index.js CHANGED
@@ -18,6 +18,7 @@ configs.recommended = {
18
18
  rules: {
19
19
  'th-rules/no-destructuring': 'error',
20
20
  'th-rules/no-default-export': 'error',
21
+ 'th-rules/no-comments': 'error',
21
22
  'unicorn/prefer-module': 'warn',
22
23
  'unicorn/filename-case': 'off',
23
24
  'unicorn/no-array-callback-reference': 'off',
@@ -26,14 +27,9 @@ configs.recommended = {
26
27
  'unicorn/no-await-expression-member': 'off',
27
28
  'new-cap': 'off',
28
29
  'no-await-in-loop': 'off',
30
+ 'n/file-extension-in-import': 'off',
31
+ 'import/no-cycle': 'off',
29
32
  camelcase: 'warn',
30
- 'no-comments/disallowComments': [
31
- 'error',
32
- {
33
- allow: ['^\\*\\*', 'eslint-disable', 'global', 'TODO', 'FIXME', 'NOTE', 'DEBUG'],
34
- },
35
- ],
36
-
37
33
  },
38
34
  env: {
39
35
  node: true,
@@ -43,7 +39,7 @@ configs.recommended = {
43
39
  };
44
40
 
45
41
  for (const configName of Object.keys(configs)) {
46
- configs[configName + '-typescript'] = {
42
+ configs[`${configName}-typescript`] = {
47
43
  ...configs[configName],
48
44
  extends: [
49
45
  'plugin:@typescript-eslint/strict-type-checked',
@@ -0,0 +1,96 @@
1
+ /* eslint-disable unicorn/prefer-module */
2
+
3
+ const allowedPatterns = [
4
+ /todo/i, // Allow TODO (case-insensitive)
5
+ /warning/i, // Allow WARNING (case-insensitive)
6
+ /error/i, // Allow ERROR (case-insensitive)
7
+ /info/i, // Allow INFO (case-insensitive)
8
+ /^\s*eslint-(disable|enable|env|globals|ignore|directive)/, // Allow ESLint directives
9
+ ];
10
+
11
+ const meta = {
12
+ type: 'problem',
13
+ docs: {
14
+ description: 'Disallow comments except for specified allowed patterns.',
15
+ },
16
+ fixable: 'code',
17
+ schema: [
18
+ {
19
+ type: 'object',
20
+ properties: {
21
+ allow: {
22
+ type: 'array',
23
+ items: {
24
+ type: 'string',
25
+ },
26
+ description: 'Additional patterns to allow in comments.',
27
+ },
28
+ disallow: {
29
+ type: 'array',
30
+ items: {
31
+ type: 'string',
32
+ },
33
+ description: 'Additional patterns to disallow in comments.',
34
+ },
35
+ },
36
+ additionalProperties: false,
37
+ },
38
+ ],
39
+ };
40
+
41
+ function create(context) {
42
+ const options = context.options[0] || {};
43
+ const userAllowedPatterns = (options.allow || []).map((pattern) => new RegExp(pattern));
44
+ const userDisallowedPatterns = (options.disallow || []).map((pattern) => new RegExp(pattern));
45
+
46
+ function isCommentAllowed(comment) {
47
+ const text = comment.value.trim();
48
+
49
+ // Check if the comment is a valid JSDoc comment
50
+ if (comment.type === 'Block' && comment.value.startsWith('*')) {
51
+ return true; // Allow any JSDoc-style block comment (/** ... */)
52
+ }
53
+
54
+ // Check if the comment matches any allowed pattern
55
+ for (const pattern of [...allowedPatterns, ...userAllowedPatterns]) {
56
+ if (pattern.test(text)) {
57
+ return true;
58
+ }
59
+ }
60
+
61
+ // Check if the comment matches any disallowed pattern
62
+ for (const pattern of userDisallowedPatterns) {
63
+ if (pattern.test(text)) {
64
+ return false;
65
+ }
66
+ }
67
+
68
+ return false; // Disallow by default if no match
69
+ }
70
+
71
+ return {
72
+ Program() {
73
+ const sourceCode = context.getSourceCode();
74
+ const comments = sourceCode.getAllComments();
75
+
76
+ comments.forEach((comment) => {
77
+ if (!isCommentAllowed(comment)) {
78
+ context.report({
79
+ node: comment,
80
+ message: 'Comment not allowed.',
81
+ fix(fixer) {
82
+ return fixer.remove(comment);
83
+ },
84
+ });
85
+ }
86
+ });
87
+ },
88
+ };
89
+ }
90
+
91
+ const rule = {
92
+ meta,
93
+ create,
94
+ };
95
+
96
+ module.exports = rule;
@@ -0,0 +1,115 @@
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
+ });