Skip to content

Commit

Permalink
prefer-ternary: Add only-single-line option (#1025)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Elliot <elliot@maisl.fr>
  • Loading branch information
3 people committed Jan 19, 2021
1 parent 88018ca commit 306c9e7
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 1 deletion.
23 changes: 23 additions & 0 deletions docs/rules/prefer-ternary.md
Expand Up @@ -120,3 +120,26 @@ if (test) {
baz = 2;
}
```

## Options

Type: `string`\
Default: `'always'`

- `'always'` (default)
- Always report when using an `IfStatement` where a ternary expression can be used.
- `'only-single-line'`
- Only check if the content of the `if` and/or `else` block is less than one line long.

The following case is considered valid:

```js
// eslint unicorn/prefer-ternary: ["error", "only-single-line"]
if (test) {
foo = [
'multiple line array'
];
} else {
bar = baz;
}
```
22 changes: 21 additions & 1 deletion rules/prefer-ternary.js
Expand Up @@ -56,6 +56,7 @@ const getScopes = scope => [
];

const create = context => {
const onlySingleLine = context.options[0] === 'only-single-line';
const sourceCode = context.getSourceCode();
const scopeToNamesGeneratedByFixer = new WeakMap();
const isSafeName = (name, scopes) => scopes.every(scope => {
Expand All @@ -76,6 +77,11 @@ const create = context => {
`(${text})` : text;
};

const isSingleLineNode = node => {
const [start, end] = node.range.map(index => sourceCode.getLocFromIndex(index));
return start.line === end.line;
};

function merge(options, mergeOptions) {
const {
before = '',
Expand Down Expand Up @@ -189,6 +195,13 @@ const create = context => {
const consequent = getNodeBody(node.consequent);
const alternate = getNodeBody(node.alternate);

if (
onlySingleLine &&
[consequent, alternate, node.test].some(node => !isSingleLineNode(node))
) {
return;
}

const result = merge({node, consequent, alternate}, {
checkThrowStatement: true,
returnFalseIfNotMergeable: true
Expand All @@ -199,7 +212,6 @@ const create = context => {
}

const scope = context.getScope();
const sourceCode = context.getSourceCode();

context.report({
node,
Expand Down Expand Up @@ -252,6 +264,13 @@ const create = context => {
};
};

const schema = [
{
enum: ['always', 'only-single-line'],
default: 'always'
}
];

module.exports = {
create,
meta: {
Expand All @@ -262,6 +281,7 @@ module.exports = {
messages: {
[messageId]: 'This `if` statement can be replaced by a ternary expression.'
},
schema,
fixable: 'code'
}
};
130 changes: 130 additions & 0 deletions test/prefer-ternary.js
Expand Up @@ -4,6 +4,8 @@ import {test} from './utils/test.js';
const messageId = 'prefer-ternary';
const errors = [{messageId}];

const onlySingleLineOptions = ['only-single-line'];

// ReturnStatement
test({
valid: [
Expand Down Expand Up @@ -957,6 +959,134 @@ test({
]
});

// `only-single-line`
test({
valid: [
{
code: outdent`
if (test) {
a = {
multiline: 'in consequent'
};
} else{
a = foo;
}
`,
options: onlySingleLineOptions
},
{
code: outdent`
if (test) {
a = foo;
} else{
a = {
multiline: 'in alternate'
};
}
`,
options: onlySingleLineOptions
},
{
code: outdent`
if (
test({
multiline: 'in test'
})
) {
a = foo;
} else{
a = bar;
}
`,
options: onlySingleLineOptions
},
{
code: outdent`
if (test) {
a = foo; b = 1;
} else{
a = bar;
}
`,
options: onlySingleLineOptions
}
],
invalid: [
{
code: outdent`
if (test) {
a = foo;
} else {
a = bar;
}
`,
output: 'a = test ? foo : bar;',
options: onlySingleLineOptions,
errors
},
// Parentheses are not considered part of `Node`
{
code: outdent`
if (
(
test
)
) {
a = foo;
} else {
a = bar;
}
`,
output: 'a = (test) ? foo : bar;',
options: onlySingleLineOptions,
errors
},
{
code: outdent`
if (test) {
(
a = foo
);
} else {
a = bar;
}
`,
output: 'a = test ? foo : bar;',
options: onlySingleLineOptions,
errors
},
// Semicolon of `ExpressionStatement` is not considered part of `Node`
{
code: outdent`
if (test) {
a = foo
;
} else {
a = bar;
}
`,
output: 'a = test ? foo : bar;',
options: onlySingleLineOptions,
errors
},
// `EmptyStatement`s are excluded
{
code: outdent`
if (test) {
;;;;;;
a = foo;
;;;;;;
} else {
a = bar;
}
`,
output: 'a = test ? foo : bar;',
options: onlySingleLineOptions,
errors
}
]
});

test({
valid: [
// No `consequent` / `alternate`
Expand Down

0 comments on commit 306c9e7

Please sign in to comment.