avoid-nested-conditional-expressions
Same as avoid-nested-conditional-expressions in Dart Code Metrics
- Group
- Complexity
- Path
lint/complexity/avoid-nested-conditional-expressions- Default
- Off, opt in
- Origin
- Dart Code Metrics
- Rule
- 98 of 512
Flags a ternary conditional expression nested inside another ternary.
Stacked conditionals like a ? b : c ? d : e are hard to read and easy to
misparse; an if/else chain, a switch expression, or an extracted
variable makes the branching explicit. The rule reports any conditional
expression that has another conditional as an ancestor (nesting level two or
deeper), matching dart_code_linter's default acceptable level of one.
Closure bodies restart the nesting count.
Invalid
// Each conditional nested inside another conditional is flagged (the inner
// conditional, matching dart_code_linter's nesting-level reporting).
void doubleNesting() {
final x = a ? (b ? c : d) : e;
final y = condition ? (isValid ? "yes" : "no") : "default";
final z = (first ? (second ? 1 : 2) : 3) + 4;
}
// Triple nesting flags both inner conditionals (nesting levels 2 and 3).
String getStatus() {
return active ? (verified ? (premium ? "premium" : "standard") : "unverified") : "inactive";
}
class StatusHelper {
String describe(bool a, bool b, bool c) {
return a ? (b ? (c ? "all" : "a,b") : "a") : "none";
}
}
int calculate(bool x, bool y) {
return x ? (y ? (100) : (50)) : (0);
}
List<String> getItems(bool filter) {
return filter ? (items.isNotEmpty ? (items.toList()) : []) : items;
}
// Regression: the violation must still be found inside Dart 3 containers
// (pattern declaration, labeled statement, switch expression and subject,
// collection if/spread, record field).
void containersRegression(int rcount) {
final (ra, _) = ((rcount > 0 ? (rcount > 1 ? 1 : 2) : 3), 0);
lbl: {
final rb = (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3);
print(rb);
}
final rc = switch (rcount) {
0 => (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3),
_ => null,
};
final rd = switch ((rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)) {
_ => 0,
};
final re = [if (rcount > 0) (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)];
final rf = [...[(rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)]];
final rg = (p: (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3), q: 0);
print([ra, rc, rd, re, rf, rg]);
}void doubleNesting() { final x = a ? (b ? c : d) : e; final x = a ? (b ? c : d) : e; final y = condition ? (isValid ? "yes" : "no") : "default"; final y = condition ? (isValid ? "yes" : "no") : "default"; final z = (first ? (second ? 1 : 2) : 3) + 4;String getStatus() { return active ? (verified ? (premium ? "premium" : "standard") : "unverified") : "inactive";String getStatus() { return active ? (verified ? (premium ? "premium" : "standard") : "unverified") : "inactive"; String describe(bool a, bool b, bool c) { return a ? (b ? (c ? "all" : "a,b") : "a") : "none"; String describe(bool a, bool b, bool c) { return a ? (b ? (c ? "all" : "a,b") : "a") : "none";int calculate(bool x, bool y) { return x ? (y ? (100) : (50)) : (0);List<String> getItems(bool filter) { return filter ? (items.isNotEmpty ? (items.toList()) : []) : items;void containersRegression(int rcount) { final (ra, _) = ((rcount > 0 ? (rcount > 1 ? 1 : 2) : 3), 0); lbl: { final rb = (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3); final rc = switch (rcount) { 0 => (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3), }; final rd = switch ((rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)) { }; final re = [if (rcount > 0) (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)]; final re = [if (rcount > 0) (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)]; final rf = [...[(rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)]]; final rf = [...[(rcount > 0 ? (rcount > 1 ? 1 : 2) : 3)]]; final rg = (p: (rcount > 0 ? (rcount > 1 ? 1 : 2) : 3), q: 0);Valid
// Good cases for avoid-nested-conditional-expressions rule
// No violations expected
void testSingleLevelTernary() {
final x = a ? b : c;
final y = condition ? "yes" : "no";
final z = isValid ? 10 : 20;
}
String getStatus() {
if (!active) return "inactive";
if (!verified) return "unverified";
return premium ? "premium" : "standard";
}
class StatusHelper {
String describe(bool a, bool b, bool c) {
if (!a) return "none";
if (!b) return "a";
return c ? "all" : "a,b";
}
}
int calculate(bool x, bool y) {
if (!x) return 0;
return y ? 100 : 50;
}
void cleanNesting() {
if (!condition1) {
return "none";
}
if (!condition2) {
return "shallow";
}
return condition3 ? "deep" : "mid";
}
List<String> getItems(bool filter) {
if (!filter) return items;
return items.isNotEmpty ? items : [];
}
void mixedApproach(bool condition) {
final result = condition ? "active" : "inactive";
print(result);
}
bool isEligible(bool verified, bool premium) {
return verified && premium;
}
// A ternary inside a closure body is read on its own, so it is not "nested"
// in the ternary the closure sits in.
List<int> closureInsideConditional(bool flag, List<int> items) {
return flag ? items.map((x) => x > 0 ? 1 : 0).toList() : const [];
}Configure avoid-nested-conditional-expressions
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"complexity": {
"avoid-nested-conditional-expressions": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/complexity/avoid-nested-conditional-expressions: <reason>More complexity rules
- avoid-nested-if
avoid_nested_ifFlags an
ifstatement whose then-branch contains nestedifstatements. - avoid-nested-switch-expressions
Reports deeply nested switch expressions.
- avoid-nested-switches
Reports deeply nested switch statements.
- avoid-nested-try-statements
Reports deeply nested try statements.
- avoid-redundant-async
avoid-redundant-asyncrecommendedFlags an
asyncfunction whose body is a singlereturn await ...;. - avoid-unnecessary-containers
avoid_unnecessary_containersrecommendedflutterFlags a
Containerwhose only argument is achild. - avoid-unnecessary-type-assertions
avoid-unnecessary-type-assertionsrecommendedFlags an
ischeck whose result is already guaranteed by the resolved static type. - avoid-unnecessary-type-casts
avoid-unnecessary-type-castsrecommendedFlags an
ascast to the operand's resolved static type.