Skip to content

Commit

Permalink
Internally separate the need for closing brackets from pseudo
Browse files Browse the repository at this point in the history
  • Loading branch information
facelessuser committed Dec 19, 2018
1 parent 8fe7251 commit a2cdbb4
Showing 1 changed file with 21 additions and 17 deletions.
38 changes: 21 additions & 17 deletions soupsieve/css_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
FLG_DEFAULT = 0x08
FLG_HTML = 0x10
FLG_INDETERMINATE = 0x20
FLG_OPEN = 0x40

_MAXCACHE = 500

Expand Down Expand Up @@ -296,7 +297,7 @@ def parse_attribute_selector(self, sel, m, has_selector):
sel.selectors.append(
self.parse_selectors(
# Simulate the content of `:not`, but make the attribute as `=` instead of `!=`.
self.selector_iter('[{}={} {}])'.format(attr, value, case)),
self.selector_iter('[{}={} {}]'.format(attr, value, case)),
FLG_PSEUDO | FLG_NOT
)
)
Expand Down Expand Up @@ -385,7 +386,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
elif pseudo in (':link', ':any-link'):
sel.selectors.append(
self.parse_selectors(
self.selector_iter(':is(a, area, link)[href])'),
self.selector_iter(':is(a, area, link)[href]'),
FLG_PSEUDO | FLG_HTML
)
)
Expand All @@ -395,7 +396,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
self.selector_iter(
'''
:is(input[type=checkbox], input[type=radio])[checked],
select > option[selected])
select > option[selected]
'''
),
FLG_PSEUDO | FLG_HTML
Expand All @@ -404,7 +405,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
elif pseudo == ':default':
sel.selectors.append(
self.parse_selectors(
self.selector_iter(':checked, form :is(button, input)[type="submit"])'),
self.selector_iter(':checked, form :is(button, input)[type="submit"]'),
FLG_PSEUDO | FLG_HTML | FLG_DEFAULT
)
)
Expand All @@ -416,7 +417,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
input[type="checkbox"][indeterminate],
input[type="radio"]:is(:not([name]), [name=""]):not([checked]),
progress:not([value]),
input[type="radio"][name][name!='']:not([checked]))
input[type="radio"][name][name!='']:not([checked])
'''
),
FLG_PSEUDO | FLG_HTML | FLG_INDETERMINATE
Expand All @@ -430,7 +431,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
:is(input[type!=hidden], button, select, textarea, fieldset, optgroup, option)[disabled],
optgroup[disabled] > option,
fieldset[disabled] > :not(legend) :is(input[type!=hidden], button, select, textarea),
fieldset[disabled] > :is(input[type!=hidden], button, select, textarea))
fieldset[disabled] > :is(input[type!=hidden], button, select, textarea)
'''
),
FLG_PSEUDO | FLG_HTML
Expand All @@ -447,7 +448,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
:is(input[type!=hidden], button, select, textarea):not(
fieldset[disabled] > :not(legend) *,
fieldset[disabled] > *
):not([disabled]))
):not([disabled])
'''
),
FLG_PSEUDO | FLG_HTML
Expand All @@ -456,14 +457,14 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
elif pseudo == ":required":
sel.selectors.append(
self.parse_selectors(
self.selector_iter(':is(input, textarea, select)[required])'),
self.selector_iter(':is(input, textarea, select)[required]'),
FLG_PSEUDO | FLG_HTML
)
)
elif pseudo == ":optional":
sel.selectors.append(
self.parse_selectors(
self.selector_iter(':is(input, textarea, select):not([required]))'),
self.selector_iter(':is(input, textarea, select):not([required])'),
FLG_PSEUDO | FLG_HTML
)
)
Expand All @@ -485,7 +486,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
[type=""]
),
textarea
)[placeholder][placeholder!=''])
)[placeholder][placeholder!='']
'''
),
FLG_PSEUDO | FLG_HTML
Expand Down Expand Up @@ -515,7 +516,7 @@ def parse_pseudo(self, sel, m, has_selector, iselector):
)
has_selector = True
elif complex_pseudo and pseudo in PSEUDO_COMPLEX_NO_MATCH:
self.parse_selectors(iselector, FLG_PSEUDO)
self.parse_selectors(iselector, FLG_PSEUDO | FLG_OPEN)
sel.no_match = True
has_selector = True
elif not complex_pseudo and pseudo in PSEUDO_SIMPLE_NO_MATCH:
Expand Down Expand Up @@ -565,13 +566,15 @@ def parse_pseudo_nth(self, sel, m, has_selector, iselector):

pseudo_sel = util.lower(m.group('pseudo_nth' + postfix))
if postfix == '_child':
flags = FLG_PSEUDO
if pseudo_sel.strip().endswith('of'):
# Parse the rest of `of S`.
temp_sel = iselector
flags |= FLG_OPEN
else:
# Use default `*|*` for `of S`. Simulate un-closed pseudo.
temp_sel = self.selector_iter('*|*)')
nth_sel = self.parse_selectors(temp_sel, FLG_PSEUDO)
# Use default `*|*` for `of S`.
temp_sel = self.selector_iter('*|*')
nth_sel = self.parse_selectors(temp_sel, flags)
if pseudo_sel.startswith(':nth-child'):
sel.nth.append(ct.SelectorNth(s1, var, s2, False, False, nth_sel))
elif pseudo_sel.startswith(':nth-last-child'):
Expand All @@ -587,7 +590,7 @@ def parse_pseudo_nth(self, sel, m, has_selector, iselector):
def parse_pseudo_open(self, sel, name, has_selector, iselector):
"""Parse pseudo with opening bracket."""

flags = FLG_PSEUDO
flags = FLG_PSEUDO | FLG_OPEN
if name == ':not':
flags |= FLG_NOT
if name == ':has':
Expand Down Expand Up @@ -703,6 +706,7 @@ def parse_selectors(self, iselector, flags=0):
relations = []
rel_type = REL_HAS_CHILD
split_last = False
is_open = flags & FLG_OPEN
is_pseudo = flags & FLG_PSEUDO
is_has = flags & FLG_HAS
is_not = flags & FLG_NOT
Expand All @@ -728,7 +732,7 @@ def parse_selectors(self, iselector, flags=0):
elif key == 'pseudo_close':
if split_last:
raise SyntaxError("Cannot end with a combining character")
if is_pseudo:
if is_open:
closed = True
break
else:
Expand Down Expand Up @@ -756,7 +760,7 @@ def parse_selectors(self, iselector, flags=0):
except StopIteration:
pass

if is_pseudo and not closed:
if is_open and not closed:
raise SyntaxError("Unclosed `:pseudo()`")

if split_last:
Expand Down

0 comments on commit a2cdbb4

Please sign in to comment.