I’m trying to find if there is a non-plugin eslint rule that would allow any of the following:
function(x) { let count = 0; if (doIncrement(x)) count++ else (doDecrement(x)) count-- if (count >=10) return "over nine"; else return "keep counting"; }
But only error on this:
let listOfThings = []; if (treatAsString) listOfThings[0] = myString.trim(); else listOfThings = [...myString.split(',').map(stringPart => stringPart.trim())]; // or let name = ''; if (hasFirstAndLAstName) name = `${firstName} ${lastName}`; else name = `${emailAddress}`;
In favour of using ternary assignment like so:
const listOfThings = treatAsString ? [myString.trim()] : [...myString.split(',').map(stringPart => stringPart.trim())]; // or let name = hasFirstAndLAstName ? `${firstName} ${lastName}` : emailAddress;
Does that rule (or a combination of rules) exist for eslint without involving a plug-in?
Advertisement
Answer
With using only base ESLint, you could try the no-restricted-syntax
rule. It is not specific but can disallow any syntax you want.
To figure out how you want to configure this rule, check:
- place your code in a tool that can generate the abstract syntax tree (AST) which will tell you what you want to forbid. The one I used is https://astexplorer.net/
- the ESLint guide on selectors which outlines how AST selectors can be used and combined. They are very similar to CSS selectors but target programming code.
With these two, here is what I came up with. This is just an example, you might want to adjust the rule further:
no-restricted-syntax: ["error", "IfStatement > ExpressionStatement > AssignmentExpression"]
This will forbid assignments in single-line if
statements (and in else
). Note that it does not apply for blocks.
Allowed
let x; if (Math.random() > 0.5) { x = 4; } else { x = 2; }
Disallowed:
let x; if (Math.random() > 0.5) x = 4; else x = 2;
For reference, the selector for if statements with a block body that contains an assignment would be IfStatement > BlockStatement > ExpressionStatement > AssignmentExpression
This will only disallow assignments not variable declarations. A construct like const x = 42;
falls under VariableDeclaration
in AST, so AssignmentExpression
is separate and only apply when a variable is already declared.
Try the online ESLint demo with:
/* eslint no-restricted-syntax: ["error", "IfStatement > ExpressionStatement > AssignmentExpression"] */ // allowed function foo(x) { let count = 0; if (doIncrement(x)) count++ else if (doDecrement(x)) count-- if (count >=10) return "over nine"; else return "keep counting"; } // allowed function foo() { const listOfThings = treatAsString ? [myString.trim()] : [...myString.split(',').map(stringPart => stringPart.trim())]; } // allowed function foo() { let name = hasFirstAndLAstName ? `${firstName} ${lastName}` : emailAddress; } // allowed - assignment is not in `if` function foo() { let x = 1; x = 2; } // allowed - if statement with blocks function foo() { let x; if (Math.random() > 0.5) { x = 4; } else { x = 2; } } // disallowed function foo() { let listOfThings = []; if (treatAsString) listOfThings[0] = myString.trim(); else listOfThings = [...myString.split(',').map(stringPart => stringPart.trim())]; } // disallowed function foo() { let name = ''; if (hasFirstAndLAstName) name = `${firstName} ${lastName}`; else name = `${emailAddress}`; } // disallowed - single line `if` (even though there is no `else`) function foo() { let x = 1; if (Math.random() > 0.5) x = 2; }
Direct link to online ESLint demo
As I said, this is just to showcase the functionality. It does not encourage you into using conditional statements (the error message just amounts to “don’t use this”) and might also not cover everything you want (e.g., assignment in if
which is inside another if
). But it is a start.
Still, you might want to look at making a custom plugin that more accurately checks for what you want and reports better errors. The no-restricted-syntax
rule is probably too generic for most use cases.