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.
- package/CHANGELOG.md +8 -0
- package/README.md +7 -0
- package/dist/configs/index.js +3 -3
- package/dist/rules/index.d.ts +14 -7
- package/dist/rules/index.js +14 -0
- package/dist/rules/no-else-break.d.ts +7 -0
- package/dist/rules/no-else-break.js +51 -0
- package/dist/rules/no-else-continue.d.ts +7 -0
- package/dist/rules/no-else-continue.js +51 -0
- package/dist/rules/no-else-throw.d.ts +7 -0
- package/dist/rules/no-else-throw.js +51 -0
- package/dist/rules/no-empty-comment.d.ts +3 -3
- package/dist/rules/no-empty-jsx-expression.d.ts +2 -2
- package/dist/rules/no-extra-nested-boolean-cast.d.ts +2 -2
- package/dist/rules/no-invalid-date-literal.d.ts +7 -0
- package/dist/rules/no-invalid-date-literal.js +68 -0
- package/dist/rules/no-jsx-statement.d.ts +2 -2
- package/dist/rules/no-suspicious-jsx-semicolon.d.ts +8 -0
- package/dist/rules/no-suspicious-jsx-semicolon.js +39 -0
- package/dist/rules/no-ternary-return.d.ts +3 -3
- package/dist/rules/no-useless-iife.d.ts +7 -0
- package/dist/rules/no-useless-iife.js +93 -0
- package/dist/rules/prefer-repeat.d.ts +7 -0
- package/dist/rules/prefer-repeat.js +108 -0
- package/dist/utils/option.js +18 -0
- package/package.json +1 -1
- package/docs/rules/no-constant-template-expression.md +0 -83
- package/docs/rules/no-empty-comment.md +0 -70
- package/docs/rules/no-empty-jsx-expression.md +0 -77
- package/docs/rules/no-extra-nested-boolean-cast.md +0 -112
- package/docs/rules/no-jsx-statement.md +0 -36
- package/docs/rules/no-ternary-return.md +0 -46
- 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 -->
|
package/dist/configs/index.js
CHANGED
|
@@ -38,7 +38,7 @@ const strictOnly = createConfigWithRules(rules_exports, "strictOnly", (rule) =>
|
|
|
38
38
|
});
|
|
39
39
|
const strict = {
|
|
40
40
|
...baseConfig,
|
|
41
|
-
name:
|
|
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:
|
|
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:
|
|
67
|
+
name: "wyrm/strictTypeChecked",
|
|
68
68
|
rules: {
|
|
69
69
|
...recommendedTypeChecked.rules,
|
|
70
70
|
...strictOnly.rules,
|
package/dist/rules/index.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { _default } from "./no-constant-template-expression.js";
|
|
2
|
-
import { _default as _default$1 } from "./no-
|
|
3
|
-
import { _default as _default$2 } from "./no-
|
|
4
|
-
import { _default as _default$3 } from "./no-
|
|
5
|
-
import { _default as _default$4 } from "./no-
|
|
6
|
-
import { _default as _default$5 } from "./no-
|
|
7
|
-
import { _default as _default$6 } from "./
|
|
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$
|
|
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 };
|
package/dist/rules/index.js
CHANGED
|
@@ -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
|
|
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:
|
|
5
|
+
declare const _default: _typescript_eslint_utils_ts_eslint5.RuleModule<"noEmptyComment", [{
|
|
6
6
|
allowStacked: boolean;
|
|
7
|
-
}], WyrmPluginDocs,
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
5
|
+
declare const _default: _typescript_eslint_utils_ts_eslint17.RuleModule<"noTernaryReturn", [{
|
|
6
6
|
allowSingleLine: boolean;
|
|
7
|
-
}], WyrmPluginDocs,
|
|
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,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 -->
|