From 485dbf97620b040f3a00087c519a6424207e3e27 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Dec 2020 18:11:53 +0800 Subject: [PATCH] Add `no-lonely-if` rule (#936) Co-authored-by: Sindre Sorhus --- docs/rules/no-lonely-if.md | 64 ++++ index.js | 1 + readme.md | 2 + rules/import-style.js | 16 +- rules/no-lonely-if.js | 90 ++++++ test/no-lonely-if.js | 126 ++++++++ test/snapshots/no-lonely-if.js.md | 477 ++++++++++++++++++++++++++++ test/snapshots/no-lonely-if.js.snap | Bin 0 -> 1467 bytes 8 files changed, 767 insertions(+), 9 deletions(-) create mode 100644 docs/rules/no-lonely-if.md create mode 100644 rules/no-lonely-if.js create mode 100644 test/no-lonely-if.js create mode 100644 test/snapshots/no-lonely-if.js.md create mode 100644 test/snapshots/no-lonely-if.js.snap diff --git a/docs/rules/no-lonely-if.md b/docs/rules/no-lonely-if.md new file mode 100644 index 0000000000..ffaffa3e72 --- /dev/null +++ b/docs/rules/no-lonely-if.md @@ -0,0 +1,64 @@ +# Disallow `if` statements as the only statement in `if` blocks without `else` + +This rule adds onto the built-in [`no-lonely-if`](https://eslint.org/docs/rules/no-lonely-if) rule, which only forbids `if` statements in `else`, not in `if`. + +This rule is fixable. + +## Fail + +```js +if (foo) { + if (bar) { + // … + } +} +``` + +```js +if (foo) { + // … +} else if (bar) { + if (baz) { + // … + } +} +``` + +## Pass + +```js +if (foo && bar) { + // … +} +``` + +```js +if (foo) { + // … +} else if (bar && baz) { + // … +} +``` + +```js +if (foo) { + // … +} else if (bar) { + if (baz) { + // … + } +} else { + // … +} +``` + +```js +// Built-in rule `no-lonely-if` case https://eslint.org/docs/rules/no-lonely-if +if (foo) { + // … +} else { + if (bar) { + // … + } +} +``` diff --git a/index.js b/index.js index f09f19ed22..9c82f03253 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,7 @@ module.exports = { 'unicorn/no-for-loop': 'error', 'unicorn/no-hex-escape': 'error', 'unicorn/no-keyword-prefix': 'off', + 'unicorn/no-lonely-if': 'error', 'no-nested-ternary': 'off', 'unicorn/no-nested-ternary': 'error', 'unicorn/no-new-buffer': 'error', diff --git a/readme.md b/readme.md index ea474c3b97..74427c84a2 100644 --- a/readme.md +++ b/readme.md @@ -53,6 +53,7 @@ Configure it in `package.json`. "unicorn/no-for-loop": "error", "unicorn/no-hex-escape": "error", "unicorn/no-keyword-prefix": "off", + "unicorn/no-lonely-if": "error", "no-nested-ternary": "off", "unicorn/no-nested-ternary": "error", "unicorn/no-new-buffer": "error", @@ -122,6 +123,7 @@ Configure it in `package.json`. - [no-for-loop](docs/rules/no-for-loop.md) - Do not use a `for` loop that can be replaced with a `for-of` loop. *(partly fixable)* - [no-hex-escape](docs/rules/no-hex-escape.md) - Enforce the use of Unicode escapes instead of hexadecimal escapes. *(fixable)* - [no-keyword-prefix](docs/rules/no-keyword-prefix.md) - Disallow identifiers starting with `new` or `class`. +- [no-lonely-if](docs/rules/no-lonely-if.md) - Disallow `if` statements as the only statement in `if` blocks without `else`. *(fixable)* - [no-nested-ternary](docs/rules/no-nested-ternary.md) - Disallow nested ternary expressions. *(partly fixable)* - [no-new-buffer](docs/rules/no-new-buffer.md) - Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. *(fixable)* - [no-null](docs/rules/no-null.md) - Disallow the use of the `null` literal. diff --git a/rules/import-style.js b/rules/import-style.js index 24813941d4..5aa23d19c8 100644 --- a/rules/import-style.js +++ b/rules/import-style.js @@ -183,15 +183,13 @@ const create = context => { let effectiveAllowedImportStyles = allowedImportStyles; - if (isRequire) { - // For `require`, `'default'` style allows both `x = require('x')` (`'namespace'` style) and - // `{default: x} = require('x')` (`'default'` style) since we don't know in advance - // whether `'x'` is a compiled ES6 module (with `default` key) or a CommonJS module and `require` - // does not provide any automatic interop for this, so the user may have to use either of theese. - if (allowedImportStyles.has('default') && !allowedImportStyles.has('namespace')) { - effectiveAllowedImportStyles = new Set(allowedImportStyles); - effectiveAllowedImportStyles.add('namespace'); - } + // For `require`, `'default'` style allows both `x = require('x')` (`'namespace'` style) and + // `{default: x} = require('x')` (`'default'` style) since we don't know in advance + // whether `'x'` is a compiled ES6 module (with `default` key) or a CommonJS module and `require` + // does not provide any automatic interop for this, so the user may have to use either of theese. + if (isRequire && allowedImportStyles.has('default') && !allowedImportStyles.has('namespace')) { + effectiveAllowedImportStyles = new Set(allowedImportStyles); + effectiveAllowedImportStyles.add('namespace'); } if (actualImportStyles.every(style => effectiveAllowedImportStyles.has(style))) { diff --git a/rules/no-lonely-if.js b/rules/no-lonely-if.js new file mode 100644 index 0000000000..0f6ba0004f --- /dev/null +++ b/rules/no-lonely-if.js @@ -0,0 +1,90 @@ +'use strict'; +const getDocumentationUrl = require('./utils/get-documentation-url'); +const needsSemicolon = require('./utils/needs-semicolon'); + +const MESSAGE_ID = 'no-lonely-if'; +const messages = { + [MESSAGE_ID]: 'Unexpected `if` as the only statement in a `if` block without `else`.' +}; + +const ifStatementWithoutAlternate = 'IfStatement:not([alternate])'; +const selector = `:matches(${ + [ + // `if (a) { if (b) {} }` + [ + ifStatementWithoutAlternate, + '>', + 'BlockStatement.consequent', + '[body.length=1]', + '>', + `${ifStatementWithoutAlternate}.body` + ].join(''), + + // `if (a) if (b) {}` + `${ifStatementWithoutAlternate} > ${ifStatementWithoutAlternate}.consequent` + ].join(', ') +})`; + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table +// Lower precedence than `&&` +const needParenthesis = node => ( + (node.type === 'LogicalExpression' && (node.operator === '||' || node.operator === '??')) || + node.type === 'ConditionalExpression' || + node.type === 'AssignmentExpression' || + node.type === 'YieldExpression' || + node.type === 'SequenceExpression' +); + +const create = context => { + const sourceCode = context.getSourceCode(); + const getText = node => sourceCode.getText(node); + const getTestNodeText = node => needParenthesis(node) ? `(${getText(node)})` : getText(node); + + return { + [selector](inner) { + const {parent} = inner; + const outer = parent.type === 'BlockStatement' ? parent.parent : parent; + + context.report({ + node: inner, + messageId: MESSAGE_ID, + * fix(fixer) { + // Merge `test` + yield fixer.replaceText(outer.test, `${getTestNodeText(outer.test)} && ${getTestNodeText(inner.test)}`); + + // Replace `consequent` + const {consequent} = inner; + let consequentText = getText(consequent); + // If the `if` statement has no block, and is not followed by a semicolon, + // make sure that fixing the issue would not change semantics due to ASI. + // Similar logic https://github.com/eslint/eslint/blob/2124e1b5dad30a905dc26bde9da472bf622d3f50/lib/rules/no-lonely-if.js#L61-L77 + if ( + consequent.type !== 'BlockStatement' && + outer.consequent.type === 'BlockStatement' && + !consequentText.endsWith(';') + ) { + const lastToken = sourceCode.getLastToken(consequent); + const nextToken = sourceCode.getTokenAfter(outer); + if (needsSemicolon(lastToken, sourceCode, nextToken.value)) { + consequentText += ';'; + } + } + + yield fixer.replaceText(outer.consequent, consequentText); + } + }); + } + }; +}; + +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + url: getDocumentationUrl(__filename) + }, + fixable: 'code', + messages + } +}; diff --git a/test/no-lonely-if.js b/test/no-lonely-if.js new file mode 100644 index 0000000000..c333c09055 --- /dev/null +++ b/test/no-lonely-if.js @@ -0,0 +1,126 @@ +import {outdent} from 'outdent'; +import {test} from './utils/test'; + +test({ + valid: [ + outdent` + if (a) { + if (b) { + } + } else {} + `, + outdent` + if (a) { + if (b) { + } + foo(); + } else {} + `, + outdent` + if (a) { + } else { + if (y) {} + } + `, + outdent` + if (a) { + b ? c() : d() + } + ` + ], + invalid: [] +}); + +test.visualize([ + outdent` + if (a) { + if (b) { + } + } + `, + // Inner one is `BlockStatement` + outdent` + if (a) if (b) { + foo(); + } + `, + // Outer one is `BlockStatement` + outdent` + if (a) { + if (b) foo(); + } + `, + // No `BlockStatement` + 'if (a) if (b) foo();', + // `EmptyStatement` + 'if (a) if (b);', + // Nested + outdent` + if (a) { + if (b) { + // Should not report + } + } else if (c) { + if (d) { + } + } + `, + // Need parenthesis + outdent` + function * foo() { + if (a || b) + if (a ?? b) + if (a ? b : c) + if (a = b) + if (a += b) + if (a -= b) + if (a &&= b) + if (yield a) + if (a, b); + } + `, + // Should not add parenthesis + outdent` + async function foo() { + if (a) + if (await a) + if (a.b) + if (a && b); + } + `, + // Don't case parenthesis in outer test + 'if (((a || b))) if (((c || d)));', + // Comments + outdent` + if /* will keep */ + ( + /* will keep */ + a /* will keep */ + .b /* will keep */ + ) /* keep */{ + /* will remove */ + if ( + /* will remove */ + c /* will keep */ + .d /* will remove */ + ) { + /* will keep */ + foo(); + /* will keep */ + } + /* will remove */ + } + `, + // Semicolon + outdent` + if (a) { + if (b) foo() + } + [].forEach(bar) + `, + outdent` + if (a) + if (b) foo() + ;[].forEach(bar) + ` +]); diff --git a/test/snapshots/no-lonely-if.js.md b/test/snapshots/no-lonely-if.js.md new file mode 100644 index 0000000000..6c5e4cce16 --- /dev/null +++ b/test/snapshots/no-lonely-if.js.md @@ -0,0 +1,477 @@ +# Snapshot report for `test/no-lonely-if.js` + +The actual snapshot is saved in `no-lonely-if.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## no-lonely-if - #1 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) {␊ + 2 | if (b) {␊ + 3 | }␊ + 4 | }␊ + ␊ + Output:␊ + 1 | if (a && b) {␊ + 2 | }␊ + ␊ + Error 1/1:␊ + 1 | if (a) {␊ + > 2 | if (b) {␊ + | ^^^^^^^^␊ + > 3 | }␊ + | ^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 4 | }␊ + ` + +## no-lonely-if - #2 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) if (b) {␊ + 2 | foo();␊ + 3 | }␊ + ␊ + Output:␊ + 1 | if (a && b) {␊ + 2 | foo();␊ + 3 | }␊ + ␊ + Error 1/1:␊ + > 1 | if (a) if (b) {␊ + | ^^^^^^^^␊ + > 2 | foo();␊ + | ^^^^^^^␊ + > 3 | }␊ + | ^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + ` + +## no-lonely-if - #3 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) {␊ + 2 | if (b) foo();␊ + 3 | }␊ + ␊ + Output:␊ + 1 | if (a && b) foo();␊ + ␊ + Error 1/1:␊ + 1 | if (a) {␊ + > 2 | if (b) foo();␊ + | ^^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 3 | }␊ + ` + +## no-lonely-if - #4 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) if (b) foo();␊ + ␊ + Output:␊ + 1 | if (a && b) foo();␊ + ␊ + Error 1/1:␊ + > 1 | if (a) if (b) foo();␊ + | ^^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + ` + +## no-lonely-if - #5 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) if (b);␊ + ␊ + Output:␊ + 1 | if (a && b) ;␊ + ␊ + Error 1/1:␊ + > 1 | if (a) if (b);␊ + | ^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + ` + +## no-lonely-if - #6 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) {␊ + 2 | if (b) {␊ + 3 | // Should not report␊ + 4 | }␊ + 5 | } else if (c) {␊ + 6 | if (d) {␊ + 7 | }␊ + 8 | }␊ + ␊ + Output:␊ + 1 | if (a) {␊ + 2 | if (b) {␊ + 3 | // Should not report␊ + 4 | }␊ + 5 | } else if (c && d) {␊ + 6 | }␊ + ␊ + Error 1/1:␊ + 1 | if (a) {␊ + 2 | if (b) {␊ + 3 | // Should not report␊ + 4 | }␊ + 5 | } else if (c) {␊ + > 6 | if (d) {␊ + | ^^^^^^^^␊ + > 7 | }␊ + | ^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 8 | }␊ + ` + +## no-lonely-if - #7 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + 6 | if (a += b)␊ + 7 | if (a -= b)␊ + 8 | if (a &&= b)␊ + 9 | if (yield a)␊ + 10 | if (a, b);␊ + 11 | }␊ + ␊ + Output:␊ + 1 | function * foo() {␊ + 2 | if ((a || b) && (a ?? b) && (a ? b : c) && (a = b) && (a += b) && (a -= b) && (a &&= b) && (yield a) && (a, b))␊ + 3 | ;␊ + 4 | }␊ + ␊ + Error 1/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + > 3 | if (a ?? b)␊ + | ^^^^^^^^^^^␊ + > 4 | if (a ? b : c)␊ + | ^^^^^^^^^^^^^^^␊ + > 5 | if (a = b)␊ + | ^^^^^^^^^^^^^^^␊ + > 6 | if (a += b)␊ + | ^^^^^^^^^^^^^^^␊ + > 7 | if (a -= b)␊ + | ^^^^^^^^^^^^^^^␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 2/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + > 4 | if (a ? b : c)␊ + | ^^^^^^^^^^^^^^␊ + > 5 | if (a = b)␊ + | ^^^^^^^^^^^␊ + > 6 | if (a += b)␊ + | ^^^^^^^^^^^␊ + > 7 | if (a -= b)␊ + | ^^^^^^^^^^^␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 3/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + > 5 | if (a = b)␊ + | ^^^^^^^^^^␊ + > 6 | if (a += b)␊ + | ^^^^^^^^^^^^␊ + > 7 | if (a -= b)␊ + | ^^^^^^^^^^^^␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 4/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + > 6 | if (a += b)␊ + | ^^^^^^^^^^^␊ + > 7 | if (a -= b)␊ + | ^^^^^^^^^^^^␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 5/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + 6 | if (a += b)␊ + > 7 | if (a -= b)␊ + | ^^^^^^^^^^^␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 6/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + 6 | if (a += b)␊ + 7 | if (a -= b)␊ + > 8 | if (a &&= b)␊ + | ^^^^^^^^^^^^␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 7/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + 6 | if (a += b)␊ + 7 | if (a -= b)␊ + 8 | if (a &&= b)␊ + > 9 | if (yield a)␊ + | ^^^^^^^^^^^^␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + Error 8/8:␊ + 1 | function * foo() {␊ + 2 | if (a || b)␊ + 3 | if (a ?? b)␊ + 4 | if (a ? b : c)␊ + 5 | if (a = b)␊ + 6 | if (a += b)␊ + 7 | if (a -= b)␊ + 8 | if (a &&= b)␊ + 9 | if (yield a)␊ + > 10 | if (a, b);␊ + | ^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 11 | }␊ + ` + +## no-lonely-if - #8 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | async function foo() {␊ + 2 | if (a)␊ + 3 | if (await a)␊ + 4 | if (a.b)␊ + 5 | if (a && b);␊ + 6 | }␊ + ␊ + Output:␊ + 1 | async function foo() {␊ + 2 | if (a && await a && a.b && a && b)␊ + 3 | ;␊ + 4 | }␊ + ␊ + Error 1/3:␊ + 1 | async function foo() {␊ + 2 | if (a)␊ + > 3 | if (await a)␊ + | ^^^^^^^^^^^^␊ + > 4 | if (a.b)␊ + | ^^^^^^^^^␊ + > 5 | if (a && b);␊ + | ^^^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 6 | }␊ + Error 2/3:␊ + 1 | async function foo() {␊ + 2 | if (a)␊ + 3 | if (await a)␊ + > 4 | if (a.b)␊ + | ^^^^^^^^␊ + > 5 | if (a && b);␊ + | ^^^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 6 | }␊ + Error 3/3:␊ + 1 | async function foo() {␊ + 2 | if (a)␊ + 3 | if (await a)␊ + 4 | if (a.b)␊ + > 5 | if (a && b);␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 6 | }␊ + ` + +## no-lonely-if - #9 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (((a || b))) if (((c || d)));␊ + ␊ + Output:␊ + 1 | if ((((a || b) && (c || d)))) ;␊ + ␊ + Error 1/1:␊ + > 1 | if (((a || b))) if (((c || d)));␊ + | ^^^^^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + ` + +## no-lonely-if - #10 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if /* will keep */␊ + 2 | (␊ + 3 | /* will keep */␊ + 4 | a /* will keep */␊ + 5 | .b /* will keep */␊ + 6 | ) /* keep */{␊ + 7 | /* will remove */␊ + 8 | if (␊ + 9 | /* will remove */␊ + 10 | c /* will keep */␊ + 11 | .d /* will remove */␊ + 12 | ) {␊ + 13 | /* will keep */␊ + 14 | foo();␊ + 15 | /* will keep */␊ + 16 | }␊ + 17 | /* will remove */␊ + 18 | }␊ + ␊ + Output:␊ + 1 | if /* will keep */␊ + 2 | (␊ + 3 | /* will keep */␊ + 4 | a /* will keep */␊ + 5 | .b && c /* will keep */␊ + 6 | .d /* will keep */␊ + 7 | ) /* keep */{␊ + 8 | /* will keep */␊ + 9 | foo();␊ + 10 | /* will keep */␊ + 11 | }␊ + ␊ + Error 1/1:␊ + 1 | if /* will keep */␊ + 2 | (␊ + 3 | /* will keep */␊ + 4 | a /* will keep */␊ + 5 | .b /* will keep */␊ + 6 | ) /* keep */{␊ + 7 | /* will remove */␊ + > 8 | if (␊ + | ^^^^␊ + > 9 | /* will remove */␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 10 | c /* will keep */␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 11 | .d /* will remove */␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 12 | ) {␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 13 | /* will keep */␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 14 | foo();␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 15 | /* will keep */␊ + | ^^^^^^^^^^^^^^^^^^^␊ + > 16 | }␊ + | ^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 17 | /* will remove */␊ + 18 | }␊ + ` + +## no-lonely-if - #11 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a) {␊ + 2 | if (b) foo()␊ + 3 | }␊ + 4 | [].forEach(bar)␊ + ␊ + Output:␊ + 1 | if (a && b) foo();␊ + 2 | [].forEach(bar)␊ + ␊ + Error 1/1:␊ + 1 | if (a) {␊ + > 2 | if (b) foo()␊ + | ^^^^^^^^^^^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + 3 | }␊ + 4 | [].forEach(bar)␊ + ` + +## no-lonely-if - #12 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | if (a)␊ + 2 | if (b) foo()␊ + 3 | ;[].forEach(bar)␊ + ␊ + Output:␊ + 1 | if (a && b)␊ + 2 | foo()␊ + 3 | ;[].forEach(bar)␊ + ␊ + Error 1/1:␊ + 1 | if (a)␊ + > 2 | if (b) foo()␊ + | ^^^^^^^^^^^^␊ + > 3 | ;[].forEach(bar)␊ + | ^^ Unexpected `if` as the only statement in a `if` block without `else`.␊ + ` diff --git a/test/snapshots/no-lonely-if.js.snap b/test/snapshots/no-lonely-if.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..b95c2cff4758816131e34ee9af81b367eba2663b GIT binary patch literal 1467 zcmV;s1w{HmRzVz1gtYVdJ;E@gIu_00000000B! zSzTxxRTRF{klI;lijiVdsoWyO-Nfv6vdLym%m#%#sHhJ?qzw(3-JNBZY<9wCVoZ}D z7U_dVB|aGt5ky3#)}Iiig~k*@Q`#bxQ0fmALLcgzf`XA!oVoL}^KWYio!@+CXYzy9TtYfl{-akls-J`E*CVBsu9FY^wQud}Cx72q zZ~TlS)}|c@b^J2<#iy5!{CY9+_Wb?w$8nBWKdeXSnVSzSHVl3<_WkF3SNpD>-r$J! zr=19i7j`8E7CLV{@#DGG{>`ILbHuu57ecwE^S7enmoFaw`bxav=A6h8>n$FkGbh5w z<~rYMIk5NV{Kn*g0!OUZLI^F7ZZ>>$`P}=V;o57b7k;?3czpIex7a>%h9lNj_an5ivKG63a_Px@(|gVNE6<+g zi1qac5xV{E;J54hAD{dEyYg2@-Z=FzN36>jp*nOAVT!9q_w8upLQj>(CY0_F#sZ$f zg&Yox5%QIe;Az#`u3Gt=EQcdKYAdd`W<#OpClq%l+}w;=UHZ#qxr~LF&>c!qroyV# z_zW2z)z>+i=2Lm5k8N7<3nl60F)5=+Sv*|G4P$W}D|rdarQ#GGS42e`l}ZXOl(48j zPZ#CP2%an`d3i#?!%}fv8jgk>1pS6Uf-IQE^8FKJc-r}Jjhuo<)-duz_D?`~%|$zK zPuDqdi{n$J49-oIGD<-%>8o~)z6L97Ovzugx%p2tgt$*I_UN)K|^A~0Qv0! zFdhIvceK(0@ioNb$iy&QqQMGe<+6@r@MttAm;1#`KAaZI5g%nqAJfyXs$x}Bf>`hz zv^9gYF-Yt2&z574qjsl|=9e;~>UhSjd|ct9Pln8hVo!DVSoE-Pjd z%^J0S7Hd>LLe*YPgM+Tg&pc5ek6S(CLFwAgk7`$1x6Mo(E|!`fMI-OwgLnhd zQ9L0EBW=qLWYzOk8^Bjw4_nq!;Ai8V25{)6ES)97r-#Si{cNM1?;*?GwUpw|3*SaOv zm6dr}z2iLo(pHR#F|bjbG_@0g}Sa-i`utX#3Pb4hFfB0kqBFr z0dOGIL4>-J0>MYq&@-)4M6?HnZQ3dorgK>um0yw!cdKAng#z@`%LShSW+d6otINq^ zuqTm5S4D_BCa{e`uvY#X6gp{+2~$Xcib?Rid#tevYN$fQ=tbK>jO}3;q*Iat+fb&$ z&mkH=0+cM