eslint-plugin-wyrm 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,27 +1,14 @@
1
1
  # Changelog
2
2
 
3
- ## [0.0.4](https://github.com/mchevestrier/eslint-plugin-wyrm/compare/eslint-plugin-wyrm-v0.0.3...eslint-plugin-wyrm-v0.0.4) (2025-11-01)
4
-
5
-
6
- ### Bug Fixes
7
-
8
- * improve no-extra-nested-boolean-cast ([333d0f3](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/333d0f3bcc3aa73a329bb9ff60189490f96813cd))
9
-
10
- ## [0.0.3](https://github.com/mchevestrier/eslint-plugin-wyrm/compare/eslint-plugin-wyrm-v0.0.2...eslint-plugin-wyrm-v0.0.3) (2025-10-26)
3
+ ## [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)
11
4
 
12
5
 
13
6
  ### Bug Fixes
14
7
 
15
- * ignore CHANGELOG.md formatting ([f6a923c](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/f6a923c348be8c2976635ae64a45c75932faba60))
16
-
17
- ## 0.0.2 (2025-10-26)
8
+ * add no-ternary-return ([4e029be](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/4e029be3f157601bbbb5b9cb854a526ad88b2c1e))
18
9
 
10
+ ## [0.0.4](https://github.com/mchevestrier/eslint-plugin-wyrm/compare/eslint-plugin-wyrm-v0.0.3...eslint-plugin-wyrm-v0.0.4) (2025-11-01)
19
11
 
20
12
  ### Bug Fixes
21
13
 
22
- * rule doc url ([1ae7be1](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/1ae7be12ffa2811f22909b36b415061ddf890a2b))
23
-
24
-
25
- ### Miscellaneous Chores
26
-
27
- * Merge npm-publish.yml with release.yml ([fba85e8](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/fba85e8ff67e5274aedb63db60756a5a41ab010f))
14
+ - improve no-extra-nested-boolean-cast ([333d0f3](https://github.com/mchevestrier/eslint-plugin-wyrm/commit/333d0f3bcc3aa73a329bb9ff60189490f96813cd))
package/README.md CHANGED
@@ -4,16 +4,35 @@
4
4
  [![GitHub release](https://img.shields.io/github/v/release/mchevestrier/eslint-plugin-wyrm?color=7f52af&labelColor=26272b)](https://github.com/mchevestrier/eslint-plugin-wyrm/releases/latest)
5
5
  [![GitHub License](https://img.shields.io/badge/license-MIT-232428.svg?color=7f52af&labelColor=26272b)](https://github.com/mchevestrier/eslint-plugin-wyrm/blob/main/LICENSE.md)
6
6
 
7
+ ## Installation
8
+
9
+ ```shell
10
+ npm install --save-dev eslint eslint-plugin-wyrm
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import { defineConfig } from 'eslint/config';
17
+ import wyrm from 'eslint-plugin-wyrm';
18
+
19
+ export default defineConfig([
20
+ // ...
21
+
22
+ wyrm.configs.recommended,
23
+ ]);
24
+ ```
25
+
7
26
  ## Configs
8
27
 
9
28
  <!-- begin auto-generated configs list -->
10
29
 
11
- | | Name |
12
- | :-- | :---------------------------- |
13
- | | `wyrm/recommended` |
14
- | ☑️ | `wyrm/recommendedTypeChecked` |
15
- | 🟢 | `wyrm/strict` |
16
- | 🟣 | `wyrm/strictTypeChecked` |
30
+ | | Name |
31
+ | :-- | :----------------------- |
32
+ | 🟩 | `recommended` |
33
+ | | `recommendedTypeChecked` |
34
+ | 🟪 | `strict` |
35
+ | ☑️ | `strictTypeChecked` |
17
36
 
18
37
  <!-- end auto-generated configs list -->
19
38
 
@@ -22,16 +41,22 @@
22
41
  <!-- begin auto-generated rules list -->
23
42
 
24
43
  💼 Configurations enabled in.\
25
- Set in the `wyrm/recommended` configuration.\
26
- ☑️ Set in the `wyrm/recommendedTypeChecked` configuration.\
27
- 🟢 Set in the `wyrm/strict` configuration.\
28
- 🟣 Set in the `wyrm/strictTypeChecked` configuration.\
44
+ 🟩 Set in the `recommended` configuration.\
45
+ Set in the `recommendedTypeChecked` configuration.\
46
+ 🟪 Set in the `strict` configuration.\
47
+ ☑️ Set in the `strictTypeChecked` configuration.\
48
+ 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
49
+ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).\
29
50
  💭 Requires [type information](https://typescript-eslint.io/linting/typed-linting).
30
51
 
31
- | Name                         | Description | 💼 | 💭 |
32
- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | :---------- | :-- |
33
- | [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 | 🟢 🟣 | |
34
- | [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 | ☑️ 🟢 🟣 | |
35
- | [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 | 🟣 | 💭 |
52
+ | Name                            | Description | 💼 | 🔧 | 💡 | 💭 |
53
+ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | :---------- | :-- | :-- | :-- |
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-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
+ | [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
+ | [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 | 🟪 ☑️ | | | |
58
+ | [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 | 🟩 ✅ 🟪 ☑️ | | | |
59
+ | [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 | 🟪 ☑️ | 🔧 | | |
60
+ | [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 | ☑️ | | | 💭 |
36
61
 
37
62
  <!-- end auto-generated rules list -->
@@ -1,10 +1,10 @@
1
- import { Linter } from "eslint";
1
+ import { FlatConfig } from "@typescript-eslint/utils/ts-eslint";
2
2
 
3
3
  //#region lib/configs/index.d.ts
4
4
  declare namespace index_d_exports {
5
5
  export { all, recommended, recommendedTypeChecked, recommendedTypeCheckedOnly, strict, strictOnly, strictTypeChecked, strictTypeCheckedOnly };
6
6
  }
7
- type Config = Linter.Config;
7
+ type Config = FlatConfig.Config;
8
8
  declare const all: Config;
9
9
  declare const recommended: Config;
10
10
  declare const strictOnly: Config;
@@ -1,7 +1,6 @@
1
1
  import { __export } from "../_virtual/rolldown_runtime.js";
2
2
  import { rules_exports } from "../rules/index.js";
3
3
  import { plugin } from "../plugin.js";
4
- import { Linter } from "eslint";
5
4
 
6
5
  //#region lib/configs/index.ts
7
6
  var configs_exports = /* @__PURE__ */ __export({
@@ -17,12 +16,12 @@ var configs_exports = /* @__PURE__ */ __export({
17
16
  const baseConfig = { plugins: { get wyrm() {
18
17
  return plugin;
19
18
  } } };
20
- function createConfigWithRules(initialRules, name, pred) {
21
- const filteredRules = Object.entries(initialRules).filter(([, rule]) => pred(rule)).map(([name$1]) => [`wyrm/${name$1}`, "error"]);
19
+ function createConfigWithRules(initialRules, configName, pred) {
20
+ const filteredRules = Object.entries(initialRules).filter(([, rule]) => pred(rule)).map(([ruleName]) => [`wyrm/${ruleName}`, "error"]);
22
21
  const rules = Object.fromEntries(filteredRules);
23
22
  return {
24
23
  ...baseConfig,
25
- name: `wyrm/${name}`,
24
+ name: `wyrm/${configName}`,
26
25
  rules
27
26
  };
28
27
  }
package/dist/index.d.ts CHANGED
@@ -2,9 +2,13 @@ import { index_d_exports } from "./configs/index.js";
2
2
  import { index_d_exports as index_d_exports$1 } from "./rules/index.js";
3
3
 
4
4
  //#region lib/index.d.ts
5
+ interface CompatibleConfig {
6
+ name?: string;
7
+ rules?: object;
8
+ }
5
9
  declare const plugin: {
6
10
  rules: typeof index_d_exports$1;
7
- configs: typeof index_d_exports;
11
+ configs: Record<keyof typeof index_d_exports, CompatibleConfig>;
8
12
  };
9
13
  //#endregion
10
14
  export { plugin as default };
package/dist/plugin.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { rules_exports } from "./rules/index.js";
2
- import { configs_exports } from "./configs/index.js";
3
2
  import { createRequire } from "node:module";
4
3
 
5
4
  //#region lib/plugin.ts
@@ -9,7 +8,6 @@ const plugin = {
9
8
  name,
10
9
  version
11
10
  },
12
- configs: configs_exports,
13
11
  rules: rules_exports
14
12
  };
15
13
 
@@ -1,10 +1,14 @@
1
- import { _default } from "./no-extra-nested-boolean-cast.js";
2
- import { _default as _default$1 } from "./no-jsx-statement.js";
3
- import { _default as _default$2 } from "./unsafe-asserted-chain.js";
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";
4
8
 
5
9
  //#region lib/rules/index.d.ts
6
10
  declare namespace index_d_exports {
7
- export { _default as "no-extra-nested-boolean-cast", _default$1 as "no-jsx-statement", _default$2 as "unsafe-asserted-chain" };
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" };
8
12
  }
9
13
  //#endregion
10
14
  export { index_d_exports };
@@ -1,12 +1,20 @@
1
1
  import { __export } from "../_virtual/rolldown_runtime.js";
2
+ import no_constant_template_expression_default from "./no-constant-template-expression.js";
3
+ import no_empty_comment_default from "./no-empty-comment.js";
4
+ import no_empty_jsx_expression_default from "./no-empty-jsx-expression.js";
2
5
  import no_extra_nested_boolean_cast_default from "./no-extra-nested-boolean-cast.js";
3
6
  import no_jsx_statement_default from "./no-jsx-statement.js";
7
+ import no_ternary_return_default from "./no-ternary-return.js";
4
8
  import unsafe_asserted_chain_default from "./unsafe-asserted-chain.js";
5
9
 
6
10
  //#region lib/rules/index.ts
7
11
  var rules_exports = /* @__PURE__ */ __export({
12
+ "no-constant-template-expression": () => no_constant_template_expression_default,
13
+ "no-empty-comment": () => no_empty_comment_default,
14
+ "no-empty-jsx-expression": () => no_empty_jsx_expression_default,
8
15
  "no-extra-nested-boolean-cast": () => no_extra_nested_boolean_cast_default,
9
16
  "no-jsx-statement": () => no_jsx_statement_default,
17
+ "no-ternary-return": () => no_ternary_return_default,
10
18
  "unsafe-asserted-chain": () => unsafe_asserted_chain_default
11
19
  });
12
20
 
@@ -0,0 +1,10 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import { ESLintUtils } from "@typescript-eslint/utils";
3
+
4
+ //#region lib/rules/no-constant-template-expression.d.ts
5
+
6
+ declare const _default: ESLintUtils.RuleModule<"noConstantTemplateExpression" | "replaceByString", [{
7
+ minAllowedLength: number;
8
+ }], WyrmPluginDocs, ESLintUtils.RuleListener>;
9
+ //#endregion
10
+ export { _default };
@@ -0,0 +1,82 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { ASTUtils, AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-constant-template-expression.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ const DEFAULT_MIN_ALLOWED_LENGTH = 10;
8
+ var no_constant_template_expression_default = createRule({
9
+ name,
10
+ meta: {
11
+ type: "problem",
12
+ docs: {
13
+ description: "Disallow constant string expressions in template literals",
14
+ requiresTypeChecking: true,
15
+ strict: true
16
+ },
17
+ hasSuggestions: true,
18
+ schema: [{
19
+ type: "object",
20
+ properties: { minAllowedLength: {
21
+ type: "number",
22
+ description: `Minimum string length allowed for constant expressions. Default: ${DEFAULT_MIN_ALLOWED_LENGTH}`
23
+ } }
24
+ }],
25
+ messages: {
26
+ noConstantTemplateExpression: "Replace this constant template expression by its value as a string ('{{value}}')",
27
+ replaceByString: "Replace by '{{value}}'"
28
+ }
29
+ },
30
+ defaultOptions: [{ minAllowedLength: DEFAULT_MIN_ALLOWED_LENGTH }],
31
+ create(context, [options]) {
32
+ return { TemplateLiteral(node) {
33
+ const services = ESLintUtils.getParserServices(context);
34
+ const checker = services.program.getTypeChecker();
35
+ const { expressions, quasis } = node;
36
+ if (quasis.some((quasi) => quasi.value.cooked.includes(" "))) return;
37
+ const scope = context.sourceCode.getScope(node);
38
+ for (const expr of expressions) {
39
+ if (expr.type === AST_NODE_TYPES.Identifier) {
40
+ const variable = ASTUtils.findVariable(scope, expr);
41
+ if (variable) {
42
+ const { references, defs } = variable;
43
+ if (references.length > 2) continue;
44
+ const def = defs.at(-1);
45
+ if (def?.parent?.type === AST_NODE_TYPES.VariableDeclaration && (def.parent.parent.type === AST_NODE_TYPES.ExportNamedDeclaration || def.parent.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration)) continue;
46
+ }
47
+ }
48
+ const value = getLiteralValue(services.getTypeAtLocation(expr), checker);
49
+ if (value === null) continue;
50
+ if (value.length >= options.minAllowedLength) return;
51
+ context.report({
52
+ node: expr,
53
+ messageId: "noConstantTemplateExpression",
54
+ data: { value },
55
+ suggest: [{
56
+ messageId: "replaceByString",
57
+ data: { value },
58
+ fix(fixer) {
59
+ const [identStart, identEnd] = expr.range;
60
+ const previousQuasi = quasis.toReversed().find((quasi) => quasi.range[1] <= identStart);
61
+ const nextQuasi = quasis.find((quasi) => quasi.range[0] >= identEnd);
62
+ const start = previousQuasi?.range[1] ?? node.range[0];
63
+ const end = nextQuasi?.range[0] ?? node.range[1];
64
+ const range = [start - 2, end + 1];
65
+ return fixer.replaceTextRange(range, value);
66
+ }
67
+ }]
68
+ });
69
+ }
70
+ } };
71
+ }
72
+ });
73
+ function getLiteralValue(type, checker) {
74
+ if (type.isStringLiteral()) return type.value;
75
+ if (type.isNumberLiteral()) return type.value.toString();
76
+ if (type === checker.getTrueType()) return "true";
77
+ if (type === checker.getFalseType()) return "false";
78
+ return null;
79
+ }
80
+
81
+ //#endregion
82
+ export { no_constant_template_expression_default as default };
@@ -0,0 +1,9 @@
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-empty-comment.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint0.RuleModule<"noEmptyComment", [{
6
+ allowStacked: boolean;
7
+ }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint0.RuleListener>;
8
+ //#endregion
9
+ export { _default };
@@ -0,0 +1,57 @@
1
+ import { createRule } from "../utils/createRule.js";
2
+ import path from "node:path";
3
+ import { AST_TOKEN_TYPES } from "@typescript-eslint/utils";
4
+
5
+ //#region lib/rules/no-empty-comment.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ const DEFAULT_ALLOW_STACKED = false;
8
+ var no_empty_comment_default = createRule({
9
+ name,
10
+ meta: {
11
+ type: "suggestion",
12
+ docs: {
13
+ description: "Forbid empty comments",
14
+ strict: true
15
+ },
16
+ schema: [{
17
+ type: "object",
18
+ additionalProperties: false,
19
+ properties: { allowStacked: {
20
+ type: "boolean",
21
+ description: `Whether to allow empty comments stacked next to non-empty comments. Default: \`${DEFAULT_ALLOW_STACKED}\``
22
+ } }
23
+ }],
24
+ messages: { noEmptyComment: "Remove this empty comment" }
25
+ },
26
+ defaultOptions: [{ allowStacked: DEFAULT_ALLOW_STACKED }],
27
+ create(context, [options]) {
28
+ if (typeof context.sourceCode.getAllComments === "undefined") return {};
29
+ const comments = context.sourceCode.getAllComments();
30
+ for (const comment of comments) {
31
+ if (!isEmptyComment(comment)) continue;
32
+ if (options.allowStacked && isStackedComment(comment, comments)) continue;
33
+ context.report({
34
+ node: comment,
35
+ messageId: "noEmptyComment"
36
+ });
37
+ }
38
+ return {};
39
+ }
40
+ });
41
+ function isEmptyComment(comment) {
42
+ return !comment.value.replace(/^\*/u, "").replaceAll("*\n", "").trim();
43
+ }
44
+ function isStackedComment(comment, comments) {
45
+ if (comment.type !== AST_TOKEN_TYPES.Line) return false;
46
+ return comments.some((otherComment) => {
47
+ if (otherComment === comment) return false;
48
+ if (otherComment.type !== AST_TOKEN_TYPES.Line) return false;
49
+ if (isEmptyComment(otherComment)) return false;
50
+ if (otherComment.loc.start.line === comment.loc.start.line - 1) return true;
51
+ if (otherComment.loc.start.line === comment.loc.start.line + 1) return true;
52
+ return false;
53
+ });
54
+ }
55
+
56
+ //#endregion
57
+ export { no_empty_comment_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-empty-jsx-expression.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint1.RuleModule<"noEmptyJsxExpression", [], 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-empty-jsx-expression.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ var no_empty_jsx_expression_default = createRule({
8
+ name,
9
+ meta: {
10
+ type: "suggestion",
11
+ docs: {
12
+ description: "Forbid empty JSX expression containers",
13
+ recommended: true
14
+ },
15
+ schema: [],
16
+ messages: { noEmptyJsxExpression: "Remove this empty JSX expression container" }
17
+ },
18
+ defaultOptions: [],
19
+ create(context) {
20
+ return {
21
+ JSXEmptyExpression(node) {
22
+ if (context.sourceCode.getCommentsInside(node).length) return;
23
+ context.report({
24
+ node,
25
+ messageId: "noEmptyJsxExpression"
26
+ });
27
+ },
28
+ JSXExpressionContainer(node) {
29
+ if (node.expression.type === AST_NODE_TYPES.JSXEmptyExpression) return;
30
+ switch (node.expression.type) {
31
+ case AST_NODE_TYPES.Literal:
32
+ if (node.expression.value === null) break;
33
+ if (node.expression.value === false) break;
34
+ if (node.expression.value === "") break;
35
+ return;
36
+ case AST_NODE_TYPES.Identifier:
37
+ if (node.expression.name === "undefined") break;
38
+ return;
39
+ default: return;
40
+ }
41
+ context.report({
42
+ node,
43
+ messageId: "noEmptyJsxExpression"
44
+ });
45
+ }
46
+ };
47
+ }
48
+ });
49
+
50
+ //#endregion
51
+ export { no_empty_jsx_expression_default as default };
@@ -1,8 +1,8 @@
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_eslint3 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_eslint0.RuleModule<"noExtraBooleanCastInCondition" | "noExtraBooleanCastInPredicate" | "noExtraBooleanCastInsideAnother", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint0.RuleListener>;
6
+ declare const _default: _typescript_eslint_utils_ts_eslint3.RuleModule<"noExtraBooleanCastInCondition" | "noExtraBooleanCastInPredicate" | "noExtraBooleanCastInsideAnother", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint3.RuleListener>;
7
7
  //#endregion
8
8
  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_eslint5 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_eslint1.RuleModule<"noJsxExpressionStatement", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint1.RuleListener>;
5
+ declare const _default: _typescript_eslint_utils_ts_eslint5.RuleModule<"noJsxExpressionStatement", [], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint5.RuleListener>;
6
6
  //#endregion
7
7
  export { _default };
@@ -0,0 +1,9 @@
1
+ import { WyrmPluginDocs } from "../utils/createRule.js";
2
+ import * as _typescript_eslint_utils_ts_eslint7 from "@typescript-eslint/utils/ts-eslint";
3
+
4
+ //#region lib/rules/no-ternary-return.d.ts
5
+ declare const _default: _typescript_eslint_utils_ts_eslint7.RuleModule<"noTernaryReturn", [{
6
+ allowSingleLine: boolean;
7
+ }], WyrmPluginDocs, _typescript_eslint_utils_ts_eslint7.RuleListener>;
8
+ //#endregion
9
+ 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-ternary-return.ts
6
+ const { name } = path.parse(import.meta.filename);
7
+ const DEFAULT_ALLOW_SINGLE_LINE = false;
8
+ var no_ternary_return_default = createRule({
9
+ name,
10
+ meta: {
11
+ type: "suggestion",
12
+ docs: {
13
+ description: "Disallow ternary conditions in return statements",
14
+ strict: true
15
+ },
16
+ fixable: "code",
17
+ schema: [{
18
+ type: "object",
19
+ properties: { allowSingleLine: {
20
+ type: "boolean",
21
+ description: `Whether to allow single line ternary conditions. Default: \`${DEFAULT_ALLOW_SINGLE_LINE}\``
22
+ } }
23
+ }],
24
+ messages: { noTernaryReturn: "Replace this ternary condition by multiple return statements" }
25
+ },
26
+ defaultOptions: [{ allowSingleLine: DEFAULT_ALLOW_SINGLE_LINE }],
27
+ create(context, [options]) {
28
+ return { ReturnStatement(node) {
29
+ const { argument } = node;
30
+ if (!argument) return;
31
+ if (argument.type !== AST_NODE_TYPES.ConditionalExpression) return;
32
+ if (options.allowSingleLine && argument.loc.start.line === argument.loc.end.line) return;
33
+ const { test, consequent, alternate } = argument;
34
+ context.report({
35
+ node,
36
+ messageId: "noTernaryReturn",
37
+ *fix(fixer) {
38
+ const condText = context.sourceCode.getText(test);
39
+ const thenText = context.sourceCode.getText(consequent);
40
+ const elseText = context.sourceCode.getText(alternate);
41
+ const indent = " ".repeat(node.loc.start.column);
42
+ yield fixer.replaceText(node, `if (${condText}) return ${thenText};`);
43
+ yield fixer.insertTextAfter(node, `\n${indent}return ${elseText};`);
44
+ }
45
+ });
46
+ } };
47
+ }
48
+ });
49
+
50
+ //#endregion
51
+ export { no_ternary_return_default as default };
@@ -0,0 +1,83 @@
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 -->
@@ -0,0 +1,70 @@
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 -->
@@ -0,0 +1,77 @@
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,6 +1,6 @@
1
1
  # Forbid extra boolean casts in conditions and predicates (`wyrm/no-extra-nested-boolean-cast`)
2
2
 
3
- 💼 This rule is enabled in the following configs: 🟢 `wyrm/strict`, 🟣 `wyrm/strictTypeChecked`.
3
+ 💼 This rule is enabled in the following configs: 🟪 `strict`, ☑️ `strictTypeChecked`.
4
4
 
5
5
  ## Description
6
6
 
@@ -20,13 +20,15 @@ declare const foo: string;
20
20
  const bar = !!foo ? 'ok' : 'ko';
21
21
  ```
22
22
 
23
+ This rules conflicts with the [`@typescript-eslint/strict-boolean-expressions`](https://typescript-eslint.io/rules/strict-boolean-expressions/) rule.
24
+
23
25
  ## Cases
24
26
 
25
27
  ### Incorrect ❌
26
28
 
27
- ```tsx
28
- // Redundant double negation
29
+ Redundant double negation:
29
30
 
31
+ ```tsx
30
32
  declare const foo: string;
31
33
 
32
34
  if (!!bar) {
@@ -34,22 +36,22 @@ if (!!bar) {
34
36
  }
35
37
  ```
36
38
 
37
- ```tsx
38
- // Redundant double negation inside of another boolean cast
39
+ Redundant double negation inside of another boolean cast:
39
40
 
41
+ ```tsx
40
42
  const x = Boolean(!!foo);
41
43
  ```
42
44
 
43
- ```tsx
44
- // Redundant double negation in return of array method predicate
45
+ Redundant double negation in return of array method predicate:
45
46
 
47
+ ```tsx
46
48
  declare const arr: string[];
47
49
  const isOkay = arr.filter((elt) => !!elt);
48
50
  ```
49
51
 
50
- ```tsx
51
- // Redundant double negations in logical sub-expressions
52
+ Redundant double negations in logical sub-expressions:
52
53
 
54
+ ```tsx
53
55
  declare const foo: string;
54
56
  declare const bar: string;
55
57
  declare const baz: string;
@@ -59,9 +61,9 @@ if (!!bar && (!!foo || !!baz)) {
59
61
  }
60
62
  ```
61
63
 
62
- ```tsx
63
- // Redundant Boolean calls
64
+ Redundant Boolean calls:
64
65
 
66
+ ```tsx
65
67
  declare const foo: string;
66
68
  declare const bar: string;
67
69
  declare const baz: string;
@@ -71,9 +73,9 @@ if (Boolean(bar) && (Boolean(foo) || Boolean(baz))) {
71
73
  }
72
74
  ```
73
75
 
74
- ```tsx
75
- // Redundant double negations nested in type assertions
76
+ Redundant double negations nested in type assertions:
76
77
 
78
+ ```tsx
77
79
  declare const foo: string;
78
80
  declare const bar: string;
79
81
  declare const baz: string;
@@ -85,9 +87,9 @@ if ((!!bar)! && ((!!foo satisfies boolean) || (!!baz as any))) {
85
87
 
86
88
  ### Correct ✅
87
89
 
88
- ```tsx
89
- // No extra boolean cast
90
+ No extra boolean cast:
90
91
 
92
+ ```tsx
91
93
  declare const foo: string;
92
94
  declare const bar: string;
93
95
  declare const baz: string;
@@ -97,9 +99,9 @@ if (bar && (foo || baz)) {
97
99
  }
98
100
  ```
99
101
 
100
- ```tsx
101
- // Short-circuiting expression
102
+ Short-circuiting expression:
102
103
 
104
+ ```tsx
103
105
  declare const foo: string;
104
106
  declare const bar: string;
105
107
  declare const baz: string;
@@ -1,14 +1,14 @@
1
1
  # Forbid JSX expression statements (`wyrm/no-jsx-statement`)
2
2
 
3
- 💼 This rule is enabled in the following configs: `wyrm/recommended`, ☑️ `wyrm/recommendedTypeChecked`, 🟢 `wyrm/strict`, 🟣 `wyrm/strictTypeChecked`.
3
+ 💼 This rule is enabled in the following configs: 🟩 `recommended`, `recommendedTypeChecked`, 🟪 `strict`, ☑️ `strictTypeChecked`.
4
4
 
5
5
  ## Cases
6
6
 
7
7
  ### Incorrect ❌
8
8
 
9
- ```tsx
10
- // JSX fragment in expression statement
9
+ JSX fragment in expression statement:
11
10
 
11
+ ```tsx
12
12
  export function MyComponent() {
13
13
  <></>;
14
14
  }
@@ -16,17 +16,17 @@ export function MyComponent() {
16
16
 
17
17
  ### Correct ✅
18
18
 
19
- ```tsx
20
- // JSX element in return statement
19
+ JSX element in return statement:
21
20
 
21
+ ```tsx
22
22
  export function MyComponent() {
23
23
  return <div />;
24
24
  }
25
25
  ```
26
26
 
27
- ```tsx
28
- // JSX element in variable initialization
27
+ JSX element in variable initialization:
29
28
 
29
+ ```tsx
30
30
  export function MyComponent() {
31
31
  const jsx = <div />;
32
32
  return jsx;
@@ -0,0 +1,46 @@
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,6 +1,6 @@
1
1
  # Disallow unsafe type assertions on optional chained expressions (`wyrm/unsafe-asserted-chain`)
2
2
 
3
- 💼 This rule is enabled in the 🟣 `wyrm/strictTypeChecked` config.
3
+ 💼 This rule is enabled in the ☑️ `strictTypeChecked` config.
4
4
 
5
5
  💭 This rule requires [type information](https://typescript-eslint.io/linting/typed-linting).
6
6
 
@@ -28,39 +28,39 @@ foo.bar as string;
28
28
 
29
29
  ### Incorrect ❌
30
30
 
31
- ```tsx
32
- // Optional chain asserted as not undefined
31
+ Optional chain asserted as not undefined:
33
32
 
33
+ ```tsx
34
34
  declare const foo: { bar: string | number } | null;
35
35
  const str = (foo?.bar as string).toUpperCase();
36
36
  ```
37
37
 
38
- ```tsx
39
- // Optional chain call expression asserted as not undefined
38
+ Optional chain call expression asserted as not undefined:
40
39
 
40
+ ```tsx
41
41
  declare const foo: { bar: () => string | number } | null;
42
42
  const str = (foo?.bar() as string | number)?.toString();
43
43
  ```
44
44
 
45
45
  ### Correct ✅
46
46
 
47
- ```tsx
48
- // Optional chain asserted as nullable
47
+ Optional chain asserted as nullable:
49
48
 
49
+ ```tsx
50
50
  declare const foo: { bar: string | number } | null;
51
51
  const str = (foo?.bar as string | undefined)?.toUpperCase();
52
52
  ```
53
53
 
54
- ```tsx
55
- // Optional chain asserted as any
54
+ Optional chain asserted as any:
56
55
 
56
+ ```tsx
57
57
  declare const foo: { bar: string | number } | null;
58
58
  const str = (foo?.bar as any)?.toUpperCase();
59
59
  ```
60
60
 
61
- ```tsx
62
- // Optional chain asserted as unknown
61
+ Optional chain asserted as unknown:
63
62
 
63
+ ```tsx
64
64
  declare const foo: { bar: string | number } | null;
65
65
  const str = (foo?.bar as unknown)?.toUpperCase();
66
66
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-wyrm",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Some custom ESLint rules",
5
5
  "keywords": [
6
6
  "eslint",
@@ -36,6 +36,7 @@
36
36
  "eslint": ">=9.38.0",
37
37
  "eslint-doc-generator": "^2.3.0",
38
38
  "jest-diff": "^30.2.0",
39
+ "jiti": "^2.6.1",
39
40
  "markdownlint-cli2": "^0.18.1",
40
41
  "prettier": "^3.6.2",
41
42
  "tsdown": "^0.15.9",
@@ -52,6 +53,7 @@
52
53
  "fix:eslint-docs": "eslint-doc-generator",
53
54
  "fix:format": "prettier --write .",
54
55
  "fix:js": "eslint . --fix",
56
+ "preinit:eslint-docs": "pnpm run build",
55
57
  "init:eslint-docs": "eslint-doc-generator --init-rule-docs",
56
58
  "lint:docs": "markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#CHANGELOG.md\"",
57
59
  "lint:eslint-docs": "eslint-doc-generator --check",