factory CallChainVisitor()

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);
  }