eslint-plugin-wyrm 0.0.5 → 0.0.6

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 (33) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +7 -0
  3. package/dist/configs/index.js +3 -3
  4. package/dist/rules/index.d.ts +14 -7
  5. package/dist/rules/index.js +14 -0
  6. package/dist/rules/no-else-break.d.ts +7 -0
  7. package/dist/rules/no-else-break.js +51 -0
  8. package/dist/rules/no-else-continue.d.ts +7 -0
  9. package/dist/rules/no-else-continue.js +51 -0
  10. package/dist/rules/no-else-throw.d.ts +7 -0
  11. package/dist/rules/no-else-throw.js +51 -0
  12. package/dist/rules/no-empty-comment.d.ts +3 -3
  13. package/dist/rules/no-empty-jsx-expression.d.ts +2 -2
  14. package/dist/rules/no-extra-nested-boolean-cast.d.ts +2 -2
  15. package/dist/rules/no-invalid-date-literal.d.ts +7 -0
  16. package/dist/rules/no-invalid-date-literal.js +68 -0
  17. package/dist/rules/no-jsx-statement.d.ts +2 -2
  18. package/dist/rules/no-suspicious-jsx-semicolon.d.ts +8 -0
  19. package/dist/rules/no-suspicious-jsx-semicolon.js +39 -0
  20. package/dist/rules/no-ternary-return.d.ts +3 -3
  21. package/dist/rules/no-useless-iife.d.ts +7 -0
  22. package/dist/rules/no-useless-iife.js +93 -0
  23. package/dist/rules/prefer-repeat.d.ts +7 -0
  24. package/dist/rules/prefer-repeat.js +108 -0
  25. package/dist/utils/option.js +18 -0
  26. package/package.json +1 -1
  27. package/docs/rules/no-constant-template-expression.md +0 -83
  28. package/docs/rules/no-empty-comment.md +0 -70
  29. package/docs/rules/no-empty-jsx-expression.md +0 -77
  30. package/docs/rules/no-extra-nested-boolean-cast.md +0 -112
  31. package/docs/rules/no-jsx-statement.md +0 -36
  32. package/docs/rules/no-ternary-return.md +0 -46
  33. package/docs/rules/unsafe-asserted-chain.md +0 -68
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.6](https://github.com/mchevestrier/eslint-plugin-wyrm/compare/eslint-plugin-wyrm-v0.0.5...eslint-plugin-wyrm-v0.0.6) (2025-11-04)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * add no-else-break and no-else-continue ([eb2647f](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/eb2647feb3a5d04782a86db8324259afb70a5369))
9
+ * add no-else-throw ([cedc18e](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/cedc18efd6952c3c3195d378dbd59a8772b7613d))
10
+
3
11
  ## [0.0.5](https://github.com/mchevestrier/eslint-plugin-wyrm/compare/eslint-plugin-wyrm-v0.0.4...eslint-plugin-wyrm-v0.0.5) (2025-11-02)
4
12
 
5
13
 
package/README.md CHANGED
@@ -52,11 +52,18 @@ export default defineConfig([
52
52
  | Name                            | Description | 💼 | 🔧 | 💡 | 💭 |
53
53
  | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | :---------- | :-- | :-- | :-- |
54
54
  | [no-constant-template-expression](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-constant-template-expression.md) | Disallow constant string expressions in template literals | ☑️ | | 💡 | 💭 |
55
+ | [no-else-break](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-else-break.md) | Forbid unnecessary `else` block after a `break` statement | 🟩 ✅ 🟪 ☑️ | 🔧 | | |
56
+ | [no-else-continue](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-else-continue.md) | Forbid unnecessary `else` block after a `continue` statement | 🟩 ✅ 🟪 ☑️ | 🔧 | | |
57
+ | [no-else-throw](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-else-throw.md) | Forbid unnecessary `else` block after a `throw` statement | 🟩 ✅ 🟪 ☑️ | 🔧 | | |
55
58
  | [no-empty-comment](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-empty-comment.md) | Forbid empty comments | 🟪 ☑️ | | | |
56
59
  | [no-empty-jsx-expression](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-empty-jsx-expression.md) | Forbid empty JSX expression containers | 🟩 ✅ 🟪 ☑️ | | | |
57
60
  | [no-extra-nested-boolean-cast](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-extra-nested-boolean-cast.md) | Forbid extra boolean casts in conditions and predicates | 🟪 ☑️ | | | |
61
+ | [no-invalid-date-literal](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-invalid-date-literal.md) | Disallow invalid date literals | 🟩 ✅ 🟪 ☑️ | | | |
58
62
  | [no-jsx-statement](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-jsx-statement.md) | Forbid JSX expression statements | 🟩 ✅ 🟪 ☑️ | | | |
63
+ | [no-suspicious-jsx-semicolon](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-suspicious-jsx-semicolon.md) | Forbid suspicious semicolons in JSX | 🟩 ✅ 🟪 ☑️ | | | |
59
64
  | [no-ternary-return](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-ternary-return.md) | Disallow ternary conditions in return statements | 🟪 ☑️ | 🔧 | | |
65
+ | [no-useless-iife](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/no-useless-iife.md) | Forbid useless IIFEs | 🟩 ✅ 🟪 ☑️ | | 💡 | |
66
+ | [prefer-repeat](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/prefer-repeat.md) | Enforce usage of `String.prototype.repeat` | 🟩 ✅ 🟪 ☑️ | | 💡 | |
60
67
  | [unsafe-asserted-chain](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/master/packages/eslint-plugin-wyrm/docs/rules/unsafe-asserted-chain.md) | Disallow unsafe type assertions on optional chained expressions | ☑️ | | | 💭 |
61
68
 
62
69
  <!-- end auto-generated rules list -->
@@ -38,7 +38,7 @@ const strictOnly = createConfigWithRules(rules_exports, "strictOnly", (rule) =>
38
38
  });
39
39
  const strict = {
40
40
  ...baseConfig,
41
- name: `wyrm/strict`,
41
+ name: "wyrm/strict",
42
42
  rules: {
43
43
  ...recommended.rules,
44
44
  ...strictOnly.rules
@@ -51,7 +51,7 @@ const recommendedTypeCheckedOnly = createConfigWithRules(rules_exports, "recomme
51
51
  });
52
52
  const recommendedTypeChecked = {
53
53
  ...baseConfig,
54
- name: `wyrm/recommendedTypeChecked`,
54
+ name: "wyrm/recommendedTypeChecked",
55
55
  rules: {
56
56
  ...recommended.rules,
57
57
  ...recommendedTypeCheckedOnly.rules
@@ -64,7 +64,7 @@ const strictTypeCheckedOnly = createConfigWithRules(rules_exports, "strictTypeCh
64
64
  });
65
65
  const strictTypeChecked = {
66
66
  ...baseConfig,
67
- name: `wyrm/strictTypeChecked`,
67
+ name: "wyrm/strictTypeChecked",
68
68
  rules: {
69
69
  ...recommendedTypeChecked.rules,
70
70
  ...strictOnly.rules,
@@ -1,14 +1,21 @@
1
1
  import { _default } from "./no-constant-template-expression.js";
2
- import { _default as _default$1 } from "./no-empty-comment.js";
3
- import { _default as _default$2 } from "./no-empty-jsx-expression.js";
4
- import { _default as _default$3 } from "./no-extra-nested-boolean-cast.js";
5
- import { _default as _default$4 } from "./no-jsx-statement.js";
6
- import { _default as _default$5 } from "./no-ternary-return.js";
7
- import { _default as _default$6 } from "./unsafe-asserted-chain.js";
2
+ import { _default as _default$1 } from "./no-else-break.js";
3
+ import { _default as _default$2 } from "./no-else-continue.js";
4
+ import { _default as _default$3 } from "./no-else-throw.js";
5
+ import { _default as _default$4 } from "./no-empty-comment.js";
6
+ import { _default as _default$5 } from "./no-empty-jsx-expression.js";
7
+ import { _default as _default$6 } from "./no-extra-nested-boolean-cast.js";
8
+ import { _default as _default$7 } from "./no-invalid-date-literal.js";
9
+ import { _default as _default$8 } from "./no-jsx-statement.js";
10
+ import { _default as _default$9 } from "./no-suspicious-jsx-semicolon.js";
11
+ import { _default as _default$10 } from "./no-ternary-return.js";
12
+ import { _default as _default$11 } from "./no-useless-iife.js";
13
+ import { _default as _default$12 } from "./prefer-repeat.js";
14
+ import { _default as _default$13 } from "./unsafe-asserted-chain.js";
8
15
 
9
16
  //#region lib/rules/index.d.ts
10
17
  declare namespace index_d_exports {
11
- export { _default as "no-constant-template-expression", _default$1 as "no-empty-comment", _default$2 as "no-empty-jsx-expression", _default$3 as "no-extra-nested-boolean-cast", _default$4 as "no-jsx-statement", _default$5 as "no-ternary-return", _default$6 as "unsafe-asserted-chain" };
18
+ export { _default as "no-constant-template-expression", _default$1 as "no-else-break", _default$2 as "no-else-continue", _default$3 as "no-else-throw", _default$4 as "no-empty-comment", _default$5 as "no-empty-jsx-expression", _default$6 as "no-extra-nested-boolean-cast", _default$7 as "no-invalid-date-literal", _default$8 as "no-jsx-statement", _default$9 as "no-suspicious-jsx-semicolon", _default$10 as "no-ternary-return", _default$11 as "no-useless-iife", _default$12 as "prefer-repeat", _default$13 as "unsafe-asserted-chain" };
12
19
  }
13
20
  //#endregion
14
21
  export { index_d_exports };
@@ -1,20 +1,34 @@
1
1
  import { __export } from "../_virtual/rolldown_runtime.js";
2
2
  import no_constant_template_expression_default from "./no-constant-template-expression.js";
3
+ import no_else_break_default from "./no-else-break.js";
4
+ import no_else_continue_default from "./no-else-continue.js";
5
+ import no_else_throw_default from "./no-else-throw.js";
3
6
  import no_empty_comment_default from "./no-empty-comment.js";
4
7
  import no_empty_jsx_expression_default from "./no-empty-jsx-expression.js";
5
8
  import no_extra_nested_boolean_cast_default from "./no-extra-nested-boolean-cast.js";
9
+ import no_invalid_date_literal_default from "./no-invalid-date-literal.js";
6
10
  import no_jsx_statement_default from "./no-jsx-statement.js";
11
+ import no_suspicious_jsx_semicolon_default from "./no-suspicious-jsx-semicolon.js";
7
12
  import no_ternary_return_default from "./no-ternary-return.js";
13
+ import no_useless_iife_default from "./no-useless-iife.js";
14
+ import prefer_repeat_default from "./prefer-repeat.js";
8
15
  import unsafe_asserted_chain_default from "./unsafe-asserted-chain.js";
9
16
 
10
17
  //#region lib/rules/index.ts
11
18
  var rules_exports = /* @__PURE__ */ __export({
12
19
  "no-constant-template-expression": () => no_constant_template_expression_default,
20
+ "no-else-break": () => no_else_break_default,
21
+ "no-else-continue": () => no_else_continue_default,
22
+ "no-else-throw": () => no_else_throw_default,
13
23
  "no-empty-comment": () => no_empty_comment_default,
14
24
  "no-empty-jsx-expression": () => no_empty_jsx_expression_default,
15
25
  "no-extra-nested-boolean-cast": () => no_extra_nested_boolean_cast_default,
26
+ "no-invalid-date-literal": () => no_invalid_date_literal_default,
16
27
  "no-jsx-statement": () => no_jsx_statement_default,
28
+ "no-suspicious-jsx-semicolon": () => no_suspicious_jsx_semicolon_default,
17
29
  "no-ternary-return": () => no_ternary_return_default,
30
+ "no-useless-iife": () => no_useless_iife_default,
31
+ "prefer-repeat": () => prefer_repeat_default,
18
32
  "unsafe-asserted-chain": () => unsafe_asserted_chain_default
19
33
  });
20
34
 
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint0 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-else-break.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint0.RuleModule<"noElseBreak", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint0.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,51 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-else-break.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_else_break_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Forbid unnecessary `else` block after a `break` statement",
13
+ recommended: true
14
+ },
15
+ fixable: "code",
16
+ schema: [],
17
+ messages: { noElseBreak: "Remove this unnecessary else" }
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ return { IfStatement(node) {
22
+ const { alternate } = node;
23
+ if (!alternate) return;
24
+ const lastConsequentStatement = getLastStatement(node.consequent);
25
+ if (!lastConsequentStatement) return;
26
+ if (lastConsequentStatement.type === AST_NODE_TYPES.BreakStatement) context.report({
27
+ node: alternate,
28
+ messageId: "noElseBreak",
29
+ *fix(fixer) {
30
+ const firstToken = context.sourceCode.getTokenBefore(alternate);
31
+ if (firstToken) yield fixer.remove(firstToken);
32
+ yield fixer.remove(alternate);
33
+ if (alternate.type === AST_NODE_TYPES.BlockStatement) {
34
+ const bodyText$1 = alternate.body.map((stmt) => context.sourceCode.getText(stmt)).join("\n");
35
+ yield fixer.insertTextAfter(node, bodyText$1);
36
+ return;
37
+ }
38
+ const bodyText = context.sourceCode.getText(alternate);
39
+ yield fixer.insertTextAfter(node, bodyText);
40
+ }
41
+ });
42
+ } };
43
+ }
44
+ });
45
+ function getLastStatement(stmt) {
46
+ if (stmt.type === AST_NODE_TYPES.BlockStatement) return stmt.body.at(-1);
47
+ return stmt;
48
+ }
49
+
50
+ //#endregion
51
+ export { no_else_break_default as default };
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint1 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-else-continue.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint1.RuleModule<"noElseContinue", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint1.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,51 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-else-continue.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_else_continue_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Forbid unnecessary `else` block after a `continue` statement",
13
+ recommended: true
14
+ },
15
+ fixable: "code",
16
+ schema: [],
17
+ messages: { noElseContinue: "Remove this unnecessary else" }
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ return { IfStatement(node) {
22
+ const { alternate } = node;
23
+ if (!alternate) return;
24
+ const lastConsequentStatement = getLastStatement(node.consequent);
25
+ if (!lastConsequentStatement) return;
26
+ if (lastConsequentStatement.type === AST_NODE_TYPES.ContinueStatement) context.report({
27
+ node: alternate,
28
+ messageId: "noElseContinue",
29
+ *fix(fixer) {
30
+ const firstToken = context.sourceCode.getTokenBefore(alternate);
31
+ if (firstToken) yield fixer.remove(firstToken);
32
+ yield fixer.remove(alternate);
33
+ if (alternate.type === AST_NODE_TYPES.BlockStatement) {
34
+ const bodyText$1 = alternate.body.map((stmt) => context.sourceCode.getText(stmt)).join("\n");
35
+ yield fixer.insertTextAfter(node, bodyText$1);
36
+ return;
37
+ }
38
+ const bodyText = context.sourceCode.getText(alternate);
39
+ yield fixer.insertTextAfter(node, bodyText);
40
+ }
41
+ });
42
+ } };
43
+ }
44
+ });
45
+ function getLastStatement(stmt) {
46
+ if (stmt.type === AST_NODE_TYPES.BlockStatement) return stmt.body.at(-1);
47
+ return stmt;
48
+ }
49
+
50
+ //#endregion
51
+ export { no_else_continue_default as default };
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint3 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-else-throw.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint3.RuleModule<"noElseThrow", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint3.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,51 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-else-throw.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_else_throw_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Forbid unnecessary `else` block after a `throw` statement",
13
+ recommended: true
14
+ },
15
+ fixable: "code",
16
+ schema: [],
17
+ messages: { noElseThrow: "Remove this unnecessary else" }
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ return { IfStatement(node) {
22
+ const { alternate } = node;
23
+ if (!alternate) return;
24
+ const lastConsequentStatement = getLastStatement(node.consequent);
25
+ if (!lastConsequentStatement) return;
26
+ if (lastConsequentStatement.type === AST_NODE_TYPES.ThrowStatement) context.report({
27
+ node: alternate,
28
+ messageId: "noElseThrow",
29
+ *fix(fixer) {
30
+ const firstToken = context.sourceCode.getTokenBefore(alternate);
31
+ if (firstToken) yield fixer.remove(firstToken);
32
+ yield fixer.remove(alternate);
33
+ if (alternate.type === AST_NODE_TYPES.BlockStatement) {
34
+ const bodyText$1 = alternate.body.map((stmt) => context.sourceCode.getText(stmt)).join("\n");
35
+ yield fixer.insertTextAfter(node, bodyText$1);
36
+ return;
37
+ }
38
+ const bodyText = context.sourceCode.getText(alternate);
39
+ yield fixer.insertTextAfter(node, bodyText);
40
+ }
41
+ });
42
+ } };
43
+ }
44
+ });
45
+ function getLastStatement(stmt) {
46
+ if (stmt.type === AST_NODE_TYPES.BlockStatement) return stmt.body.at(-1);
47
+ return stmt;
48
+ }
49
+
50
+ //#endregion
51
+ export { no_else_throw_default as default };
@@ -1,9 +1,9 @@
1
1
  import { WyrmPluginDocs } from "../utils/createRule.js";
2
- import * as _typescript_eslint_utils_ts_eslint0 from "@typescript-eslint/utils/ts-eslint";
2
+ import * as _typescript_eslint_utils_ts_eslint5 from "@typescript-eslint/utils/ts-eslint";
3
3
 
4
4
  //#region lib/rules/no-empty-comment.d.ts
5
- declare const _default: _typescript_eslint_utils_ts_eslint0.RuleModule<"noEmptyComment", [{
5
+ declare const _default: _typescript_eslint_utils_ts_eslint5.RuleModule<"noEmptyComment", [{
6
6
  allowStacked: boolean;
7
- }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint0.RuleListener>;
7
+ }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint5.RuleListener>;
8
8
  //#endregion
9
9
  export { _default };
@@ -1,7 +1,7 @@
1
1
  import { WyrmPluginDocs } from "../utils/createRule.js";
2
- import * as _typescript_eslint_utils_ts_eslint1 from "@typescript-eslint/utils/ts-eslint";
2
+ import * as _typescript_eslint_utils_ts_eslint7 from "@typescript-eslint/utils/ts-eslint";
3
3
 
4
4
  //#region lib/rules/no-empty-jsx-expression.d.ts
5
- declare const _default: _typescript_eslint_utils_ts_eslint1.RuleModule<"noEmptyJsxExpression", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint1.RuleListener>;
5
+ declare const _default: _typescript_eslint_utils_ts_eslint7.RuleModule<"noEmptyJsxExpression", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint7.RuleListener>;
6
6
  //#endregion
7
7
  export { _default };
@@ -1,8 +1,8 @@
1
1
  import { WyrmPluginDocs } from "../utils/createRule.js";
2
- import * as _typescript_eslint_utils_ts_eslint3 from "@typescript-eslint/utils/ts-eslint";
2
+ import * as _typescript_eslint_utils_ts_eslint9 from "@typescript-eslint/utils/ts-eslint";
3
3
 
4
4
  //#region lib/rules/no-extra-nested-boolean-cast.d.ts
5
5
 
6
- declare const _default: _typescript_eslint_utils_ts_eslint3.RuleModule<"noExtraBooleanCastInCondition" | "noExtraBooleanCastInPredicate" | "noExtraBooleanCastInsideAnother", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint3.RuleListener>;
6
+ declare const _default: _typescript_eslint_utils_ts_eslint9.RuleModule<"noExtraBooleanCastInCondition" | "noExtraBooleanCastInPredicate" | "noExtraBooleanCastInsideAnother", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint9.RuleListener>;
7
7
  //#endregion
8
8
  export { _default };
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint11 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-invalid-date-literal.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint11.RuleModule<"noInvalidDateLiteral", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint11.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,68 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-invalid-date-literal.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_invalid_date_literal_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "problem",
11
+ docs: {
12
+ description: "Disallow invalid date literals",
13
+ recommended: true
14
+ },
15
+ schema: [],
16
+ messages: { noInvalidDateLiteral: "This results in an invalid date" }
17
+ },
18
+ defaultOptions: [],
19
+ create(context) {
20
+ return {
21
+ NewExpression(node) {
22
+ if (node.arguments.length > 1) return;
23
+ const [arg] = node.arguments;
24
+ if (!arg) return;
25
+ if (arg.type === AST_NODE_TYPES.Identifier) {
26
+ if (["NaN", "Infinity"].includes(arg.name)) context.report({
27
+ node,
28
+ messageId: "noInvalidDateLiteral"
29
+ });
30
+ return;
31
+ }
32
+ if (arg.type !== AST_NODE_TYPES.Literal) return;
33
+ if (typeof arg.value === "string" || typeof arg.value === "number") {
34
+ if (isValidDateLiteral(arg.value)) return;
35
+ context.report({
36
+ node,
37
+ messageId: "noInvalidDateLiteral"
38
+ });
39
+ }
40
+ },
41
+ CallExpression(node) {
42
+ const { callee } = node;
43
+ if (callee.type !== AST_NODE_TYPES.MemberExpression) return;
44
+ if (callee.object.type !== AST_NODE_TYPES.Identifier) return;
45
+ if (callee.property.type !== AST_NODE_TYPES.Identifier) return;
46
+ if (callee.object.name !== "Date") return;
47
+ if (callee.property.name !== "parse") return;
48
+ const [arg] = node.arguments;
49
+ if (!arg) return;
50
+ if (arg.type !== AST_NODE_TYPES.Literal) return;
51
+ if (typeof arg.value === "string") {
52
+ if (isValidDateLiteral(arg.value)) return;
53
+ context.report({
54
+ node,
55
+ messageId: "noInvalidDateLiteral"
56
+ });
57
+ }
58
+ }
59
+ };
60
+ }
61
+ });
62
+ function isValidDateLiteral(literal) {
63
+ const value = new Date(literal).valueOf();
64
+ return !Number.isNaN(value);
65
+ }
66
+
67
+ //#endregion
68
+ export { no_invalid_date_literal_default as default };
@@ -1,7 +1,7 @@
1
1
  import { WyrmPluginDocs } from "../utils/createRule.js";
2
- import * as _typescript_eslint_utils_ts_eslint5 from "@typescript-eslint/utils/ts-eslint";
2
+ import * as _typescript_eslint_utils_ts_eslint13 from "@typescript-eslint/utils/ts-eslint";
3
3
 
4
4
  //#region lib/rules/no-jsx-statement.d.ts
5
- declare const _default: _typescript_eslint_utils_ts_eslint5.RuleModule<"noJsxExpressionStatement", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint5.RuleListener>;
5
+ declare const _default: _typescript_eslint_utils_ts_eslint13.RuleModule<"noJsxExpressionStatement", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint13.RuleListener>;
6
6
  //#endregion
7
7
  export { _default };
@@ -0,0 +1,8 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint15 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-suspicious-jsx-semicolon.d.ts
5
+
6
+ declare const _default: _typescript_eslint_utils_ts_eslint15.RuleModule<"noSuspiciousJsxSemicolon" | "noSuspiciousJsxComma", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint15.RuleListener>;
7
+ //#endregion
8
+ export { _default };
@@ -0,0 +1,39 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+
4
+ //#region lib/rules/no-suspicious-jsx-semicolon.ts
5
+ const { name } = path.parse(import.meta.filename);
6
+ var no_suspicious_jsx_semicolon_default = createRule({
7
+ name,
8
+ meta: {
9
+ type: "problem",
10
+ docs: {
11
+ description: "Forbid suspicious semicolons in JSX",
12
+ recommended: true
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ noSuspiciousJsxSemicolon: "This semicolon looks suspiciously out of place. Did you add it on purpose?",
17
+ noSuspiciousJsxComma: "This comma looks suspiciously out of place. Did you add it on purpose?"
18
+ }
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ return { JSXText(node) {
23
+ if (node.value.trim() === ";") {
24
+ context.report({
25
+ node,
26
+ messageId: "noSuspiciousJsxSemicolon"
27
+ });
28
+ return;
29
+ }
30
+ if (node.value.trimEnd() === ",") context.report({
31
+ node,
32
+ messageId: "noSuspiciousJsxComma"
33
+ });
34
+ } };
35
+ }
36
+ });
37
+
38
+ //#endregion
39
+ export { no_suspicious_jsx_semicolon_default as default };
@@ -1,9 +1,9 @@
1
1
  import { WyrmPluginDocs } from "../utils/createRule.js";
2
- import * as _typescript_eslint_utils_ts_eslint7 from "@typescript-eslint/utils/ts-eslint";
2
+ import * as _typescript_eslint_utils_ts_eslint17 from "@typescript-eslint/utils/ts-eslint";
3
3
 
4
4
  //#region lib/rules/no-ternary-return.d.ts
5
- declare const _default: _typescript_eslint_utils_ts_eslint7.RuleModule<"noTernaryReturn", [{
5
+ declare const _default: _typescript_eslint_utils_ts_eslint17.RuleModule<"noTernaryReturn", [{
6
6
  allowSingleLine: boolean;
7
- }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint7.RuleListener>;
7
+ }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint17.RuleListener>;
8
8
  //#endregion
9
9
  export { _default };
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint19 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-useless-iife.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint19.RuleModule<"noUselessIIFE" | "removeIIFE", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint19.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,93 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-useless-iife.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_useless_iife_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Forbid useless IIFEs",
13
+ recommended: true
14
+ },
15
+ hasSuggestions: true,
16
+ schema: [],
17
+ messages: {
18
+ noUselessIIFE: "An IIFE is unnecessary here",
19
+ removeIIFE: "Remove this IIFE"
20
+ }
21
+ },
22
+ defaultOptions: [],
23
+ create(context) {
24
+ return { CallExpression(node) {
25
+ const { callee } = node;
26
+ if (callee.type !== AST_NODE_TYPES.FunctionExpression && callee.type !== AST_NODE_TYPES.ArrowFunctionExpression) return;
27
+ if (callee.body.type !== AST_NODE_TYPES.BlockStatement) {
28
+ context.report({
29
+ node,
30
+ messageId: "noUselessIIFE",
31
+ suggest: [{
32
+ messageId: "removeIIFE",
33
+ fix(fixer) {
34
+ return fixer.replaceText(node, context.sourceCode.getText(callee.body));
35
+ }
36
+ }]
37
+ });
38
+ return;
39
+ }
40
+ const { body } = callee.body;
41
+ const [lastStatement] = body;
42
+ if (!lastStatement) return;
43
+ if (body.length === 1 && lastStatement.type === AST_NODE_TYPES.ReturnStatement) {
44
+ context.report({
45
+ node,
46
+ messageId: "noUselessIIFE",
47
+ suggest: [{
48
+ messageId: "removeIIFE",
49
+ fix(fixer) {
50
+ const txt = lastStatement.argument ? context.sourceCode.getText(lastStatement.argument) : "undefined";
51
+ return fixer.replaceText(node, txt);
52
+ }
53
+ }]
54
+ });
55
+ return;
56
+ }
57
+ if (node.parent.type !== AST_NODE_TYPES.ExpressionStatement) return;
58
+ if (!body.some((stmt) => stmt.type === AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === AST_NODE_TYPES.AwaitExpression)) {
59
+ context.report({
60
+ node,
61
+ messageId: "noUselessIIFE",
62
+ suggest: [{
63
+ messageId: "removeIIFE",
64
+ fix(fixer) {
65
+ const txt = context.sourceCode.getText(callee.body);
66
+ return fixer.replaceText(node, txt);
67
+ }
68
+ }]
69
+ });
70
+ return;
71
+ }
72
+ if (isStatementInAsyncFunction(node.parent)) context.report({
73
+ node,
74
+ messageId: "noUselessIIFE",
75
+ suggest: [{
76
+ messageId: "removeIIFE",
77
+ fix(fixer) {
78
+ const txt = context.sourceCode.getText(callee.body);
79
+ return fixer.replaceText(node, txt);
80
+ }
81
+ }]
82
+ });
83
+ } };
84
+ }
85
+ });
86
+ function isStatementInAsyncFunction(stmt) {
87
+ if (stmt.parent.type !== AST_NODE_TYPES.BlockStatement) return false;
88
+ if (stmt.parent.parent.type === AST_NODE_TYPES.FunctionDeclaration || stmt.parent.parent.type === AST_NODE_TYPES.ArrowFunctionExpression || stmt.parent.parent.type === AST_NODE_TYPES.FunctionExpression) return stmt.parent.parent.async;
89
+ return false;
90
+ }
91
+
92
+ //#endregion
93
+ export { no_useless_iife_default as default };
@@ -0,0 +1,7 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint21 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/prefer-repeat.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint21.RuleModule<"preferRepeat" | "replaceByRepeat", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint21.RuleListener>;
6
+ //#endregion
7
+ export { _default };
@@ -0,0 +1,108 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import { None, Option, Some } from "../utils/option.js";
3
+ import path from "node:path";
4
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
5
+
6
+ //#region lib/rules/prefer-repeat.ts
7
+ const { name } = path.parse(import.meta.filename);
8
+ var prefer_repeat_default = createRule({
9
+ name,
10
+ meta: {
11
+ type: "suggestion",
12
+ docs: {
13
+ description: "Enforce usage of `String.prototype.repeat`",
14
+ recommended: true
15
+ },
16
+ hasSuggestions: true,
17
+ schema: [],
18
+ messages: {
19
+ preferRepeat: "This could be simplified as `{{fixed}}`",
20
+ replaceByRepeat: "Replace by `{{fixed}}`"
21
+ }
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ return { CallExpression(node) {
26
+ if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return;
27
+ if (node.callee.property.type !== AST_NODE_TYPES.Identifier) return;
28
+ if (!["reduce", "reduceRight"].includes(node.callee.property.name)) return;
29
+ const length = getConstructedArrayLength(node.callee.object);
30
+ if (!length.some) return;
31
+ const [arg] = node.arguments;
32
+ if (!arg) return;
33
+ const repeatedString = getRepeatedString(arg);
34
+ if (!repeatedString.some) return;
35
+ const n = context.sourceCode.getText(length.value);
36
+ const fixed = `${typeof repeatedString.value === "string" ? `'${repeatedString.value}'` : context.sourceCode.getText(repeatedString.value)}.repeat(${n})`;
37
+ context.report({
38
+ node,
39
+ messageId: "preferRepeat",
40
+ data: { fixed },
41
+ suggest: [{
42
+ messageId: "replaceByRepeat",
43
+ data: { fixed },
44
+ fix(fixer) {
45
+ return fixer.replaceText(node, fixed);
46
+ }
47
+ }]
48
+ });
49
+ } };
50
+ }
51
+ });
52
+ function getConstructedArrayLength(expr) {
53
+ if (expr.type !== AST_NODE_TYPES.CallExpression) return None;
54
+ const { callee } = expr;
55
+ if (callee.type !== AST_NODE_TYPES.MemberExpression) return None;
56
+ if (callee.property.type !== AST_NODE_TYPES.Identifier) return None;
57
+ if (callee.property.name === "from") {
58
+ if (callee.object.type !== AST_NODE_TYPES.Identifier) return None;
59
+ if (callee.object.name !== "Array") return None;
60
+ if (expr.arguments[0]?.type !== AST_NODE_TYPES.ObjectExpression) return None;
61
+ const { properties } = expr.arguments[0];
62
+ const length = properties.filter((prop) => prop.type === AST_NODE_TYPES.Property).find((prop) => prop.key.type === AST_NODE_TYPES.Identifier && prop.key.name === "length");
63
+ if (!length) return None;
64
+ return Some(length.value);
65
+ }
66
+ if (callee.property.name !== "fill") return None;
67
+ if (callee.object.type === AST_NODE_TYPES.CallExpression || callee.object.type === AST_NODE_TYPES.NewExpression) return Option.fromUndef(callee.object.arguments[0]);
68
+ return None;
69
+ }
70
+ function getRepeatedString(callback) {
71
+ if (callback.type !== AST_NODE_TYPES.FunctionExpression && callback.type !== AST_NODE_TYPES.ArrowFunctionExpression) return None;
72
+ const [acc] = callback.params;
73
+ if (!acc) return None;
74
+ if (acc.type !== AST_NODE_TYPES.Identifier) return None;
75
+ if (callback.body.type !== AST_NODE_TYPES.BlockStatement) return extractRepeatedString(callback.body, acc);
76
+ const returnStatement = callback.body.body.at(-1);
77
+ if (returnStatement?.type !== AST_NODE_TYPES.ReturnStatement) return None;
78
+ if (!returnStatement.argument) return None;
79
+ return extractRepeatedString(returnStatement.argument, acc);
80
+ }
81
+ function extractRepeatedString(expr, acc) {
82
+ if (expr.type === AST_NODE_TYPES.TemplateLiteral) return extractRepeatedStringFromTemplateLiteral(expr, acc);
83
+ if (expr.type === AST_NODE_TYPES.CallExpression) return extractRepeatedStringFromCallExpression(expr, acc);
84
+ return None;
85
+ }
86
+ function extractRepeatedStringFromTemplateLiteral(expr, acc) {
87
+ if (expr.expressions.length === 2) {
88
+ const str = expr.expressions.find((expression) => expression.type !== AST_NODE_TYPES.Identifier || expression.name !== acc.name);
89
+ return Option.fromUndef(str);
90
+ }
91
+ if (expr.expressions.length !== 1) return None;
92
+ if (expr.expressions[0]?.type !== AST_NODE_TYPES.Identifier) return None;
93
+ if (expr.expressions[0].name !== acc.name) return None;
94
+ if (expr.quasis.length !== 2) return None;
95
+ const quasi = expr.quasis.map((q) => q.value.cooked).find(Boolean);
96
+ return Option.fromUndef(quasi);
97
+ }
98
+ function extractRepeatedStringFromCallExpression(expr, acc) {
99
+ if (expr.callee.type !== AST_NODE_TYPES.MemberExpression) return None;
100
+ if (expr.callee.property.type !== AST_NODE_TYPES.Identifier) return None;
101
+ if (expr.callee.property.name !== "concat") return None;
102
+ if (expr.callee.object.type !== AST_NODE_TYPES.Identifier) return None;
103
+ if (expr.callee.object.name !== acc.name) return None;
104
+ return Option.fromUndef(expr.arguments[0]);
105
+ }
106
+
107
+ //#endregion
108
+ export { prefer_repeat_default as default };
@@ -0,0 +1,18 @@
1
+ //#region lib/utils/option.ts
2
+ const Option = { fromUndef: (value) => {
3
+ if (value === void 0) return None;
4
+ return Some(value);
5
+ } };
6
+ const None = {
7
+ value: null,
8
+ some: false
9
+ };
10
+ function Some(value) {
11
+ return {
12
+ value,
13
+ some: true
14
+ };
15
+ }
16
+
17
+ //#endregion
18
+ export { None, Option, Some };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-wyrm",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Some custom ESLint rules",
5
5
  "keywords": [
6
6
  "eslint",
@@ -1,83 +0,0 @@
1
- # Disallow constant string expressions in template literals (`wyrm/no-constant-template-expression`)
2
-
3
- 💼 This rule is enabled in the ☑️ `strictTypeChecked` config.
4
-
5
- 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
6
-
7
- 💭 This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
8
-
9
- ## Description
10
-
11
- It is sometimes clearer to inline interpolated expressions when their values are constant:
12
-
13
- ### Example
14
-
15
- ```ts
16
- const foo = 'foobar';
17
- const str = `${foo}_baz`;
18
- // This would be clearer as:
19
- const str = 'foobar_baz';
20
- ```
21
-
22
- By default, this rule allows constant values when they take up at least 10 characters.
23
- This can be configured with the `minAllowedLength` option.
24
-
25
- ## Cases
26
-
27
- ### Incorrect ❌
28
-
29
- Template expression with a constant string value:
30
-
31
- ```tsx
32
- const foo = 'foobar';
33
- const str = `${foo}_baz`;
34
- ```
35
-
36
- Template expression with a constant number value:
37
-
38
- ```tsx
39
- const n = 42;
40
- const str = `${n}_baz`;
41
- ```
42
-
43
- Template expression with a constant boolean value:
44
-
45
- ```tsx
46
- const bool = true;
47
- const str = `${bool}_baz`;
48
- ```
49
-
50
- With a 14 character string (`minAllowedLength: 15`):
51
-
52
- ```tsx
53
- const foo = '12345678901234';
54
- const str = `${foo}_baz`;
55
- ```
56
-
57
- ### Correct ✅
58
-
59
- Template expression typed as string:
60
-
61
- ```tsx
62
- declare const foo: string;
63
- const str = `${foo}_baz`;
64
- ```
65
-
66
- Template expression with a 10 character string value (as long as the default `minAllowedLength` value):
67
-
68
- ```tsx
69
- const n = 'aaaaaaaaaa';
70
- const str = `${n}_baz`;
71
- ```
72
-
73
- <!-- end auto-generated rule header -->
74
-
75
- ## Options
76
-
77
- <!-- begin auto-generated rule options list -->
78
-
79
- | Name | Description | Type |
80
- | :----------------- | :------------------------------------------------------------------ | :----- |
81
- | `minAllowedLength` | Minimum string length allowed for constant expressions. Default: 10 | Number |
82
-
83
- <!-- end auto-generated rule options list -->
@@ -1,70 +0,0 @@
1
- # Forbid empty comments (`wyrm/no-empty-comment`)
2
-
3
- 💼 This rule is enabled in the following configs: 🟪 `strict`, ☑️ `strictTypeChecked`.
4
-
5
- ## Cases
6
-
7
- ### Incorrect ❌
8
-
9
- Empty inline comment:
10
-
11
- ```tsx
12
- //
13
- ```
14
-
15
- Empty block comment:
16
-
17
- ```tsx
18
- /* */
19
- ```
20
-
21
- Empty JSDoc comment:
22
-
23
- ```tsx
24
- /** */
25
- ```
26
-
27
- Stacked empty comments (with `allowStacked: false`):
28
-
29
- ```tsx
30
- //
31
- // Ok
32
- //
33
- ```
34
-
35
- Several stacked empty comments (with `allowStacked: true`):
36
-
37
- ```tsx
38
- //
39
- // Ok
40
- //
41
- //
42
- ```
43
-
44
- ### Correct ✅
45
-
46
- Not an empty comment:
47
-
48
- ```tsx
49
- // Ok
50
- ```
51
-
52
- Stacked empty comments (with `allowStacked: true`):
53
-
54
- ```tsx
55
- //
56
- // Ok
57
- //
58
- ```
59
-
60
- <!-- end auto-generated rule header -->
61
-
62
- ## Options
63
-
64
- <!-- begin auto-generated rule options list -->
65
-
66
- | Name | Description | Type |
67
- | :------------- | :----------------------------------------------------------------------------------- | :------ |
68
- | `allowStacked` | Whether to allow empty comments stacked next to non-empty comments. Default: `false` | Boolean |
69
-
70
- <!-- end auto-generated rule options list -->
@@ -1,77 +0,0 @@
1
- # Forbid empty JSX expression containers (`wyrm/no-empty-jsx-expression`)
2
-
3
- 💼 This rule is enabled in the following configs: 🟩 `recommended`, ✅ `recommendedTypeChecked`, 🟪 `strict`, ☑️ `strictTypeChecked`.
4
-
5
- ## Cases
6
-
7
- ### Incorrect ❌
8
-
9
- Empty JSX expression container:
10
-
11
- ```tsx
12
- function Foo() {
13
- return (
14
- <div>
15
- {}
16
- Ok
17
- </div>
18
- );
19
- }
20
- ```
21
-
22
- JSX expression container with only a literal `null`:
23
-
24
- ```tsx
25
- function Foo() {
26
- return <div>{null}</div>;
27
- }
28
- ```
29
-
30
- JSX expression container with only a literal `undefined`:
31
-
32
- ```tsx
33
- function Foo() {
34
- return <div>{undefined}</div>;
35
- }
36
- ```
37
-
38
- JSX expression container with only a literal `false`:
39
-
40
- ```tsx
41
- function Foo() {
42
- return <div>{false}</div>;
43
- }
44
- ```
45
-
46
- JSX expression container with only a literal empty string:
47
-
48
- ```tsx
49
- function Foo() {
50
- return <div>{''}</div>;
51
- }
52
- ```
53
-
54
- ### Correct ✅
55
-
56
- JSX expression container is not empty:
57
-
58
- ```tsx
59
- function Foo({ children }: PropsWithChildren) {
60
- return <div>{children}</div>;
61
- }
62
- ```
63
-
64
- JSX expression container with a comment:
65
-
66
- ```tsx
67
- function Foo() {
68
- return (
69
- <div>
70
- {/* A comment */}
71
- Ok
72
- </div>
73
- );
74
- }
75
- ```
76
-
77
- <!-- end auto-generated rule header -->
@@ -1,112 +0,0 @@
1
- # Forbid extra boolean casts in conditions and predicates (`wyrm/no-extra-nested-boolean-cast`)
2
-
3
- 💼 This rule is enabled in the following configs: 🟪 `strict`, ☑️ `strictTypeChecked`.
4
-
5
- ## Description
6
-
7
- When an expression is inside a conditional test, it is implicitly coerced to a boolean.
8
- Casting this expression to a boolean is therefore redundant.
9
-
10
- This rule supplements the builtin [`no-extra-boolean-cast`](https://eslint.org/docs/latest/rules/no-extra-boolean-cast) ESLint rule.
11
- The `wyrm/no-extra-nested-boolean-cast` should have the same behavior as the builtin rule with the `enforceForInnerExpressions` option enabled, but it also supports some TypeScript constructs.
12
-
13
- Contrary to the builtin rule, it also enforces this for callback returns of some array methods like `Array.prototype.find` or `Array.prototype.filter`.
14
-
15
- ### Example
16
-
17
- ```ts
18
- declare const foo: string;
19
- // `foo` doesn't need to be coerced to a boolean, because it is inside a ternary condition:
20
- const bar = !!foo ? 'ok' : 'ko';
21
- ```
22
-
23
- This rules conflicts with the [`@typescript-eslint/strict-boolean-expressions`](https://typescript-eslint.io/rules/strict-boolean-expressions/) rule.
24
-
25
- ## Cases
26
-
27
- ### Incorrect ❌
28
-
29
- Redundant double negation:
30
-
31
- ```tsx
32
- declare const foo: string;
33
-
34
- if (!!bar) {
35
- console.log('foo!');
36
- }
37
- ```
38
-
39
- Redundant double negation inside of another boolean cast:
40
-
41
- ```tsx
42
- const x = Boolean(!!foo);
43
- ```
44
-
45
- Redundant double negation in return of array method predicate:
46
-
47
- ```tsx
48
- declare const arr: string[];
49
- const isOkay = arr.filter((elt) => !!elt);
50
- ```
51
-
52
- Redundant double negations in logical sub-expressions:
53
-
54
- ```tsx
55
- declare const foo: string;
56
- declare const bar: string;
57
- declare const baz: string;
58
-
59
- if (!!bar && (!!foo || !!baz)) {
60
- console.log('foo!');
61
- }
62
- ```
63
-
64
- Redundant Boolean calls:
65
-
66
- ```tsx
67
- declare const foo: string;
68
- declare const bar: string;
69
- declare const baz: string;
70
-
71
- if (Boolean(bar) && (Boolean(foo) || Boolean(baz))) {
72
- console.log('foo!');
73
- }
74
- ```
75
-
76
- Redundant double negations nested in type assertions:
77
-
78
- ```tsx
79
- declare const foo: string;
80
- declare const bar: string;
81
- declare const baz: string;
82
-
83
- if ((!!bar)! && ((!!foo satisfies boolean) || (!!baz as any))) {
84
- console.log('foo!');
85
- }
86
- ```
87
-
88
- ### Correct ✅
89
-
90
- No extra boolean cast:
91
-
92
- ```tsx
93
- declare const foo: string;
94
- declare const bar: string;
95
- declare const baz: string;
96
-
97
- if (bar && (foo || baz)) {
98
- console.log('foo!');
99
- }
100
- ```
101
-
102
- Short-circuiting expression:
103
-
104
- ```tsx
105
- declare const foo: string;
106
- declare const bar: string;
107
- declare const baz: string;
108
-
109
- const val = !!bar && (!!foo || !!baz);
110
- ```
111
-
112
- <!-- end auto-generated rule header -->
@@ -1,36 +0,0 @@
1
- # Forbid JSX expression statements (`wyrm/no-jsx-statement`)
2
-
3
- 💼 This rule is enabled in the following configs: 🟩 `recommended`, ✅ `recommendedTypeChecked`, 🟪 `strict`, ☑️ `strictTypeChecked`.
4
-
5
- ## Cases
6
-
7
- ### Incorrect ❌
8
-
9
- JSX fragment in expression statement:
10
-
11
- ```tsx
12
- export function MyComponent() {
13
- <></>;
14
- }
15
- ```
16
-
17
- ### Correct ✅
18
-
19
- JSX element in return statement:
20
-
21
- ```tsx
22
- export function MyComponent() {
23
- return <div />;
24
- }
25
- ```
26
-
27
- JSX element in variable initialization:
28
-
29
- ```tsx
30
- export function MyComponent() {
31
- const jsx = <div />;
32
- return jsx;
33
- }
34
- ```
35
-
36
- <!-- end auto-generated rule header -->
@@ -1,46 +0,0 @@
1
- # Disallow ternary conditions in return statements (`wyrm/no-ternary-return`)
2
-
3
- 💼 This rule is enabled in the following configs: 🟪 `strict`, ☑️ `strictTypeChecked`.
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
- ## Cases
8
-
9
- ### Incorrect ❌
10
-
11
- Ternary return:
12
-
13
- ```tsx
14
- function foo(cond: boolean) {
15
- return cond ? 42 : 105;
16
- }
17
- ```
18
-
19
- ### Correct ✅
20
-
21
- No ternary return:
22
-
23
- ```tsx
24
- function foo(cond: boolean) {
25
- if (cond) return 42;
26
- return 105;
27
- }
28
- ```
29
-
30
- Inline arrow function:
31
-
32
- ```tsx
33
- const foo = (cond: boolean) => (cond ? 42 : 105);
34
- ```
35
-
36
- <!-- end auto-generated rule header -->
37
-
38
- ## Options
39
-
40
- <!-- begin auto-generated rule options list -->
41
-
42
- | Name | Description | Type |
43
- | :---------------- | :---------------------------------------------------------------- | :------ |
44
- | `allowSingleLine` | Whether to allow single line ternary conditions. Default: `false` | Boolean |
45
-
46
- <!-- end auto-generated rule options list -->
@@ -1,68 +0,0 @@
1
- # Disallow unsafe type assertions on optional chained expressions (`wyrm/unsafe-asserted-chain`)
2
-
3
- 💼 This rule is enabled in the ☑️ `strictTypeChecked` config.
4
-
5
- 💭 This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
6
-
7
- ## Description
8
-
9
- This rule supplements the [`@typescript-eslint/no-non-null-asserted-optional-chain`](https://typescript-eslint.io/rules/no-non-null-asserted-optional-chain/) ESLint rule.
10
-
11
- It checks for type assertions on optional chain expressions (`?.`) where the asserted type doesn't include `undefined`.
12
-
13
- Optional chaining can return `undefined` by default, so this is likely a mistake.
14
-
15
- This rule only makes sense if you have `strictNullChecks` enabled in your `tsconfig.json` (this is the default for `strict: true`).
16
-
17
- ### Example
18
-
19
- ```ts
20
- foo?.bar as string;
21
- // This should be:
22
- foo?.bar as string | undefined;
23
- // Or, if the optional chaining isn't actually necessary:
24
- foo.bar as string;
25
- ```
26
-
27
- ## Cases
28
-
29
- ### Incorrect ❌
30
-
31
- Optional chain asserted as not undefined:
32
-
33
- ```tsx
34
- declare const foo: { bar: string | number } | null;
35
- const str = (foo?.bar as string).toUpperCase();
36
- ```
37
-
38
- Optional chain call expression asserted as not undefined:
39
-
40
- ```tsx
41
- declare const foo: { bar: () => string | number } | null;
42
- const str = (foo?.bar() as string | number)?.toString();
43
- ```
44
-
45
- ### Correct ✅
46
-
47
- Optional chain asserted as nullable:
48
-
49
- ```tsx
50
- declare const foo: { bar: string | number } | null;
51
- const str = (foo?.bar as string | undefined)?.toUpperCase();
52
- ```
53
-
54
- Optional chain asserted as any:
55
-
56
- ```tsx
57
- declare const foo: { bar: string | number } | null;
58
- const str = (foo?.bar as any)?.toUpperCase();
59
- ```
60
-
61
- Optional chain asserted as unknown:
62
-
63
- ```tsx
64
- declare const foo: { bar: string | number } | null;
65
- const str = (foo?.bar as unknown)?.toUpperCase();
66
- ```
67
-
68
- <!-- end auto-generated rule header -->