From 1bc35fa7ee6c7ba2bc96b34c9f351e7ba2cb3735 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sun, 5 Apr 2015 06:20:52 +0200 Subject: [PATCH] Implement handling of nested `:not` pseudo selectors They should not appear in the output. Ruby sass seems to have a minor bug, as it inserts additional spaces before the comma when the pseudo selector gets eliminated. --- ast.hpp | 31 +++++++++++++++++++++++++++++++ output.cpp | 10 ++++++++++ output.hpp | 1 + 3 files changed, 42 insertions(+) diff --git a/ast.hpp b/ast.hpp index 0eea9a9451..a92be72341 100644 --- a/ast.hpp +++ b/ast.hpp @@ -1791,6 +1791,8 @@ namespace Sass { virtual unsigned long specificity() { return Constants::Specificity_Universal; }; + virtual bool is_child(const string& name) { return false; } + virtual bool has_child(const string& name) { return false; } }; inline Selector::~Selector() { } @@ -1977,6 +1979,13 @@ namespace Sass { Wrapped_Selector(ParserState pstate, string n, Selector* sel) : Simple_Selector(pstate), name_(n), selector_(sel) { } + virtual bool is_child(const string& name) { + return name_ == name; + } + virtual bool has_child(const string& name) { + if (selector_ == 0) return false; + return selector_->has_child(name); + } // Selectors inside the negation pseudo-class are counted like any // other, but the negation itself does not count as a pseudo-class. virtual unsigned long specificity() @@ -2030,6 +2039,13 @@ namespace Sass { { sum += (*this)[i]->specificity(); } return sum; } + virtual bool has_child(const string& name) { + for (auto el : elements()) { + if (el->is_child(name)) return true; + if (el->has_child(name)) return true; + } + return false; + } bool is_empty_reference() { return length() == 1 && @@ -2091,6 +2107,12 @@ namespace Sass { if (tail()) sum += tail()->specificity(); return sum; } + virtual bool has_child(const string& name) { + return (head_ && head_->is_child(name)) || + (head_ && head_->has_child(name)) || + (tail_ && tail_->is_child(name)) || + (tail_ && tail_->has_child(name)); + } bool operator<(const Complex_Selector& rhs) const; bool operator==(const Complex_Selector& rhs) const; inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); } @@ -2172,6 +2194,15 @@ namespace Sass { { sum += (*this)[i]->specificity(); } return sum; } + virtual bool has_child(const string& name) + { + for (size_t i = 0, L = length(); i < L; ++i) + { + if ((*this)[i]->is_child(name)) return true; + if ((*this)[i]->has_child(name)) return true; + } + return false; + } // vector members() { return elements_; } ATTACH_OPERATIONS(); }; diff --git a/output.cpp b/output.cpp index 66729b4305..73a2cbdbec 100644 --- a/output.cpp +++ b/output.cpp @@ -72,6 +72,16 @@ namespace Sass { } + void Output::operator()(Wrapped_Selector* s) + { + if (s->name() == ":not(") { + if (s->has_child(":has(") || s->has_child(":not(")) { + return; // abort + } + } + return Inspect::operator()(s); + } + void Output::operator()(Comment* c) { To_String to_string(ctx); diff --git a/output.hpp b/output.hpp index 9417a05613..013beb5e50 100644 --- a/output.hpp +++ b/output.hpp @@ -42,6 +42,7 @@ namespace Sass { virtual void operator()(Media_Block*); virtual void operator()(At_Rule*); virtual void operator()(Keyframe_Rule*); + virtual void operator()(Wrapped_Selector*); virtual void operator()(Import*); virtual void operator()(Comment*); virtual void operator()(String_Quoted*);