Basic support for the CSS :not pseudo class

This does _not_ support element states such as DISABLED, nor does it
support the special handling of namespaces (e.g. *|*:not(*)). Instead
this selector basically acts as a negation, some examples:

    :not(foo)  # All but any "foo" nodes
    :not(#foo) # Skips nodes with id="foo"
    :not(.foo) # Skips nodes with a class "foo"

Fixes #125
This commit is contained in:
Yorick Peterse 2015-09-01 22:05:46 +02:00
parent b7b38255d3
commit aef7c510c2
4 changed files with 49 additions and 0 deletions

View File

@ -230,6 +230,8 @@ module Oga
pseudo_args := |*
whitespace;
hash | dot | colon;
# NOTE: the priorities here are put in place to ensure that rules such
# as `nth` take precedence over `identifier`. The highest number has
# the highest priority.

View File

@ -497,6 +497,24 @@ even
s(:call, 'not', s(:axis, 'child', s(:type_test, 'node')))
end
# Generates the AST for the `:not` selector.
#
# @param [AST::Node] arg
# @return [AST::Node]
def on_pseudo_class_not(arg)
# Unpacks (axis "descendant" (test nil "x")) into just (test nil "x") as
# in this case we want to wrap the (test) node in a (axis "self") node.
if arg.type == :axis
arg = s(:axis, 'self', arg.children[1])
# Unpack (predicate (eq ...)) into just (eq)
elsif arg.type == :predicate
arg = arg.children[1]
end
s(:call, 'not', arg)
end
# Generates the AST for the `=` operator.
#
# @param [AST::Node] attr

View File

@ -126,5 +126,16 @@ describe Oga::CSS::Lexer do
[:T_RPAREN, nil]
]
end
it 'lexes the :not(#foo) pseudo class' do
lex_css(':not(#foo)').should == [
[:T_COLON, nil],
[:T_IDENT, 'not'],
[:T_LPAREN, nil],
[:T_HASH, nil],
[:T_IDENT, 'foo'],
[:T_RPAREN, nil]
]
end
end
end

View File

@ -0,0 +1,18 @@
require 'spec_helper'
describe Oga::CSS::Parser do
describe ':not pseudo class' do
it 'parses the :not(x) pseudo class' do
parse_css(':not(x)').should == parse_xpath('descendant::*[not(self::x)]')
end
it 'parses the x:not(y) pseudo class' do
parse_css('x:not(y)').should == parse_xpath('descendant::x[not(self::y)]')
end
it 'parses the x:not(#foo) pseudo class' do
parse_css('x:not(#foo)').should ==
parse_xpath('descendant::x[not(@id="foo")]')
end
end
end