Skip to content

Commit

Permalink
feat: Add prefer-less-than rule.
Browse files Browse the repository at this point in the history
  • Loading branch information
cartant committed May 27, 2021
1 parent 6932adf commit 17fafab
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -78,5 +78,6 @@ Rules marked with ✅ are recommended and rules marked with 🔧 have fixers.
| [`no-misused-generics`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/no-misused-generics.md) | Forbids type parameters without inference sites and type parameters that don't add type safety to declarations. This is an ESLint port of [Wotan's `no-misused-generics` rule](https://github.com/fimbullinter/wotan/blob/11368a193ba90a9e79b9f6ab530be1b434b122de/packages/mimir/docs/no-misused-generics.md). See also ["The Golden Rule of Generics"](https://effectivetypescript.com/2020/08/12/generics-golden-rule/). | | |
| [`no-t`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/no-t.md) | Forbids single-character type parameters. | | |
| [`prefer-interface`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/prefer-interface.md) | Forbids type aliases where interfaces can be used. | | 🔧 |
| [`prefer-less-than`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/prefer-less-than.md) | Forbids greater-than comparisons. (Yes, this is the rule for [Ben Lesh comparisons](https://twitter.com/BenLesh/status/1397593619096166400).) | | 🔧 |
| [`throw-error`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/throw-error.md) | Forbids throwing - or rejecting with - non-`Error` values. | | |
| [`underscore-internal`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/underscore-internal.md) | Forbids internal APIs that are not prefixed with underscores. | | |
25 changes: 25 additions & 0 deletions docs/rules/prefer-less-than.md
@@ -0,0 +1,25 @@
# Use less-than instead of greater-than comparisons (`prefer-less-than`)

Yes, this is the rule for [Ben Lesh comparisons](https://twitter.com/BenLesh/status/1397593619096166400).

## Rule details

Examples of **incorrect** code for this rule:

```ts
if (x > a && x < b) { /* .. */ }
```

```ts
if (x >= a && x =< b) { /* .. */ }
```
Examples of **correct** code for this rule:
```ts
if (a < x && x < b) { /* .. */ }
```
```ts
if (a <= x && x =< b) { /* .. */ }
```
65 changes: 65 additions & 0 deletions source/rules/prefer-less-than.ts
@@ -0,0 +1,65 @@
/**
* @license Use of this source code is governed by an MIT-style license that
* can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-etc
*/

import {
TSESLint as eslint,
TSESTree as es,
} from "@typescript-eslint/experimental-utils";
import { ruleCreator } from "../utils";

const rule = ruleCreator({
defaultOptions: [],
meta: {
docs: {
category: "Best Practices",
description: "Forbids greater-than comparisons.",
recommended: false,
},
fixable: "code",
messages: {
forbiddenGT: "Greater-than comparisons are forbidden.",
forbiddenGTE: "Greater-than-or-equal comparisons are forbidden.",
suggestLT: "Use a less-than comparison instead.",
suggestLTE: "Use a less-than-or-equal comparison instead.",
},
schema: [],
type: "suggestion",
},
name: "prefer-less-than",
create: (context) => {
return {
"BinaryExpression[operator=/^(>|>=)$/]": (
expression: es.BinaryExpression
) => {
const gte = expression.operator === ">=";
function fix(fixer: eslint.RuleFixer) {
const { left, right } = expression;
const sourceCode = context.getSourceCode();
const operator = sourceCode.getTokenAfter(left);
return operator
? [
fixer.replaceText(left, sourceCode.getText(right)),
fixer.replaceTextRange(operator.range, gte ? "<=" : "<"),
fixer.replaceText(right, sourceCode.getText(left)),
]
: [];
}
context.report({
fix,
messageId: gte ? "forbiddenGTE" : "forbiddenGT",
node: expression,
suggest: [
{
fix,
messageId: gte ? "suggestLTE" : "suggestLT",
},
],
});
},
};
},
});

export = rule;
112 changes: 112 additions & 0 deletions tests/rules/prefer-less-than.ts
@@ -0,0 +1,112 @@
/**
* @license Use of this source code is governed by an MIT-style license that
* can be found in the LICENSE file at https://github.com/cartant/eslint-plugin-etc
*/

import { stripIndent } from "common-tags";
import { fromFixture } from "eslint-etc";
import rule = require("../../source/rules/prefer-less-than");
import { ruleTester } from "../utils";

ruleTester({ types: false }).run("prefer-less-than", rule, {
valid: [
`const result = 42 < 54;`,
`const result = 42 <= 54;`,
`const result = 42 == 54;`,
`const result = 42 === 54;`,
`const result = 42 != 54;`,
`const result = 42 !== 54;`,
`if (a < x && x < b) { /* .. */ }`,
`if (a <= x && x <= b) { /* .. */ }`,
],
invalid: [
fromFixture(
stripIndent`
const result = 54 > 42;
~~~~~~~ [forbiddenGT]
`,
{
output: stripIndent`
const result = 42 < 54;
`,
}
),
fromFixture(
stripIndent`
const result = 54 >= 42;
~~~~~~~~ [forbiddenGTE]
`,
{
output: stripIndent`
const result = 42 <= 54;
`,
}
),
fromFixture(
stripIndent`
const result = 54.0 > 42;
~~~~~~~~~ [forbiddenGT]
`,
{
output: stripIndent`
const result = 42 < 54.0;
`,
}
),
fromFixture(
stripIndent`
const result = 54.0 >= 42;
~~~~~~~~~~ [forbiddenGTE]
`,
{
output: stripIndent`
const result = 42 <= 54.0;
`,
}
),
fromFixture(
stripIndent`
const result = 54 > 42.0;
~~~~~~~~~ [forbiddenGT]
`,
{
output: stripIndent`
const result = 42.0 < 54;
`,
}
),
fromFixture(
stripIndent`
const result = 54 >= 42.0;
~~~~~~~~~~ [forbiddenGTE]
`,
{
output: stripIndent`
const result = 42.0 <= 54;
`,
}
),
fromFixture(
stripIndent`
if (x > a && x < b) { /* .. */ }
~~~~~ [forbiddenGT]
`,
{
output: stripIndent`
if (a < x && x < b) { /* .. */ }
`,
}
),
fromFixture(
stripIndent`
if (x >= a && x <= b) { /* .. */ }
~~~~~~ [forbiddenGTE]
`,
{
output: stripIndent`
if (a <= x && x <= b) { /* .. */ }
`,
}
),
],
});

0 comments on commit 17fafab

Please sign in to comment.