in lib/src/source_visitor.dart [1898:2021]
void visitIfElement(IfElement node) {
// Treat a chain of if-else elements as a single unit so that we don't
// unnecessarily indent each subsequent section of the chain.
var ifElements = [
for (CollectionElement? thisNode = node;
thisNode is IfElement;
thisNode = thisNode.elseElement)
thisNode
];
// If the body of the then or else branch is a spread of a collection
// literal, then we want to format those collections more like blocks than
// like standalone objects. In particular, if both the then and else branch
// are spread collection literals, we want to ensure that they both split
// if either splits. So this:
//
// [
// if (condition) ...[
// thenClause
// ] else ...[
// elseClause
// ]
// ]
//
// And not something like this:
//
// [
// if (condition) ...[
// thenClause
// ] else ...[elseClause]
// ]
//
// To do that, if we see that either clause is a spread collection, we
// create a single rule and force both collections to use it.
var spreadRule = Rule();
var spreadBrackets = <CollectionElement, Token>{};
for (var element in ifElements) {
var spreadBracket = _findSpreadCollectionBracket(element.thenElement);
if (spreadBracket != null) {
spreadBrackets[element] = spreadBracket;
beforeBlock(spreadBracket, spreadRule, null);
}
}
var elseSpreadBracket =
_findSpreadCollectionBracket(ifElements.last.elseElement);
if (elseSpreadBracket != null) {
spreadBrackets[ifElements.last.elseElement!] = elseSpreadBracket;
beforeBlock(elseSpreadBracket, spreadRule, null);
}
void visitChild(CollectionElement element, CollectionElement child) {
builder.nestExpression(indent: 2, now: true);
// Treat a spread of a collection literal like a block in an if statement
// and don't split after the "else".
var isSpread = spreadBrackets.containsKey(element);
if (isSpread) {
space();
} else {
split();
// If the then clause is a non-spread collection or lambda, make sure the
// body is indented.
builder.startBlockArgumentNesting();
}
visit(child);
if (!isSpread) builder.endBlockArgumentNesting();
builder.unnest();
}
// Wrap the whole thing in a single rule. If a split happens inside the
// condition or the then clause, we want the then and else clauses to split.
builder.startLazyRule();
var hasInnerControlFlow = false;
for (var element in ifElements) {
// The condition.
token(element.ifKeyword);
space();
token(element.leftParenthesis);
visit(element.condition);
token(element.rightParenthesis);
visitChild(element, element.thenElement);
if (_isControlFlowElement(element.thenElement)) {
hasInnerControlFlow = true;
}
// Handle this element's "else" keyword and prepare to write the element,
// but don't write it. It will either be the next element in [ifElements]
// or the final else element handled after the loop.
if (element.elseElement != null) {
if (spreadBrackets.containsKey(element)) {
space();
} else {
split();
}
token(element.elseKeyword);
// If there is another if element in the chain, put a space between
// it and this "else".
if (element != ifElements.last) space();
}
}
// Handle the final trailing else if there is one.
var lastElse = ifElements.last.elseElement;
if (lastElse != null) {
visitChild(lastElse, lastElse);
if (_isControlFlowElement(lastElse)) {
hasInnerControlFlow = true;
}
}
// If a control flow element is nested inside another, force the outer one
// to split.
if (hasInnerControlFlow) builder.forceRules();
builder.endRule();
}