From e0ab71f73e2043a89f2a9db5bcac97bee72f963e Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sun, 7 Jun 2020 13:27:54 -0400 Subject: [PATCH] simple pseudo selector-extend tests --- src/selector/compound.rs | 4 +-- src/selector/simple.rs | 54 ++++++++++++++++++++++++++++++++--- tests/selector-extend.rs | 61 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/selector/compound.rs b/src/selector/compound.rs index 179513c..9b398d5 100644 --- a/src/selector/compound.rs +++ b/src/selector/compound.rs @@ -40,11 +40,11 @@ impl fmt::Display for CompoundSelector { impl CompoundSelector { pub fn max_specificity(&self) -> i32 { - self.specificity().min + self.specificity().max } pub fn min_specificity(&self) -> i32 { - self.specificity().max + self.specificity().min } /// Returns tuple of (min, max) specificity diff --git a/src/selector/simple.rs b/src/selector/simple.rs index 9ecd3f3..fe7ea0c 100644 --- a/src/selector/simple.rs +++ b/src/selector/simple.rs @@ -2,11 +2,13 @@ use std::fmt::{self, Write}; use super::{ Attribute, ComplexSelector, ComplexSelectorComponent, CompoundSelector, Namespace, - QualifiedName, SelectorList, + QualifiedName, SelectorList, Specificity, }; const SUBSELECTOR_PSEUDOS: [&str; 4] = ["matches", "any", "nth-child", "nth-last-child"]; +const BASE_SPECIFICITY: i32 = 1000; + #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub(crate) enum SimpleSelector { /// * @@ -84,9 +86,9 @@ impl SimpleSelector { match self { Self::Universal(..) => 0, Self::Type(..) => 1, - Self::Pseudo { .. } => todo!(), - Self::Id(..) => 1000_i32.pow(2_u32), - _ => 1000, + Self::Pseudo(pseudo) => pseudo.min_specificity(), + Self::Id(..) => BASE_SPECIFICITY.pow(2_u32), + _ => BASE_SPECIFICITY, } } @@ -97,6 +99,7 @@ impl SimpleSelector { pub fn max_specificity(&self) -> i32 { match self { Self::Universal(..) => 0, + Self::Pseudo(pseudo) => pseudo.max_specificity(), _ => self.min_specificity(), } } @@ -567,6 +570,49 @@ impl Pseudo { pub fn with_selector(self, selector: Option) -> Self { Self { selector, ..self } } + + pub fn max_specificity(&self) -> i32 { + self.specificity().max + } + + pub fn min_specificity(&self) -> i32 { + self.specificity().min + } + + pub fn specificity(&self) -> Specificity { + if !self.is_class { + return Specificity { min: 1, max: 1 }; + } + + let selector = match &self.selector { + Some(sel) => sel, + None => { + return Specificity { + min: BASE_SPECIFICITY, + max: BASE_SPECIFICITY, + } + } + }; + + if self.name == "not" { + let mut min = 0; + let mut max = 0; + for complex in &selector.components { + min = min.max(complex.min_specificity()); + max = max.max(complex.max_specificity()); + } + return Specificity { min, max }; + } else { + // This is higher than any selector's specificity can actually be. + let mut min = BASE_SPECIFICITY.pow(3_u32); + let mut max = 0; + for complex in &selector.components { + min = min.min(complex.min_specificity()); + max = max.max(complex.max_specificity()); + } + return Specificity { min, max }; + } + } } /// Returns all pseudo selectors in `compound` that have a selector argument, diff --git a/tests/selector-extend.rs b/tests/selector-extend.rs index aebd99c..8e795a9 100644 --- a/tests/selector-extend.rs +++ b/tests/selector-extend.rs @@ -128,6 +128,66 @@ test!( "a {\n color: selector-extend(\"*|c\", \"*|c\", \"d\");\n}\n", "a {\n color: *|c, d;\n}\n" ); +test!( + simple_pseudo_class_no_arg_equal, + "a {\n color: selector-extend(\":c\", \":c\", \"e\");\n}\n", + "a {\n color: :c, e;\n}\n" +); +test!( + simple_pseudo_class_no_arg_unequal, + "a {\n color: selector-extend(\":c\", \":d\", \"e\");\n}\n", + "a {\n color: :c;\n}\n" +); +test!( + simple_pseudo_class_no_arg_and_element, + "a {\n color: selector-extend(\":c\", \"::c\", \"e\");\n}\n", + "a {\n color: :c;\n}\n" +); +test!( + simple_pseudo_element_no_arg_and_element_equal, + "a {\n color: selector-extend(\"::c\", \"::c\", \"e\");\n}\n", + "a {\n color: ::c, e;\n}\n" +); +test!( + simple_pseudo_element_no_arg_and_class, + "a {\n color: selector-extend(\"::c\", \":c\", \"e\");\n}\n", + "a {\n color: ::c;\n}\n" +); +test!( + simple_pseudo_class_arg_equal, + "a {\n color: selector-extend(\":c(@#$)\", \":c(@#$)\", \"e\");\n}\n", + "a {\n color: :c(@#$), e;\n}\n" +); +test!( + simple_pseudo_class_arg_unequal_name, + "a {\n color: selector-extend(\":c(@#$)\", \":d(@#$)\", \"e\");\n}\n", + "a {\n color: :c(@#$);\n}\n" +); +test!( + simple_pseudo_class_arg_unequal_arg, + "a {\n color: selector-extend(\":c(@#$)\", \":c(*&^)\", \"e\");\n}\n", + "a {\n color: :c(@#$);\n}\n" +); +test!( + simple_pseudo_class_arg_unequal_no_arg, + "a {\n color: selector-extend(\":c(@#$)\", \":c\", \"e\");\n}\n", + "a {\n color: :c(@#$);\n}\n" +); +test!( + simple_pseudo_class_arg_and_element, + "a {\n color: selector-extend(\":c(@#$)\", \"::c(@#$)\", \"e\");\n}\n", + "a {\n color: :c(@#$);\n}\n" +); +test!( + simple_pseudo_element_arg_and_element_equal, + "a {\n color: selector-extend(\"::c(@#$)\", \"::c(@#$)\", \"e\");\n}\n", + "a {\n color: ::c(@#$), e;\n}\n" +); +test!( + simple_pseudo_element_arg_and_class, + "a {\n color: selector-extend(\"::c(@#$)\", \":c(@#$)\", \"e\");\n}\n", + "a {\n color: ::c(@#$);\n}\n" +); test!( complex_parent_without_grandparents_simple, "a {\n color: selector-extend(\".c .d\", \".c\", \".e\");\n}\n", @@ -173,3 +233,4 @@ test!( "a {\n color: selector-extend(\".c .d\", \".c\", \".e +\");\n}\n", "a {\n color: .c .d, .e + .d;\n}\n" ); +// todo: https://github.com/sass/sass-spec/tree/master/spec/core_functions/selector/extend/simple/pseudo/selector/