From 98f326b5072693099e6b7a4e5bfe7dbdb81f1158 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Fri, 19 Aug 2022 15:17:58 -0700 Subject: [PATCH] Convert visitor classes to mixins (#1784) Co-authored-by: Jennifer Thakar --- lib/src/ast/css/node.dart | 2 +- lib/src/ast/sass/statement/mixin_rule.dart | 2 +- lib/src/ast/selector.dart | 6 +++--- lib/src/visitor/any_selector.dart | 4 +--- lib/src/visitor/every_css.dart | 4 +--- lib/src/visitor/find_dependencies.dart | 2 +- lib/src/visitor/recursive_ast.dart | 4 +--- lib/src/visitor/recursive_selector.dart | 4 +--- lib/src/visitor/recursive_statement.dart | 4 +--- lib/src/visitor/statement_search.dart | 4 +--- pkg/sass_api/CHANGELOG.md | 20 ++++++++++++++++++-- test/dart_api/visitor_test.dart | 14 -------------- 12 files changed, 30 insertions(+), 40 deletions(-) delete mode 100644 test/dart_api/visitor_test.dart diff --git a/lib/src/ast/css/node.dart b/lib/src/ast/css/node.dart index a69b529fd..0ca31890c 100644 --- a/lib/src/ast/css/node.dart +++ b/lib/src/ast/css/node.dart @@ -62,7 +62,7 @@ abstract class CssParentNode extends CssNode { } /// The visitor used to implement [CssNode.isInvisible] -class _IsInvisibleVisitor extends EveryCssVisitor { +class _IsInvisibleVisitor with EveryCssVisitor { /// Whether to consider selectors with bogus combinators invisible. final bool includeBogus; diff --git a/lib/src/ast/sass/statement/mixin_rule.dart b/lib/src/ast/sass/statement/mixin_rule.dart index bd323f196..20e2ac254 100644 --- a/lib/src/ast/sass/statement/mixin_rule.dart +++ b/lib/src/ast/sass/statement/mixin_rule.dart @@ -50,7 +50,7 @@ class MixinRule extends CallableDeclaration implements SassDeclaration { /// A visitor for determining whether a [MixinRule] recursively contains a /// [ContentRule]. -class _HasContentVisitor extends StatementSearchVisitor { +class _HasContentVisitor with StatementSearchVisitor { const _HasContentVisitor(); bool visitContentRule(_) => true; diff --git a/lib/src/ast/selector.dart b/lib/src/ast/selector.dart index 6934dab8e..8b694e430 100644 --- a/lib/src/ast/selector.dart +++ b/lib/src/ast/selector.dart @@ -98,7 +98,7 @@ abstract class Selector { } /// The visitor used to implement [Selector.isInvisible]. -class _IsInvisibleVisitor extends AnySelectorVisitor { +class _IsInvisibleVisitor with AnySelectorVisitor { /// Whether to consider selectors with bogus combinators invisible. final bool includeBogus; @@ -128,7 +128,7 @@ class _IsInvisibleVisitor extends AnySelectorVisitor { } /// The visitor used to implement [Selector.isBogus]. -class _IsBogusVisitor extends AnySelectorVisitor { +class _IsBogusVisitor with AnySelectorVisitor { /// Whether to consider selectors with leading combinators as bogus. final bool includeLeadingCombinator; @@ -159,7 +159,7 @@ class _IsBogusVisitor extends AnySelectorVisitor { } /// The visitor used to implement [Selector.isUseless] -class _IsUselessVisitor extends AnySelectorVisitor { +class _IsUselessVisitor with AnySelectorVisitor { const _IsUselessVisitor(); bool visitComplexSelector(ComplexSelector complex) => diff --git a/lib/src/visitor/any_selector.dart b/lib/src/visitor/any_selector.dart index c58c0cc4a..dc6b4591f 100644 --- a/lib/src/visitor/any_selector.dart +++ b/lib/src/visitor/any_selector.dart @@ -12,9 +12,7 @@ import 'interface/selector.dart'; /// /// Each method returns `false` by default. @internal -abstract class AnySelectorVisitor implements SelectorVisitor { - const AnySelectorVisitor(); - +mixin AnySelectorVisitor implements SelectorVisitor { bool visitComplexSelector(ComplexSelector complex) => complex.components .any((component) => visitCompoundSelector(component.selector)); diff --git a/lib/src/visitor/every_css.dart b/lib/src/visitor/every_css.dart index e8d22a548..e2df6862a 100644 --- a/lib/src/visitor/every_css.dart +++ b/lib/src/visitor/every_css.dart @@ -12,9 +12,7 @@ import 'interface/css.dart'; /// /// Each method returns `false` by default. @internal -abstract class EveryCssVisitor implements CssVisitor { - const EveryCssVisitor(); - +mixin EveryCssVisitor implements CssVisitor { bool visitCssAtRule(CssAtRule node) => node.children.every((child) => child.accept(this)); bool visitCssComment(CssComment node) => false; diff --git a/lib/src/visitor/find_dependencies.dart b/lib/src/visitor/find_dependencies.dart index 7048f74ed..362157a0c 100644 --- a/lib/src/visitor/find_dependencies.dart +++ b/lib/src/visitor/find_dependencies.dart @@ -19,7 +19,7 @@ Tuple2, List> findDependencies(Stylesheet stylesheet) => /// A visitor that traverses a stylesheet and records, all `@import`, `@use`, /// and `@forward` rules (excluding built-in modules) it contains. -class _FindDependenciesVisitor extends RecursiveStatementVisitor { +class _FindDependenciesVisitor with RecursiveStatementVisitor { final _usesAndForwards = []; final _imports = []; diff --git a/lib/src/visitor/recursive_ast.dart b/lib/src/visitor/recursive_ast.dart index c4ce85ede..aee77c869 100644 --- a/lib/src/visitor/recursive_ast.dart +++ b/lib/src/visitor/recursive_ast.dart @@ -20,10 +20,8 @@ import 'recursive_statement.dart'; /// * [visitInterpolation] /// /// {@category Visitor} -abstract class RecursiveAstVisitor extends RecursiveStatementVisitor +mixin RecursiveAstVisitor on RecursiveStatementVisitor implements ExpressionVisitor { - const RecursiveAstVisitor(); - void visitAtRootRule(AtRootRule node) { node.query.andThen(visitInterpolation); super.visitAtRootRule(node); diff --git a/lib/src/visitor/recursive_selector.dart b/lib/src/visitor/recursive_selector.dart index b66b8d939..1819c2301 100644 --- a/lib/src/visitor/recursive_selector.dart +++ b/lib/src/visitor/recursive_selector.dart @@ -9,9 +9,7 @@ import 'interface/selector.dart'; /// A visitor that recursively traverses each component of a Selector AST. /// /// {@category Visitor} -abstract class RecursiveSelectorVisitor implements SelectorVisitor { - const RecursiveSelectorVisitor(); - +mixin RecursiveSelectorVisitor implements SelectorVisitor { void visitAttributeSelector(AttributeSelector attribute) {} void visitClassSelector(ClassSelector klass) {} void visitIDSelector(IDSelector id) {} diff --git a/lib/src/visitor/recursive_statement.dart b/lib/src/visitor/recursive_statement.dart index 31714b7f0..408bb5874 100644 --- a/lib/src/visitor/recursive_statement.dart +++ b/lib/src/visitor/recursive_statement.dart @@ -18,9 +18,7 @@ import 'interface/statement.dart'; /// * [visitChildren] /// /// {@category Visitor} -abstract class RecursiveStatementVisitor implements StatementVisitor { - const RecursiveStatementVisitor(); - +mixin RecursiveStatementVisitor implements StatementVisitor { void visitAtRootRule(AtRootRule node) { visitChildren(node.children); } diff --git a/lib/src/visitor/statement_search.dart b/lib/src/visitor/statement_search.dart index ca0cead9c..c1651b80e 100644 --- a/lib/src/visitor/statement_search.dart +++ b/lib/src/visitor/statement_search.dart @@ -18,9 +18,7 @@ import 'recursive_statement.dart'; /// This supports the same additional methods as [RecursiveStatementVisitor]. /// /// {@category Visitor} -abstract class StatementSearchVisitor implements StatementVisitor { - const StatementSearchVisitor(); - +mixin StatementSearchVisitor implements StatementVisitor { T? visitAtRootRule(AtRootRule node) => visitChildren(node.children); T? visitAtRule(AtRule node) => node.children.andThen(visitChildren); diff --git a/pkg/sass_api/CHANGELOG.md b/pkg/sass_api/CHANGELOG.md index 3ea3bfb4d..e1ae44fc0 100644 --- a/pkg/sass_api/CHANGELOG.md +++ b/pkg/sass_api/CHANGELOG.md @@ -1,7 +1,23 @@ ## 3.0.0 -* Replace the `minSpecificity` and `maxSpecificity` fields on `ComplexSelector`, - `CompoundSelector`, and `SimpleSelector` with a single `specificity` field. +* **Breaking change:** Convert all visitor superclasses into mixins. This + includes `RecursiveAstVisitor`, `RecursiveSelectorVisitor`, + `RecursiveStatementVisitor`, and `StatementSearchVisitor`. This has several + effects; + + * You must use `with` to mix in visitors rather than `extends`. + + * It's now possible to mix multiple visitors into the same class, which wasn't + possible with `extends`. + + * Because [mixins can't be composed], when mixing in `RecursiveAstVisitor` you + must explicitly mix in `RecursiveStatementVisitor` as well. + + [mixins can't be composed]: https://github.com/dart-lang/language/issues/540 + +* **Breaking change:** Replace the `minSpecificity` and `maxSpecificity` fields + on `ComplexSelector`, `CompoundSelector`, and `SimpleSelector` with a single + `specificity` field. ## 2.0.4 diff --git a/test/dart_api/visitor_test.dart b/test/dart_api/visitor_test.dart deleted file mode 100644 index a8d4455c8..000000000 --- a/test/dart_api/visitor_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2021 Google LLC. 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:sass/src/visitor/recursive_ast.dart'; -import 'package:sass/src/visitor/recursive_statement.dart'; - -/// Test that `RecursiveAstVisitor` is not missing any implementations. -class TestAstVisitor extends RecursiveAstVisitor {} - -/// Test that `RecursiveStatementVisitor` is not missing any implementations. -class TestStatementVisitor extends RecursiveStatementVisitor {} - -void main() {}