linter-bundle 6.3.0 → 7.1.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 (156) hide show
  1. package/.linter-bundle.js +27 -17
  2. package/.linter-bundle.schema.json +45 -0
  3. package/CHANGELOG.md +146 -3
  4. package/README.md +56 -63
  5. package/TODO.md +0 -58
  6. package/eslint/gatsby.mjs +95 -0
  7. package/eslint/index.mjs +1146 -0
  8. package/eslint/javascript-lazy.mjs +24 -0
  9. package/eslint/javascript.mjs +126 -0
  10. package/eslint/jest.mjs +175 -0
  11. package/eslint/jsdoc.mjs +103 -0
  12. package/eslint/react.mjs +244 -0
  13. package/eslint/rules/enforce-logical-expression-parens.md +31 -0
  14. package/eslint/rules/enforce-logical-expression-parens.mjs +39 -0
  15. package/eslint/rules/enforce-ternary-parens.md +29 -0
  16. package/eslint/rules/enforce-ternary-parens.mjs +39 -0
  17. package/eslint/rules/ensure-lucide-import-consistency.md +38 -0
  18. package/eslint/rules/ensure-lucide-import-consistency.mjs +112 -0
  19. package/eslint/rules/helper/is-parenthesized.mjs +40 -0
  20. package/eslint/rules/no-extra-spaces-in-generics.md +25 -0
  21. package/eslint/rules/no-extra-spaces-in-generics.mjs +55 -0
  22. package/eslint/rules/no-ternary-return.md +29 -0
  23. package/eslint/rules/no-ternary-return.mjs +50 -0
  24. package/eslint/rules/no-unnecessary-typeof.md +1 -1
  25. package/eslint/rules/{no-unnecessary-typeof.js → no-unnecessary-typeof.mjs} +14 -21
  26. package/eslint/rules/restricted-filenames.md +4 -4
  27. package/eslint/rules/{restricted-filenames.js → restricted-filenames.mjs} +7 -7
  28. package/eslint/storybook.mjs +42 -0
  29. package/eslint/type-declarations.mjs +49 -0
  30. package/eslint/{overrides-worker.cjs → worker.mjs} +12 -14
  31. package/eslint.mjs +5 -0
  32. package/files/index.js +3 -3
  33. package/helper/{ensure-type.cjs → ensure-type.mjs} +7 -6
  34. package/helper/get-git-files.js +1 -1
  35. package/helper/get-outdated-dependencies.js +4 -4
  36. package/helper/get-outdated-overrides.js +2 -2
  37. package/helper/get-stylelint-path.js +4 -3
  38. package/helper/is-npm-or-yarn.js +2 -2
  39. package/helper/linter-bundle-config.js +9 -14
  40. package/helper/run-process.js +6 -4
  41. package/lint.js +33 -24
  42. package/package.json +32 -29
  43. package/stylelint/index.mjs +1111 -0
  44. package/stylelint/plugins/stylelint-15.11.0-stylistic/html-tags/{index.cjs → index.mjs} +1 -1
  45. package/stylelint/plugins/stylelint-15.11.0-stylistic/reference/{selectors.cjs → selectors.mjs} +15 -31
  46. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/at-rule-name-case/{index.cjs → index.mjs} +6 -12
  47. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/at-rule-name-space-after/{index.cjs → index.mjs} +11 -13
  48. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/at-rule-semicolon-newline-after/{index.cjs → index.mjs} +18 -22
  49. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/at-rule-semicolon-space-before/{index.cjs → index.mjs} +10 -9
  50. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{atRuleNameSpaceChecker.cjs → atRuleNameSpaceChecker.mjs} +4 -3
  51. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-closing-brace-empty-line-before/{index.cjs → index.mjs} +16 -30
  52. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-closing-brace-newline-after/{index.cjs → index.mjs} +13 -35
  53. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-closing-brace-newline-before/{index.cjs → index.mjs} +11 -40
  54. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-closing-brace-space-before/{index.cjs → index.mjs} +10 -27
  55. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-opening-brace-newline-after/{index.cjs → index.mjs} +14 -65
  56. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-opening-brace-space-after/{index.cjs → index.mjs} +13 -30
  57. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/block-opening-brace-space-before/{index.cjs → index.mjs} +14 -27
  58. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/color-hex-case/{index.cjs → index.mjs} +10 -16
  59. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-bang-space-after/index.mjs +93 -0
  60. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-bang-space-before/{index.cjs → index.mjs} +11 -12
  61. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-block-semicolon-newline-after/{index.cjs → index.mjs} +11 -29
  62. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-block-semicolon-newline-before/{index.cjs → index.mjs} +9 -8
  63. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-block-semicolon-space-after/{index.cjs → index.mjs} +10 -23
  64. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-block-semicolon-space-before/{index.cjs → index.mjs} +11 -36
  65. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-block-trailing-semicolon/{index.cjs → index.mjs} +9 -27
  66. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-colon-newline-after/{index.cjs → index.mjs} +9 -25
  67. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-colon-space-after/{index.cjs → index.mjs} +8 -9
  68. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-colon-space-before/{index.cjs → index.mjs} +8 -9
  69. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{declarationBangSpaceChecker.cjs → declarationBangSpaceChecker.mjs} +5 -4
  70. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{declarationColonSpaceChecker.cjs → declarationColonSpaceChecker.mjs} +5 -4
  71. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{findMediaOperator.cjs → findMediaOperator.mjs} +2 -2
  72. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-comma-newline-after/{index.cjs → index.mjs} +8 -9
  73. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-comma-newline-before/{index.cjs → index.mjs} +8 -9
  74. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-comma-space-after/{index.cjs → index.mjs} +8 -9
  75. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-comma-space-before/{index.cjs → index.mjs} +8 -9
  76. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-max-empty-lines/{index.cjs → index.mjs} +19 -39
  77. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-parentheses-newline-inside/{index.cjs → index.mjs} +19 -54
  78. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-parentheses-space-inside/{index.cjs → index.mjs} +21 -68
  79. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/function-whitespace-after/{index.cjs → index.mjs} +16 -31
  80. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{functionCommaSpaceChecker.cjs → functionCommaSpaceChecker.mjs} +8 -7
  81. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{functionCommaSpaceFix.cjs → functionCommaSpaceFix.mjs} +1 -1
  82. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/indentation/{index.cjs → index.mjs} +39 -64
  83. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/linebreaks/{index.cjs → index.mjs} +15 -44
  84. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/max-empty-lines/{index.cjs → index.mjs} +10 -49
  85. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/max-line-length/{index.cjs → index.mjs} +10 -9
  86. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-colon-space-after/{index.cjs → index.mjs} +8 -9
  87. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-colon-space-before/{index.cjs → index.mjs} +8 -9
  88. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-name-case/{index.cjs → index.mjs} +9 -16
  89. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-parentheses-space-inside/{index.cjs → index.mjs} +8 -21
  90. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-range-operator-space-after/{index.cjs → index.mjs} +10 -11
  91. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-feature-range-operator-space-before/{index.cjs → index.mjs} +10 -11
  92. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-query-list-comma-newline-after/{index.cjs → index.mjs} +8 -9
  93. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-query-list-comma-newline-before/{index.cjs → index.mjs} +6 -6
  94. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-query-list-comma-space-after/{index.cjs → index.mjs} +8 -9
  95. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/media-query-list-comma-space-before/{index.cjs → index.mjs} +8 -9
  96. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{mediaFeatureColonSpaceChecker.cjs → mediaFeatureColonSpaceChecker.mjs} +5 -4
  97. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{mediaQueryListCommaWhitespaceChecker.cjs → mediaQueryListCommaWhitespaceChecker.mjs} +6 -5
  98. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/no-empty-first-line/{index.cjs → index.mjs} +6 -20
  99. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/no-eol-whitespace/{index.cjs → index.mjs} +13 -16
  100. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/no-extra-semicolons/{index.cjs → index.mjs} +10 -33
  101. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/no-missing-end-of-source-newline/{index.cjs → index.mjs} +7 -13
  102. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/number-leading-zero/{index.cjs → index.mjs} +13 -31
  103. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/number-no-trailing-zeros/{index.cjs → index.mjs} +9 -18
  104. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/property-case/{index.cjs → index.mjs} +10 -16
  105. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-attribute-brackets-space-inside/{index.cjs → index.mjs} +9 -36
  106. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-attribute-operator-space-after/{index.cjs → index.mjs} +7 -8
  107. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-attribute-operator-space-before/{index.cjs → index.mjs} +7 -8
  108. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-combinator-space-after/{index.cjs → index.mjs} +7 -8
  109. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-combinator-space-before/{index.cjs → index.mjs} +7 -8
  110. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-descendant-combinator-no-non-space/{index.cjs → index.mjs} +9 -20
  111. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-list-comma-newline-after/{index.cjs → index.mjs} +9 -14
  112. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-list-comma-newline-before/{index.cjs → index.mjs} +7 -8
  113. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-list-comma-space-after/{index.cjs → index.mjs} +7 -8
  114. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-list-comma-space-before/{index.cjs → index.mjs} +7 -8
  115. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-max-empty-lines/{index.cjs → index.mjs} +10 -21
  116. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-pseudo-class-case/{index.cjs → index.mjs} +10 -24
  117. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-pseudo-class-parentheses-space-inside/{index.cjs → index.mjs} +12 -35
  118. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/selector-pseudo-element-case/{index.cjs → index.mjs} +10 -15
  119. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{selectorAttributeOperatorSpaceChecker.cjs → selectorAttributeOperatorSpaceChecker.mjs} +6 -5
  120. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{selectorCombinatorSpaceChecker.cjs → selectorCombinatorSpaceChecker.mjs} +12 -11
  121. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{selectorListCommaWhitespaceChecker.cjs → selectorListCommaWhitespaceChecker.mjs} +5 -4
  122. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/string-quotes/{index.cjs → index.mjs} +43 -65
  123. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/unicode-bom/{index.cjs → index.mjs} +5 -5
  124. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/unit-case/{index.cjs → index.mjs} +17 -34
  125. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/value-list-comma-newline-after/{index.cjs → index.mjs} +11 -12
  126. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/value-list-comma-newline-before/{index.cjs → index.mjs} +6 -6
  127. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/value-list-comma-space-after/{index.cjs → index.mjs} +10 -11
  128. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/value-list-comma-space-before/{index.cjs → index.mjs} +10 -11
  129. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/value-list-max-empty-lines/{index.cjs → index.mjs} +12 -18
  130. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/{valueListCommaWhitespaceChecker.cjs → valueListCommaWhitespaceChecker.mjs} +6 -5
  131. package/stylelint/plugins/stylelint-15.11.0-stylistic/style-search/{index.cjs → index.mjs} +1 -1
  132. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/{addEmptyLineAfter.cjs → addEmptyLineAfter.mjs} +1 -1
  133. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/{hasEmptyBlock.cjs → hasEmptyBlock.mjs} +2 -2
  134. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/{nextNonCommentNode.cjs → nextNonCommentNode.mjs} +1 -1
  135. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/{removeEmptyLinesAfter.cjs → removeEmptyLinesAfter.mjs} +1 -1
  136. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/transformSelector.mjs +19 -0
  137. package/stylelint/plugins/stylelint-15.11.0-stylistic/utils/{whitespaceChecker.cjs → whitespaceChecker.mjs} +5 -5
  138. package/stylelint/plugins/stylelint-selector-no-empty.js +2 -0
  139. package/stylelint/plugins/stylelint-selector-tag-no-without-class.js +2 -2
  140. package/stylelint.mjs +6 -0
  141. package/eslint/index.cjs +0 -1071
  142. package/eslint/overrides-gatsby.cjs +0 -108
  143. package/eslint/overrides-javascript-lazy.cjs +0 -27
  144. package/eslint/overrides-javascript.cjs +0 -121
  145. package/eslint/overrides-jest.cjs +0 -144
  146. package/eslint/overrides-jsdoc.cjs +0 -94
  147. package/eslint/overrides-react.cjs +0 -220
  148. package/eslint/overrides-storybook.cjs +0 -44
  149. package/eslint/overrides-type-declarations.cjs +0 -51
  150. package/eslint/rules/no-global-undefined-check.js +0 -85
  151. package/eslint/rules/no-global-undefined-check.md +0 -34
  152. package/eslint/rules/package.json +0 -8
  153. package/eslint.cjs +0 -5
  154. package/stylelint/index.cjs +0 -1104
  155. package/stylelint/plugins/stylelint-15.11.0-stylistic/rules/declaration-bang-space-after/index.cjs +0 -95
  156. package/stylelint.cjs +0 -5
@@ -0,0 +1,31 @@
1
+ # Enforce parentheses around logical operations (`linter-bundle/enforce-logical-expression-parens`)
2
+
3
+ ## Rule Details
4
+
5
+ This rule ensures that logical operations (using `&&`, `||`, etc.) are always enclosed in parentheses unless they are already part of an existing expression. This improves readability and prevents potential issues with operator precedence.
6
+
7
+ Examples of **incorrect** code for this rule:
8
+
9
+ ```ts
10
+ return foo !== null && foo.bar === 42 && baz === 84;
11
+ ```
12
+
13
+ The logical operations in the above code are not enclosed in parentheses. The rule will automatically add parentheses to make the code clearer and ensure proper precedence.
14
+
15
+ Corrected code would look like this:
16
+
17
+ ```ts
18
+ return (foo !== null && foo.bar === 42 && baz === 84);
19
+ ```
20
+
21
+ ### When the rule will not apply
22
+
23
+ If the logical operations are already inside parentheses, no changes will be made:
24
+
25
+ ```ts
26
+ if (foo !== null && foo.bar === 42 && baz === 84) {
27
+ // code
28
+ }
29
+ ```
30
+
31
+ In this case, the code is already correctly wrapped in parentheses, so no further modifications are necessary.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @file ESLint rule which ensures logical operations are wrapped in parentheses.
3
+ */
4
+
5
+ import { isParenthesized } from './helper/is-parenthesized.mjs';
6
+
7
+ /**
8
+ * @type {import('eslint').Rule.RuleModule}
9
+ */
10
+ export default {
11
+ meta: {
12
+ type: 'problem',
13
+ docs: {
14
+ description: 'Add parentheses around logical operations if not already present',
15
+ category: 'Best Practices',
16
+ recommended: false
17
+ },
18
+ fixable: 'code'
19
+ },
20
+ create (context) {
21
+ return {
22
+ LogicalExpression (node) {
23
+ // Check if the parent node is a logical expression
24
+ if (node.parent.type === 'LogicalExpression' || isParenthesized(context, node)) {
25
+ return; // Do not add parentheses if they are already present
26
+ }
27
+
28
+ // If no parentheses are present, add parentheses around the logical operation
29
+ context.report({
30
+ node,
31
+ message: 'Add parentheses around the logical operation.',
32
+ fix (fixer) {
33
+ return fixer.replaceText(node, `(${context.getSourceCode().getText(node)})`);
34
+ }
35
+ });
36
+ }
37
+ };
38
+ }
39
+ };
@@ -0,0 +1,29 @@
1
+ # Enforce parentheses around ternary expressions (`linter-bundle/enforce-ternary-parens`)
2
+
3
+ ## Rule Details
4
+
5
+ This rule enforces that ternary expressions are always wrapped in parentheses to improve readability and maintain consistency in code formatting.
6
+
7
+ ### Examples of **incorrect** code for this rule
8
+
9
+ ```ts
10
+ const foo = bar ? 1 : 2;
11
+ const value = condition ? 'yes' : 'no';
12
+ ```
13
+
14
+ ### Examples of **correct** code for this rule
15
+
16
+ ```ts
17
+ const foo = (bar ? 1 : 2);
18
+ const value = (condition ? 'yes' : 'no');
19
+ ```
20
+
21
+ ## Why is this rule useful?
22
+
23
+ - **Improved readability**: Wrapping ternary expressions in parentheses makes it clear that the entire expression is evaluated together.
24
+ - **Consistency**: Ensures a uniform style when using the ternary operator.
25
+ - **Avoids ambiguity**: Helps prevent misunderstandings in complex expressions.
26
+
27
+ ## Fixable
28
+
29
+ This rule is fixable. It will automatically wrap ternary expressions in parentheses.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @file ESLint rule which ensures ternary expressions are wrapped in parentheses.
3
+ */
4
+
5
+ import { isParenthesized } from './helper/is-parenthesized.mjs';
6
+
7
+ /**
8
+ * @type {import('eslint').Rule.RuleModule}
9
+ */
10
+ export default {
11
+ meta: {
12
+ type: 'problem',
13
+ fixable: 'code',
14
+ docs: {
15
+ description: 'Requires ternary expressions to be wrapped in parentheses.',
16
+ category: 'Styling',
17
+ recommended: false
18
+ }
19
+ },
20
+
21
+ create (context) {
22
+ return {
23
+ ConditionalExpression (node) {
24
+ if (isParenthesized(context, node)) {
25
+ return;
26
+ }
27
+
28
+ context.report({
29
+ node,
30
+ message: 'Ternary expressions must be wrapped in parentheses.',
31
+ fix (fixer) {
32
+ // Wrap the entire ternary expression in parentheses.
33
+ return fixer.replaceText(node, `(${context.sourceCode.getText(node)})`);
34
+ }
35
+ });
36
+ }
37
+ };
38
+ }
39
+ };
@@ -0,0 +1,38 @@
1
+ # Enforces using Lucide prefix for lucide-react imports and their usage (`linter-bundle/ensure-lucide-import-consistency`)
2
+
3
+ ## Rule Details
4
+
5
+ This rule ensures that components imported from `lucide-react` are used with a `Lucide` prefix. It checks both the import statements and the JSX or JavaScript usage of these components.
6
+ If a component does not follow this convention, it will be automatically fixed by replacing the component name with the properly prefixed name (`Lucide`).
7
+
8
+ ### Correct Usage
9
+
10
+ When importing components from `lucide-react`, the component name should start with the `Lucide` prefix.
11
+
12
+ #### Correct Code Example
13
+
14
+ ```ts
15
+ import { LucideHome } from 'lucide-react';
16
+
17
+ <LucideHome />
18
+ ```
19
+
20
+ #### Incorrect Code Example
21
+
22
+ ```ts
23
+ import { Home } from 'lucide-react';
24
+
25
+ <Home />
26
+ ```
27
+
28
+ ### Rule Behavior
29
+
30
+ - **Import Declarations**: If a component from `lucide-react` is imported without the `Lucide` prefix, the rule will automatically rename it to add the `Lucide` prefix.
31
+
32
+ - **JSX Usage**: In JSX, if a component is used without the `Lucide` prefix (even if correctly imported), it will be reported and fixed.
33
+
34
+ - **JavaScript Usage**: For non-JSX usage (e.g., when components are referenced via `React.createElement` or directly as identifiers), the rule will also ensure the correct `Lucide` prefix is applied.
35
+
36
+ ## Fixable
37
+
38
+ This rule is fixable. It will automatically rename components and their usages to ensure they follow the `Lucide` prefix convention.
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @file ESLint rule which enforces using Lucide prefix for lucide-react imports and their usage.
3
+ */
4
+
5
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
6
+
7
+ /**
8
+ * @typedef {'alternative'} MessageIds
9
+ */
10
+
11
+ /** @type {import('@typescript-eslint/utils/ts-eslint').RuleModule<MessageIds>} */
12
+ export default {
13
+ meta: {
14
+ type: 'suggestion',
15
+ docs: {
16
+ description: 'Enforces using Lucide prefix for lucide-react imports and their usage',
17
+ category: 'Best Practices',
18
+ recommended: true
19
+ },
20
+ messages: {
21
+ alternative: 'Please use "{{lucideName}}" instead of "{{componentName}}"'
22
+ },
23
+ schema: [],
24
+ fixable: 'code'
25
+ },
26
+ defaultOptions: [],
27
+ create (context) {
28
+ // Track renamed imports from lucide-react
29
+ const renamedImports = new Map();
30
+
31
+ return {
32
+ ImportDeclaration (node) {
33
+ if (node.source.value === 'lucide-react') {
34
+ for (const specifier of node.specifiers) {
35
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {
36
+ const importedName = /** @type {any} */(specifier.imported).name;
37
+ const localName = specifier.local.name;
38
+
39
+ if (!importedName.startsWith('Lucide')) {
40
+ const lucideName = `Lucide${importedName.replace(/Icon$/u, '')}`;
41
+
42
+ // Store the mapping of local name to Lucide name
43
+ renamedImports.set(localName, lucideName);
44
+
45
+ context.report({
46
+ node: specifier,
47
+ messageId: 'alternative',
48
+ data: { lucideName, importedName },
49
+ fix (fixer) {
50
+ return fixer.replaceText(
51
+ specifier.imported,
52
+ lucideName
53
+ );
54
+ }
55
+ });
56
+ }
57
+ }
58
+ }
59
+ }
60
+ },
61
+
62
+ // Fix JSX usage
63
+ JSXIdentifier (node) {
64
+ // Only check opening elements, not attributes
65
+ if (node.parent.type === AST_NODE_TYPES.JSXOpeningElement || node.parent.type === AST_NODE_TYPES.JSXClosingElement) {
66
+ const componentName = node.name;
67
+
68
+ if (renamedImports.has(componentName)) {
69
+ /** @type {string} */
70
+ const lucideName = renamedImports.get(componentName);
71
+
72
+ context.report({
73
+ node,
74
+ messageId: 'alternative',
75
+ data: { lucideName, componentName },
76
+ fix (fixer) {
77
+ return fixer.replaceText(node, lucideName);
78
+ }
79
+ });
80
+ }
81
+ }
82
+ },
83
+
84
+ // Fix JS usage (for non-JSX cases like React.createElement)
85
+ Identifier (node) {
86
+ // Exclude import declarations (already handled) and JSX (handled separately)
87
+ if (
88
+ node.parent.type !== AST_NODE_TYPES.ImportSpecifier &&
89
+ node.parent.type !== AST_NODE_TYPES.JSXIdentifier &&
90
+ node.parent.type !== AST_NODE_TYPES.JSXOpeningElement &&
91
+ node.parent.type !== AST_NODE_TYPES.JSXClosingElement
92
+ ) {
93
+ const componentName = node.name;
94
+
95
+ if (renamedImports.has(componentName)) {
96
+ /** @type {string} */
97
+ const lucideName = renamedImports.get(componentName);
98
+
99
+ context.report({
100
+ node,
101
+ messageId: 'alternative',
102
+ data: { lucideName, componentName },
103
+ fix (fixer) {
104
+ return fixer.replaceText(node, lucideName);
105
+ }
106
+ });
107
+ }
108
+ }
109
+ }
110
+ };
111
+ }
112
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file ESLint helper function to check if an ESLint Rule Node is wrapped in parentheses.
3
+ */
4
+
5
+ /**
6
+ * Helper function to check if the node is wrapped in parentheses.
7
+ *
8
+ * @param {import('eslint').Rule.RuleContext} context - The rule context.
9
+ * @param {import('eslint').Rule.Node} node - The expression node.
10
+ * @returns {boolean} Returns `true` with the node is wrapped by parens.
11
+ */
12
+ export function isParenthesized (context, node) {
13
+ const { sourceCode } = context;
14
+
15
+ const firstToken = sourceCode.getFirstToken(node);
16
+
17
+ if (!firstToken) {
18
+ return false;
19
+ }
20
+
21
+ const lastToken = sourceCode.getLastToken(node);
22
+
23
+ if (!lastToken) {
24
+ return false;
25
+ }
26
+
27
+ const tokenBefore = sourceCode.getTokenBefore(firstToken);
28
+
29
+ if (!tokenBefore) {
30
+ return false;
31
+ }
32
+
33
+ const tokenAfter = sourceCode.getTokenAfter(lastToken);
34
+
35
+ if (!tokenAfter) {
36
+ return false;
37
+ }
38
+
39
+ return (tokenBefore.value === '(' && tokenAfter.value === ')');
40
+ }
@@ -0,0 +1,25 @@
1
+ # Disallow spaces in TypeScript generics (`linter-bundle/no-spaces-in-generics`)
2
+
3
+ ## Rule Details
4
+
5
+ This rule disallows spaces after the `<` and before the `>` in TypeScript generics. Ensuring that no unnecessary spaces are used around generics helps maintain consistency and readability in your code.
6
+
7
+ Examples of **incorrect** code for this rule:
8
+
9
+ ```ts
10
+ declare function foo< T>(x: T): T; // Space after '<'
11
+
12
+ function bar<U >(): U { // Space before '>'
13
+ return null as U;
14
+ }
15
+ ```
16
+
17
+ Examples of **correct** code for this rule:
18
+
19
+ ```ts
20
+ declare function foo<T>(x: T): T;
21
+
22
+ function bar<U>(): U {
23
+ return null as U;
24
+ }
25
+ ```
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @file ESLint rule which disallows spaces after '<' and before '>' in TypeScript generics.
3
+ */
4
+
5
+ /**
6
+ * @typedef {'noSpaceAfterLessThan' | 'noSpaceBeforeGreaterThan'} MessageIds
7
+ */
8
+
9
+ /** @type {import('@typescript-eslint/utils/ts-eslint').RuleModule<MessageIds>} */
10
+ export default {
11
+ meta: {
12
+ type: 'problem',
13
+ docs: {
14
+ description: "Disallow spaces after '<' and before '>' in TypeScript generics.",
15
+ category: 'Stylistic Issues',
16
+ recommended: false
17
+ },
18
+ fixable: 'whitespace',
19
+ schema: [],
20
+ messages: {
21
+ noSpaceAfterLessThan: "No space allowed after '<' in generics.",
22
+ noSpaceBeforeGreaterThan: "No space allowed before '>' in generics."
23
+ }
24
+ },
25
+ defaultOptions: [],
26
+ create (context) {
27
+ return {
28
+ TSTypeParameterInstantiation (node) {
29
+ const text = context.sourceCode.getText(node);
30
+
31
+ // Check for space after "<"
32
+ if ((/<[ \t]+/u).test(text)) {
33
+ context.report({
34
+ node,
35
+ messageId: 'noSpaceAfterLessThan',
36
+ fix (fixer) {
37
+ return fixer.replaceText(node, text.replace(/<[ \t]+/u, '<'));
38
+ }
39
+ });
40
+ }
41
+
42
+ // Check for space before ">"
43
+ if ((/[ \t]+>/u).test(text)) {
44
+ context.report({
45
+ node,
46
+ messageId: 'noSpaceBeforeGreaterThan',
47
+ fix (fixer) {
48
+ return fixer.replaceText(node, text.replace(/[ \t]+>/u, '>'));
49
+ }
50
+ });
51
+ }
52
+ }
53
+ };
54
+ }
55
+ };
@@ -0,0 +1,29 @@
1
+ # Disallow ternary expressions as return values (`linter-bundle/no-ternary-return`)
2
+
3
+ ## Rule Details
4
+
5
+ To improve code readability, this rule disallows using ternary expressions directly as return values. Instead, it enforces using explicit `if` statements.
6
+
7
+ ### Examples of **incorrect** code for this rule
8
+
9
+ ```ts
10
+ function getValue(condition: boolean) {
11
+ return condition ? "yes" : "no";
12
+ }
13
+ ```
14
+
15
+ ### Examples of **correct** code for this rule
16
+
17
+ ```ts
18
+ function getValue(condition: boolean) {
19
+ if (condition) {
20
+ return "yes";
21
+ }
22
+
23
+ return "no";
24
+ }
25
+ ```
26
+
27
+ ## Fixable
28
+
29
+ This rule is **fixable**. The autofix will transform ternary return expressions into an `if` statement followed by a separate `return`.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @file ESLint rule which disallows ternary expressions as return values for better readability.
3
+ */
4
+
5
+ /**
6
+ * @type {import('eslint').Rule.RuleModule}
7
+ */
8
+ export default {
9
+ meta: {
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Disallow ternary expressions as return values for better readability',
13
+ category: 'Stylistic Issues',
14
+ recommended: true
15
+ },
16
+ fixable: 'code',
17
+ schema: []
18
+ },
19
+ create (context) {
20
+ return {
21
+ ReturnStatement (node) {
22
+ if (node.argument && node.argument.type === 'ConditionalExpression') {
23
+ context.report({
24
+ node,
25
+ message: 'Avoid using ternary expressions as return values; use an if-else statement instead.',
26
+ fix (fixer) {
27
+ const sourceCode = context.sourceCode;
28
+ const argumentText = /** @type {any} */(node.argument)?.test;
29
+ const argumentConsequent = /** @type {any} */(node.argument)?.consequent;
30
+ const argumentAlternate = /** @type {any} */(node.argument)?.alternate;
31
+
32
+ if (!argumentText || !argumentConsequent || !argumentAlternate) {
33
+ return null;
34
+ }
35
+
36
+ const test = sourceCode.getText(argumentText);
37
+ const consequent = sourceCode.getText(argumentConsequent);
38
+ const alternate = sourceCode.getText(argumentAlternate);
39
+ const indent = (/^\s*/u).exec(sourceCode.getText(node))?.[0];
40
+
41
+ const fixedCode = `if (${test}) {\n${indent} return ${consequent};\n}\n\n${indent}return ${alternate};`;
42
+
43
+ return fixer.replaceText(node, fixedCode);
44
+ }
45
+ });
46
+ }
47
+ }
48
+ };
49
+ }
50
+ };
@@ -1,4 +1,4 @@
1
- # Disallow unnecessary `typeof` checks (`no-unnecessary-typeof`)
1
+ # Disallow unnecessary `typeof` checks (`linter-bundle/no-unnecessary-typeof`)
2
2
 
3
3
  ## Rule Details
4
4
 
@@ -2,41 +2,34 @@
2
2
  * @file ESLint rule which ensures that a `typeof` operant has more than one type in TypeScript, to prevent unnecessary checks of types at runtime.
3
3
  */
4
4
 
5
- /* eslint-disable unicorn/prefer-module -- For ESLint, we still need to rely on CommonJS modules */
6
-
7
5
  /** @typedef {ts.Type & { intrinsicName?: string; types?: ts.Type[]; objectFlags?: ts.ObjectFlags; }} Type */
8
6
 
9
- const ts = require('typescript');
7
+ import * as ts from 'typescript';
10
8
 
11
- const { ESLintUtils } = require('@typescript-eslint/utils');
9
+ import { ESLintUtils } from '@typescript-eslint/utils';
12
10
 
13
11
  /**
14
- * @type {import('eslint').Rule.RuleModule}
12
+ * @typedef {'text'} MessageIds
15
13
  */
16
- module.exports = {
14
+
15
+ /** @type {import('@typescript-eslint/utils/ts-eslint').RuleModule<MessageIds>} */
16
+ export default {
17
17
  meta: {
18
+ type: 'problem',
18
19
  docs: {
19
20
  description: 'If a `typeof` operant has only one type in TypeScript, it\'s unnecessary to check it\'s type at runtime.',
20
- recommended: true
21
+ recommended: true,
22
+ requiresTypeChecking: true
21
23
  },
22
24
  messages: {
23
25
  text: 'Unnecessary `typeof`, because the only possible type of {{ variableName }} is `{{ typeName }}`.'
24
- }
26
+ },
27
+ schema: []
25
28
  },
26
- /**
27
- * Create a new rule.
28
- *
29
- * @param {Readonly<import('@typescript-eslint/utils/ts-eslint').RuleContext<'text', []>>} context - RuleContext of @typescript-eslint instead of ESlint
30
- * @returns {import('@typescript-eslint/utils/ts-eslint').RuleListener} RuleListener of @typescript-eslint, instead of ESlint
31
- */
29
+ defaultOptions: [],
30
+
32
31
  create (context) {
33
32
  return {
34
- /**
35
- * Rule function to handle unary expressions.
36
- *
37
- * @param {import('@typescript-eslint/typescript-estree').TSESTree.UnaryExpression} node - UnaryExpression of @typescript-eslint instead of ESlint
38
- * @returns {import('@typescript-eslint/utils/ts-eslint').RuleFunction<import('@typescript-eslint/typescript-estree').TSESTree.UnaryExpression> | void} RuleFunction of @typescript-eslint instead of ESlint
39
- */
40
33
  UnaryExpression (node) {
41
34
  if (node.operator !== 'typeof') {
42
35
  return;
@@ -136,7 +129,7 @@ function getTypeString (checker, type) {
136
129
  * @returns {boolean} Returns `true` if the type is either `any` or `unknown`, or an object which is based on `unknown`
137
130
  */
138
131
  function isAnyOrUnknown (type) {
139
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- `symbol` on Object is `undefined` for `Omit<unknown, 'undefined'>`
132
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @todo I've seen `symbol` to be undefined. Is that an issue in the TypeScript type definition?
140
133
  return (type.flags === ts.TypeFlags.Any || type.flags === ts.TypeFlags.Unknown || (type.flags === ts.TypeFlags.Object && type.symbol === undefined));
141
134
  }
142
135
 
@@ -7,7 +7,7 @@ In projects in which several developers or even teams work together, it is impor
7
7
  Example configuration for this rule:
8
8
 
9
9
  ```js
10
- 'restricted-filenames': ['error', {
10
+ 'linter-bundle/restricted-filenames': ['error', {
11
11
  basePath: './src',
12
12
  allowed: [
13
13
  'components/**/index.tsx',
@@ -64,7 +64,7 @@ If both are set, `disallowed` wins over `allowed` and all unspecified files are
64
64
 
65
65
  Instead of defining the same complex patterns over and over again, e.g. for casing, you can write them into a variable and use them within the pattern, for example by using template strings.
66
66
 
67
- Example of `.eslintrc.cjs`:
67
+ Example of `eslint.config.mjs`:
68
68
 
69
69
  ```js
70
70
  const snippets = {
@@ -77,9 +77,9 @@ const snippets = {
77
77
  pascalCase: '[A-Z]*([a-zA-Z0-9])'
78
78
  };
79
79
 
80
- module.exports = {
80
+ export default {
81
81
  rules: {
82
- 'restricted-filenames': ['error', {
82
+ 'linter-bundle/restricted-filenames': ['error', {
83
83
  basePath: './src',
84
84
  allowed: [
85
85
  `components/${snippets.pascalCase}/index.tsx`,
@@ -2,19 +2,19 @@
2
2
  * @file ESLint rule which ensures that only files which match given glob patterns are part of your project.
3
3
  */
4
4
 
5
- /* eslint-disable unicorn/prefer-module -- For ESLint, we still need to rely on CommonJS modules */
5
+ import path from 'node:path';
6
6
 
7
- const path = require('node:path');
7
+ import micromatch from 'micromatch';
8
8
 
9
- const micromatch = require('micromatch');
9
+ // eslint-disable-next-line n/no-process-env -- If the ESLint sub-process is running from within the linter-bundle, we make use of its configuration.
10
+ const isInLinterBundle = !process.env['LINTER_BUNDLE'];
10
11
 
11
- // eslint-disable-next-line n/no-process-env -- Only merge the linter-bundle config, if the linting is not started by the linter-bundle CLI tool (e.g. if ESlint is running separately in VSCode), to get warnings shown there too
12
- const linterBundleConfig = (!process.env['LINTER_BUNDLE'] ? require('../../helper/linter-bundle-config.cjs').linterBundleConfig : undefined);
12
+ const { linterBundleConfig } = (isInLinterBundle ? await import('../../helper/linter-bundle-config.js') : {});
13
13
 
14
14
  /**
15
15
  * @type {import('eslint').Rule.RuleModule}
16
16
  */
17
- module.exports = {
17
+ export default {
18
18
  meta: {
19
19
  docs: {
20
20
  description: 'Restrict file and path names with given glob patterns.',
@@ -55,7 +55,7 @@ module.exports = {
55
55
  create: (context) => {
56
56
  const filePath = context.filename;
57
57
  /** @type {{ basePath: string, allowed?: string[]; disallowed?: string[]; }[]} */
58
- const options = linterBundleConfig?.files?.restrictions ? [...linterBundleConfig.files.restrictions, ...context.options] : context.options;
58
+ const options = (linterBundleConfig?.files?.restrictions ? [...linterBundleConfig.files.restrictions, ...context.options] : context.options);
59
59
 
60
60
  for (const { basePath, allowed, disallowed } of options) {
61
61
  const normalizedName = path.relative(path.join(process.cwd(), basePath), filePath);
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file Settings for Storybook configuration and stories.
3
+ */
4
+
5
+ export default [
6
+ {
7
+ files: ['**/*.stories.[jt]s?(x)'],
8
+ rules: {
9
+ /**
10
+ * eslint-plugin-import
11
+ *
12
+ * @see https://github.com/import-js/eslint-plugin-import
13
+ */
14
+ 'import/no-default-export': 'off'
15
+ }
16
+ },
17
+ {
18
+ files: ['.storybook/main.ts'],
19
+ rules: {
20
+ /**
21
+ * eslint-plugin-import
22
+ *
23
+ * @see https://github.com/import-js/eslint-plugin-import
24
+ */
25
+ 'import/no-nodejs-modules': 'off'
26
+ }
27
+ },
28
+ {
29
+ files: ['.storybook/preview.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
30
+ rules: {
31
+ /**
32
+ * eslint
33
+ *
34
+ * @see https://eslint.org/docs/rules/
35
+ */
36
+ 'no-underscore-dangle': ['error', {
37
+ allow: ['__BASE_PATH__', '___loader', '___navigate'],
38
+ allowAfterThis: true
39
+ }]
40
+ }
41
+ }
42
+ ];