Fixed AST generation for nth-(first|last)-of-type.
This commit is contained in:
parent
9eead81a7c
commit
b464815577
|
@ -424,10 +424,11 @@ end
|
||||||
##
|
##
|
||||||
# @param [String] count_axis
|
# @param [String] count_axis
|
||||||
# @param [AST::Node] arg
|
# @param [AST::Node] arg
|
||||||
|
# @param [AST::Node] count_test
|
||||||
# @return [AST::Node]
|
# @return [AST::Node]
|
||||||
#
|
#
|
||||||
def generate_nth_child(count_axis, arg)
|
def generate_nth_child(count_axis, arg, count_test = s(:test, nil, '*'))
|
||||||
count_call = s(:call, 'count', s(:axis, count_axis, s(:test, nil, '*')))
|
count_call = s(:call, 'count', s(:axis, count_axis, count_test))
|
||||||
|
|
||||||
# literal 2, 4, etc
|
# literal 2, 4, etc
|
||||||
if int_node?(arg)
|
if int_node?(arg)
|
||||||
|
@ -462,9 +463,7 @@ end
|
||||||
# @return [AST::Node]
|
# @return [AST::Node]
|
||||||
#
|
#
|
||||||
def on_pseudo_class_nth_of_type(arg)
|
def on_pseudo_class_nth_of_type(arg)
|
||||||
position_node = s(:call, 'position')
|
return generate_nth_child('preceding-sibling', arg, current_element)
|
||||||
|
|
||||||
return generate_nth_of_type(arg, position_node)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -474,44 +473,7 @@ end
|
||||||
# @return [AST::Node]
|
# @return [AST::Node]
|
||||||
#
|
#
|
||||||
def on_pseudo_class_nth_last_of_type(arg)
|
def on_pseudo_class_nth_last_of_type(arg)
|
||||||
position_node = s(
|
return generate_nth_child('following-sibling', arg, current_element)
|
||||||
:add,
|
|
||||||
s(:sub, s(:call, 'last'), s(:call, 'position')),
|
|
||||||
s(:int, 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
return generate_nth_of_type(arg, position_node)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# @param [AST::Node] arg
|
|
||||||
# @param [AST::Node] position_node
|
|
||||||
# @return [AST::Node]
|
|
||||||
#
|
|
||||||
def generate_nth_of_type(arg, position_node)
|
|
||||||
# literal 2, 4, etc
|
|
||||||
if int_node?(arg)
|
|
||||||
node = s(:eq, position_node, arg)
|
|
||||||
else
|
|
||||||
step, offset = *arg
|
|
||||||
compare = step_comparison(step)
|
|
||||||
|
|
||||||
# 2n+2, 2n-4, etc
|
|
||||||
if offset
|
|
||||||
mod_val = step_modulo_value(step)
|
|
||||||
node = s(
|
|
||||||
:and,
|
|
||||||
s(compare, position_node, offset),
|
|
||||||
s(:eq, s(:mod, s(:sub, position_node, offset), mod_val), s(:int, 0))
|
|
||||||
)
|
|
||||||
|
|
||||||
# 2n, n, -2n
|
|
||||||
else
|
|
||||||
node = s(:eq, s(:mod, position_node, step), s(:int, 0))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return node
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -2,109 +2,93 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe Oga::CSS::Parser do
|
describe Oga::CSS::Parser do
|
||||||
context ':nth-last-of-type pseudo class' do
|
context ':nth-last-of-type pseudo class' do
|
||||||
|
example 'parse the x:nth-last-of-type(1) pseudo class' do
|
||||||
|
parse_css('x:nth-last-of-type(1)').should == parse_xpath(
|
||||||
|
'descendant::x[count(following-sibling::x) = 0]'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(1) pseudo class' do
|
example 'parse the :nth-last-of-type(1) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(1)').should == parse_xpath(
|
parse_css(':nth-last-of-type(1)').should == parse_xpath(
|
||||||
'descendant::*[(last() - position() + 1) = 1]'
|
'descendant::*[count(following-sibling::*) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(2n) pseudo class' do
|
example 'parse the :nth-last-of-type(2) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(2n)').should == parse_xpath(
|
parse_css(':nth-last-of-type(2)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) mod 2) = 0]'
|
'descendant::*[count(following-sibling::*) = 1]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(3n) pseudo class' do
|
example 'parse the x:nth-last-of-type(even) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(3n)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(even)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) mod 3) = 0]'
|
'descendant::x[((count(following-sibling::x) + 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(2n+5) pseudo class' do
|
example 'parse the x:nth-last-of-type(odd) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(2n+5)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(odd)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) >= 5) ' \
|
'descendant::x[(count(following-sibling::x) + 1) >= 1 ' \
|
||||||
'and ((((last() - position() + 1) - 5) mod 2) = 0)]'
|
'and (((count(following-sibling::x) + 1) - 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(3n+5) pseudo class' do
|
example 'parse the x:nth-last-of-type(n) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(3n+5)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(n)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) >= 5) ' \
|
'descendant::x[((count(following-sibling::x) + 1) mod 1) = 0]'
|
||||||
'and ((((last() - position() + 1) - 5) mod 3) = 0)]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(2n-5) pseudo class' do
|
example 'parse the x:nth-last-of-type(-n) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(2n-5)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(-n)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) >= 1) ' \
|
'descendant::x[((count(following-sibling::x) + 1) mod 1) = 0]'
|
||||||
'and ((((last() - position() + 1) - 1) mod 2) = 0)]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(2n-6) pseudo class' do
|
example 'parse the x:nth-last-of-type(-n+6) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(2n-6)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(-n+6)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) >= 2) ' \
|
'descendant::x[((count(following-sibling::x) + 1) <= 6) ' \
|
||||||
'and ((((last() - position() + 1) - 2) mod 2) = 0)]'
|
'and (((count(following-sibling::x) + 1) - 6) mod 1) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(-2n+5) pseudo class' do
|
example 'parse the x:nth-last-of-type(n+5) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(-2n+5)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(n+5)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) <= 5) ' \
|
'descendant::x[(count(following-sibling::x) + 1) >= 5 ' \
|
||||||
'and (((last() - position() + 1) - 5) mod 2) = 0]'
|
'and (((count(following-sibling::x) + 1) - 5) mod 1) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(-2n-5) pseudo class' do
|
example 'parse the x:nth-last-of-type(2n) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(-2n-5)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(2n)')
|
||||||
'descendant::*[((last() - position() + 1) <= -1) ' \
|
.should == parse_css('x:nth-last-of-type(even)')
|
||||||
'and (((last() - position() + 1) - -1) mod 2) = 0]'
|
end
|
||||||
|
|
||||||
|
example 'parse the x:nth-last-of-type(2n+1) pseudo class' do
|
||||||
|
parse_css('x:nth-last-of-type(2n+1)').should == parse_xpath(
|
||||||
|
'descendant::x[(count(following-sibling::x) + 1) >= 1 ' \
|
||||||
|
'and (((count(following-sibling::x) + 1) - 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(-2n-6) pseudo class' do
|
example 'parse the x:nth-last-of-type(3n+1) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(-2n-6)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(3n+1)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) <= -2) ' \
|
'descendant::x[(count(following-sibling::x) + 1) >= 1 ' \
|
||||||
'and (((last() - position() + 1) - -2) mod 2) = 0]'
|
'and (((count(following-sibling::x) + 1) - 1) mod 3) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(even) pseudo class' do
|
example 'parse the x:nth-last-of-type(2n-6) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(even)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(2n-6)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) mod 2) = 0]'
|
'descendant::x[(count(following-sibling::x) + 1) >= 2 ' \
|
||||||
|
'and (((count(following-sibling::x) + 1) - 2) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(odd) pseudo class' do
|
example 'parse the x:nth-last-of-type(-2n+6) pseudo class' do
|
||||||
parse_css(':nth-last-of-type(odd)').should == parse_xpath(
|
parse_css('x:nth-last-of-type(-2n+6)').should == parse_xpath(
|
||||||
'descendant::*[((last() - position() + 1) >= 1) ' \
|
'descendant::x[((count(following-sibling::x) + 1) <= 6) ' \
|
||||||
'and ((((last() - position() + 1) - 1) mod 2) = 0)]'
|
'and (((count(following-sibling::x) + 1) - 6) mod 2) = 0]'
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(n) pseudo class' do
|
|
||||||
parse_css(':nth-last-of-type(n)').should == parse_xpath(
|
|
||||||
'descendant::*[((last() - position() + 1) mod 1) = 0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(n+5) pseudo class' do
|
|
||||||
parse_css(':nth-last-of-type(n+5)').should == parse_xpath(
|
|
||||||
'descendant::*[(last() - position() + 1) >= 5 ' \
|
|
||||||
'and (((last() - position() + 1) - 5) mod 1) = 0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(-n) pseudo class' do
|
|
||||||
parse_css(':nth-last-of-type(-n)').should == parse_xpath(
|
|
||||||
'descendant::*[((last() - position() + 1) mod 1) = 0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-last-of-type(-n+5) pseudo class' do
|
|
||||||
parse_css(':nth-last-of-type(-n+5)').should == parse_xpath(
|
|
||||||
'descendant::*[((last() - position() + 1) <= 5) ' \
|
|
||||||
'and (((last() - position() + 1) - 5) mod 1) = 0]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,109 +2,92 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe Oga::CSS::Parser do
|
describe Oga::CSS::Parser do
|
||||||
context ':nth-of-type pseudo class' do
|
context ':nth-of-type pseudo class' do
|
||||||
|
example 'parse the x:nth-of-type(1) pseudo class' do
|
||||||
|
parse_css('x:nth-of-type(1)').should == parse_xpath(
|
||||||
|
'descendant::x[count(preceding-sibling::x) = 0]'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(1) pseudo class' do
|
example 'parse the :nth-of-type(1) pseudo class' do
|
||||||
parse_css(':nth-of-type(1)').should == parse_xpath(
|
parse_css(':nth-of-type(1)').should == parse_xpath(
|
||||||
'descendant::*[position() = 1]'
|
'descendant::*[count(preceding-sibling::*) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(2n) pseudo class' do
|
example 'parse the :nth-of-type(2) pseudo class' do
|
||||||
parse_css(':nth-of-type(2n)').should == parse_xpath(
|
parse_css(':nth-of-type(2)').should == parse_xpath(
|
||||||
'descendant::*[(position() mod 2) = 0]'
|
'descendant::*[count(preceding-sibling::*) = 1]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(3n) pseudo class' do
|
example 'parse the x:nth-of-type(even) pseudo class' do
|
||||||
parse_css(':nth-of-type(3n)').should == parse_xpath(
|
parse_css('x:nth-of-type(even)').should == parse_xpath(
|
||||||
'descendant::*[(position() mod 3) = 0]'
|
'descendant::x[((count(preceding-sibling::x) + 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(2n+5) pseudo class' do
|
example 'parse the x:nth-of-type(odd) pseudo class' do
|
||||||
parse_css(':nth-of-type(2n+5)').should == parse_xpath(
|
parse_css('x:nth-of-type(odd)').should == parse_xpath(
|
||||||
'descendant::*[(position() >= 5) ' \
|
'descendant::x[(count(preceding-sibling::x) + 1) >= 1 ' \
|
||||||
'and (((position() - 5) mod 2) = 0)]'
|
'and (((count(preceding-sibling::x) + 1) - 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(3n+5) pseudo class' do
|
example 'parse the x:nth-of-type(n) pseudo class' do
|
||||||
parse_css(':nth-of-type(3n+5)').should == parse_xpath(
|
parse_css('x:nth-of-type(n)').should == parse_xpath(
|
||||||
'descendant::*[(position() >= 5) ' \
|
'descendant::x[((count(preceding-sibling::x) + 1) mod 1) = 0]'
|
||||||
'and (((position() - 5) mod 3) = 0)]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(2n-5) pseudo class' do
|
example 'parse the x:nth-of-type(-n) pseudo class' do
|
||||||
parse_css(':nth-of-type(2n-5)').should == parse_xpath(
|
parse_css('x:nth-of-type(-n)').should == parse_xpath(
|
||||||
'descendant::*[(position() >= 1) ' \
|
'descendant::x[((count(preceding-sibling::x) + 1) mod 1) = 0]'
|
||||||
'and (((position() - 1) mod 2) = 0)]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(2n-6) pseudo class' do
|
example 'parse the x:nth-of-type(-n+6) pseudo class' do
|
||||||
parse_css(':nth-of-type(2n-6)').should == parse_xpath(
|
parse_css('x:nth-of-type(-n+6)').should == parse_xpath(
|
||||||
'descendant::*[(position() >= 2) ' \
|
'descendant::x[((count(preceding-sibling::x) + 1) <= 6) ' \
|
||||||
'and (((position() - 2) mod 2) = 0)]'
|
'and (((count(preceding-sibling::x) + 1) - 6) mod 1) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(-2n+5) pseudo class' do
|
example 'parse the x:nth-of-type(n+5) pseudo class' do
|
||||||
parse_css(':nth-of-type(-2n+5)').should == parse_xpath(
|
parse_css('x:nth-of-type(n+5)').should == parse_xpath(
|
||||||
'descendant::*[(position() <= 5) ' \
|
'descendant::x[(count(preceding-sibling::x) + 1) >= 5 ' \
|
||||||
'and ((position() - 5) mod 2) = 0]'
|
'and (((count(preceding-sibling::x) + 1) - 5) mod 1) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(-2n-5) pseudo class' do
|
example 'parse the x:nth-of-type(2n) pseudo class' do
|
||||||
parse_css(':nth-of-type(-2n-5)').should == parse_xpath(
|
parse_css('x:nth-of-type(2n)').should == parse_css('x:nth-of-type(even)')
|
||||||
'descendant::*[(position() <= -1) ' \
|
end
|
||||||
'and ((position() - -1) mod 2) = 0]'
|
|
||||||
|
example 'parse the x:nth-of-type(2n+1) pseudo class' do
|
||||||
|
parse_css('x:nth-of-type(2n+1)').should == parse_xpath(
|
||||||
|
'descendant::x[(count(preceding-sibling::x) + 1) >= 1 ' \
|
||||||
|
'and (((count(preceding-sibling::x) + 1) - 1) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(-2n-6) pseudo class' do
|
example 'parse the x:nth-of-type(3n+1) pseudo class' do
|
||||||
parse_css(':nth-of-type(-2n-6)').should == parse_xpath(
|
parse_css('x:nth-of-type(3n+1)').should == parse_xpath(
|
||||||
'descendant::*[(position() <= -2) ' \
|
'descendant::x[(count(preceding-sibling::x) + 1) >= 1 ' \
|
||||||
'and ((position() - -2) mod 2) = 0]'
|
'and (((count(preceding-sibling::x) + 1) - 1) mod 3) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(even) pseudo class' do
|
example 'parse the x:nth-of-type(2n-6) pseudo class' do
|
||||||
parse_css(':nth-of-type(even)').should == parse_xpath(
|
parse_css('x:nth-of-type(2n-6)').should == parse_xpath(
|
||||||
'descendant::*[(position() mod 2) = 0]'
|
'descendant::x[(count(preceding-sibling::x) + 1) >= 2 ' \
|
||||||
|
'and (((count(preceding-sibling::x) + 1) - 2) mod 2) = 0]'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
example 'parse the :nth-of-type(odd) pseudo class' do
|
example 'parse the x:nth-of-type(-2n+6) pseudo class' do
|
||||||
parse_css(':nth-of-type(odd)').should == parse_xpath(
|
parse_css('x:nth-of-type(-2n+6)').should == parse_xpath(
|
||||||
'descendant::*[(position() >= 1) ' \
|
'descendant::x[((count(preceding-sibling::x) + 1) <= 6) ' \
|
||||||
'and (((position() - 1) mod 2) = 0)]'
|
'and (((count(preceding-sibling::x) + 1) - 6) mod 2) = 0]'
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-of-type(n) pseudo class' do
|
|
||||||
parse_css(':nth-of-type(n)').should == parse_xpath(
|
|
||||||
'descendant::*[(position() mod 1) =0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-of-type(n+5) pseudo class' do
|
|
||||||
parse_css(':nth-of-type(n+5)').should == parse_xpath(
|
|
||||||
'descendant::*[position() >= 5 ' \
|
|
||||||
'and ((position() - 5) mod 1) = 0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-of-type(-n) pseudo class' do
|
|
||||||
parse_css(':nth-of-type(-n)').should == parse_xpath(
|
|
||||||
'descendant::*[(position() mod 1) = 0]'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
example 'parse the :nth-of-type(-n+5) pseudo class' do
|
|
||||||
parse_css(':nth-of-type(-n+5)').should == parse_xpath(
|
|
||||||
'descendant::*[(position() <= 5) ' \
|
|
||||||
'and ((position() - 5) mod 1) = 0]'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue