content: // Copyright 2018 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/nullable.dart';
  import 'interface/statement.dart';
  
  /// A visitor that recursively traverses each statement in a Sass AST.
  ///
  /// In addition to the methods from [StatementVisitor], this has more general
  /// protected methods that can be overridden to add behavior for a wide variety
  /// of AST nodes:
  ///
  /// * [visitCallableDeclaration]
  /// * [visitChildren]
  ///
  /// {@category Visitor}
  mixin RecursiveStatementVisitor implements StatementVisitor<void> {
    void visitAtRootRule(AtRootRule node) {
      visitChildren(node.children);
    }
  
    void visitAtRule(AtRule node) => node.children.andThen(visitChildren);
  
    void visitContentBlock(ContentBlock node) => visitCallableDeclaration(node);
  
    void visitContentRule(ContentRule node) {}
  
    void visitDebugRule(DebugRule node) {}
  
    void visitDeclaration(Declaration node) =>
        node.children.andThen(visitChildren);
  
    void visitEachRule(EachRule node) => visitChildren(node.children);
  
    void visitErrorRule(ErrorRule node) {}
  
    void visitExtendRule(ExtendRule node) {}
  
    void visitForRule(ForRule node) => visitChildren(node.children);
  
    void visitForwardRule(ForwardRule node) {}
  
    void visitFunctionRule(FunctionRule node) => visitCallableDeclaration(node);
  
    void visitIfRule(IfRule node) {
      for (var clause in node.clauses) {
        for (var child in clause.children) {
          child.accept(this);
        }
      }
  
      if (node.lastClause case var lastClause?) {
        for (var child in lastClause.children) {
          child.accept(this);
        }
      }
    }
  
    void visitImportRule(ImportRule node) {}
  
    void visitIncludeRule(IncludeRule node) =>
        node.content.andThen(visitContentBlock);
  
    void visitLoudComment(LoudComment node) {}
  
    void visitMediaRule(MediaRule node) => visitChildren(node.children);
  
    void visitMixinRule(MixinRule node) => visitCallableDeclaration(node);
  
    void visitReturnRule(ReturnRule node) {}
  
    void visitSilentComment(SilentComment node) {}
  
    void visitStyleRule(StyleRule node) => visitChildren(node.children);
  
    void visitStylesheet(Stylesheet node) => visitChildren(node.children);
  
    void visitSupportsRule(SupportsRule node) => visitChildren(node.children);
  
    void visitUseRule(UseRule node) {}
  
    void visitVariableDeclaration(VariableDeclaration node) {}
  
    void visitWarnRule(WarnRule node) {}
  
    void visitWhileRule(WhileRule node) => visitChildren(node.children);
  
    /// Visits each of [node]'s children.
    ///
    /// The default implementations of [visitFunctionRule] and [visitMixinRule]
    /// call this.
    @protected
    void 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
    void visitChildren(List<Statement> children) {
      for (var child in children) {
        child.accept(this);
      }
    }
  }
  