content: // Copyright 2016 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:source_span/source_span.dart';
  
  import '../../../util/span.dart';
  import '../../../visitor/interface/statement.dart';
  import '../../../visitor/statement_search.dart';
  import '../declaration.dart';
  import 'callable_declaration.dart';
  import 'content_rule.dart';
  
  /// A mixin declaration.
  ///
  /// This declares a mixin that's invoked using `@include`.
  ///
  /// {@category AST}
  final class MixinRule extends CallableDeclaration implements SassDeclaration {
    /// Whether the mixin contains a `@content` rule.
    late final bool hasContent =
        const _HasContentVisitor().visitMixinRule(this) == true;
  
    FileSpan get nameSpan {
      var startSpan = span.text.startsWith('=')
          ? span.subspan(1).trimLeft()
          : span.withoutInitialAtRule();
      return startSpan.initialIdentifier();
    }
  
    MixinRule(
      super.name,
      super.parameters,
      super.children,
      super.span, {
      super.comment,
    });
  
    T accept<T>(StatementVisitor<T> visitor) => visitor.visitMixinRule(this);
  
    String toString() {
      var buffer = StringBuffer("@mixin $name");
      if (!parameters.isEmpty) buffer.write("($parameters)");
      buffer.write(" {${children.join(' ')}}");
      return buffer.toString();
    }
  }
  
  /// A visitor for determining whether a [MixinRule] recursively contains a
  /// [ContentRule].
  class _HasContentVisitor with StatementSearchVisitor<bool> {
    const _HasContentVisitor();
  
    bool visitContentRule(_) => true;
  }
  