content: // Copyright 2021 Google Inc. Use of this source code is governed by an
  // MIT-style license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT.
  
  import 'package:meta/meta.dart';
  
  import '../ast/sass.dart';
  import '../util/iterable.dart';
  import '../util/nullable.dart';
  import 'interface/statement.dart';
  import 'recursive_statement.dart';
  
  /// A [StatementVisitor] whose `visit*` methods default to returning `null`, but
  /// which returns the first non-`null` value returned by any method.
  ///
  /// This can be extended to find the first instance of particular nodes in the
  /// AST.
  ///
  /// This supports the same additional methods as [RecursiveStatementVisitor].
  ///
  /// {@category Visitor}
  mixin StatementSearchVisitor<T> implements StatementVisitor<T?> {
    T? visitAtRootRule(AtRootRule node) => visitChildren(node.children);
  
    T? visitAtRule(AtRule node) => node.children.andThen(visitChildren);
  
    T? visitContentBlock(ContentBlock node) => visitCallableDeclaration(node);
  
    T? visitContentRule(ContentRule node) => null;
  
    T? visitDebugRule(DebugRule node) => null;
  
    T? visitDeclaration(Declaration node) => node.children.andThen(visitChildren);
  
    T? visitEachRule(EachRule node) => visitChildren(node.children);
  
    T? visitErrorRule(ErrorRule node) => null;
  
    T? visitExtendRule(ExtendRule node) => null;
  
    T? visitForRule(ForRule node) => visitChildren(node.children);
  
    T? visitForwardRule(ForwardRule node) => null;
  
    T? visitFunctionRule(FunctionRule node) => visitCallableDeclaration(node);
  
    T? visitIfRule(IfRule node) =>
        node.clauses.search(
          (clause) => clause.children.search((child) => child.accept(this)),
        ) ??
        node.lastClause.andThen(
          (lastClause) =>
              lastClause.children.search((child) => child.accept(this)),
        );
  
    T? visitImportRule(ImportRule node) => null;
  
    T? visitIncludeRule(IncludeRule node) =>
        node.content.andThen(visitContentBlock);
  
    T? visitLoudComment(LoudComment node) => null;
  
    T? visitMediaRule(MediaRule node) => visitChildren(node.children);
  
    T? visitMixinRule(MixinRule node) => visitCallableDeclaration(node);
  
    T? visitReturnRule(ReturnRule node) => null;
  
    T? visitSilentComment(SilentComment node) => null;
  
    T? visitStyleRule(StyleRule node) => visitChildren(node.children);
  
    T? visitStylesheet(Stylesheet node) => visitChildren(node.children);
  
    T? visitSupportsRule(SupportsRule node) => visitChildren(node.children);
  
    T? visitUseRule(UseRule node) => null;
  
    T? visitVariableDeclaration(VariableDeclaration node) => null;
  
    T? visitWarnRule(WarnRule node) => null;
  
    T? visitWhileRule(WhileRule node) => visitChildren(node.children);
  
    /// Visits each of [node]'s expressions and children.
    ///
    /// The default implementations of [visitFunctionRule] and [visitMixinRule]
    /// call this.
    @protected
    T? visitCallableDeclaration(CallableDeclaration node) =>
        visitChildren(node.children);
  
    /// Visits each child in [children].
    ///
    /// The default implementation of the visit methods for all [ParentStatement]s
    /// call this.
    @protected
    T? visitChildren(List<Statement> children) =>
        children.search((child) => child.accept(this));
  }
  