in lib/src/call_chain_visitor.dart [114:170]
factory CallChainVisitor(SourceVisitor visitor, Expression node) {
// Flatten the call chain tree to a list of selectors with postfix
// expressions.
var calls = <_Selector>[];
var target = _unwrapTarget(node, calls);
// An expression that starts with a series of dotted names gets treated a
// little specially. We don't force leading properties to split with the
// rest of the chain. Allows code like:
//
// address.street.number
// .toString()
// .length;
var properties = <_Selector>[];
if (_unwrapNullAssertion(target) is SimpleIdentifier) {
properties = calls.takeWhile((call) => call.isProperty).toList();
}
calls.removeRange(0, properties.length);
// Separate out the block calls, if there are any.
List<_MethodSelector>? blockCalls;
_Selector? hangingCall;
var inBlockCalls = false;
for (var call in calls) {
if (call.isBlockCall(visitor)) {
inBlockCalls = true;
blockCalls ??= [];
blockCalls.add(call as _MethodSelector);
} else if (inBlockCalls) {
// We found a non-block call after a block call.
if (call == calls.last) {
// It's the one allowed hanging one, so it's OK.
hangingCall = call;
break;
}
// Don't allow any of the calls to be block formatted.
blockCalls = null;
break;
}
}
if (blockCalls != null) {
for (var blockCall in blockCalls) {
calls.remove(blockCall);
}
}
if (hangingCall != null) {
calls.remove(hangingCall);
}
return CallChainVisitor._(
visitor, target, properties, calls, blockCalls, hangingCall);
}