Skip to content

Commit bb8902d

Browse files
committed
:is and :has pseudo classes
1 parent 531600e commit bb8902d

5 files changed

Lines changed: 28 additions & 9 deletions

File tree

src/CssParser/Lexer.x

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ $pm = [\-\+]
117117
@profile = @p@r@o@f@i@l@e
118118

119119
@to = @t@o
120+
@is = @i@s
121+
@has = @h@a@s
120122
@not = @n@o@t
121123
@where = @w@h@e@r@e
122124
@and = @a@n@d
@@ -278,8 +280,10 @@ tokens :-
278280
@psc @nthh@lasth@child "(" { constAndBegin (PseudoFunction NthFLastChild) nth_state }
279281
@psc @nthh@lasth@oftype "(" { constAndBegin (PseudoFunction NthFLastOfType) nth_state }
280282
@psc @nthh@oftype "(" { constAndBegin (PseudoFunction NthFOfType) nth_state }
281-
@psc @not "(" @wo { constoken TNot }
283+
@psc @not { constoken TNot }
282284
@psc @where { constoken TWhere }
285+
@psc @has { constoken THas }
286+
@psc @is { constoken TIs }
283287
@wo ")" { constoken TClose }
284288
"(" { constoken TOpen }
285289
@psc @onlyh@oftype { constoken (AtomicPseudoClassT OnlyOfType) }
@@ -431,6 +435,8 @@ data Token
431435
| TClose
432436
| TNot
433437
| TWhere
438+
| TIs
439+
| THas
434440
| TLang
435441
deriving (Show, Eq)
436442

src/CssParser/Parser.y

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import CssParser.Lexer
3636
, TOpen, TClose
3737
, Greater, Less, LessEqual, GreaterEqual
3838
, RatioT, Percents, Pixels
39-
, UrlT, TWhere
39+
, UrlT, TWhere, THas, TIs
4040
, PseudoPageT, PageT, PageMarginT
4141
, KeyframesT, ColorProfileT, FontFaceT, SrcPropT, UnicodeRangeT, UnicodeRangeVal
4242
, FontFeatureValuesT, AtT, FontPaletteValuesT, ContainerT, DivT, PositionTryT
@@ -152,8 +152,10 @@ import Prelude
152152
px { TokenLoc (Pixels $$) _ _ }
153153
var { TokenLoc (Var $$) _ _ }
154154
nth { TokenLoc (TNth $$) _ _ }
155-
'not(' { TokenLoc TNot _ _ }
155+
':not' { TokenLoc TNot _ _ }
156156
where { TokenLoc TWhere _ _ }
157+
is { TokenLoc TIs _ _ }
158+
has { TokenLoc THas _ _ }
157159
'lang(' { TokenLoc TLang _ _ }
158160
'(' { TokenLoc TOpen _ _ }
159161
')' { TokenLoc TClose _ _ }
@@ -440,12 +442,15 @@ CssRuleBody :: { [ CssRuleBodyItem ] }
440442
| IdKwd pseudc ContinueRule CssRuleBody { upsertHeadTagSelector
441443
(setTag $1 . addClass (AtomicPseudoClass $2)) $3 $4 }
442444
| IdKwd pseudc ERB CssRuleBody { newRule (addClass (AtomicPseudoClass $2) . setTag $1) $3 $4 }
443-
| IdKwd 'not(' SelectorList ')' ContinueRule CssRuleBody
444-
{ upsertHeadTagSelector (setTag $1 . addClass (NotClass $3)) $5 $6 }
445-
| IdKwd 'not(' SelectorList ')' ERB CssRuleBody
446-
{ newRule (setTag $1 . addClass (NotClass $3)) $5 $6 }
445+
| IdKwd ':not' ESL ContinueRule CssRuleBody { upsertHeadTagSelector (setTag $1 . addClass (NotClass $3)) $4 $5 }
446+
| IdKwd ':not' ESL ERB CssRuleBody { newRule (setTag $1 . addClass (NotClass $3)) $4 $5 }
447447
| IdKwd where ESL ContinueRule CssRuleBody { upsertHeadTagSelector (setTag $1 . addClass (Where $3)) $4 $5 }
448448
| IdKwd where ESL ERB CssRuleBody { newRule (setTag $1 . addClass (Where $3)) $4 $5 }
449+
| IdKwd is ESL ContinueRule CssRuleBody { upsertHeadTagSelector (setTag $1 . addClass (Is $3)) $4 $5 }
450+
| IdKwd is ESL ERB CssRuleBody { newRule (setTag $1 . addClass (Is $3)) $4 $5 }
451+
| IdKwd has ESL ContinueRule CssRuleBody { upsertHeadTagSelector (setTag $1 . addClass (Has $3)) $4 $5 }
452+
| IdKwd has ESL ERB CssRuleBody { newRule (setTag $1 . addClass (Has $3)) $4 $5 }
453+
449454
| IdKwd 'lang(' Str ')' ContinueRule CssRuleBody
450455
{ upsertHeadTagSelector (setTag $1 . addClass (Lang (Language $3))) $5 $6 }
451456
| IdKwd 'lang(' Str ')' ERB CssRuleBody { newRule (setTag $1 . addClass (Lang (Language $3))) $5 $6 }
@@ -501,9 +506,11 @@ TagClasses :: { [ Class ] }
501506
TagClass :: { Class }
502507
: '.' Ident { AtomicClass $2 }
503508
| pseudc { AtomicPseudoClass $1 }
504-
| 'not(' SelectorList ')' { NotClass $2 }
505-
| 'lang(' string ')' { Lang (Language (pack $2)) }
509+
| ':not' ESL { NotClass $2 }
510+
| 'lang(' Str ')' { Lang (Language $2) }
506511
| where ESL { Where $2 }
512+
| is ESL { Is $2 }
513+
| has ESL { Has $2 }
507514
| pseudf Os Nth { call $1 $3 }
508515
ZipTagRelAndTagSel :: { [ (TagRelation, TagSelector) ] }
509516
: { [] }

src/CssParser/Rule.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ data Class
6868
| NotClass SelectorList
6969
| Lang Language
7070
| Where SelectorList
71+
| Has SelectorList
72+
| Is SelectorList
7173
| NthChild Nth
7274
| NthLastChild Nth
7375
| NthLastOfType Nth

src/CssParser/Rule/Show.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ instance CssShow Class where
8585
NotClass nes -> ":not(" <> toCssText nes <> ")"
8686
Lang (Language l) -> ":lang(" <> fromStrict l <> ")"
8787
Where nes -> ":where(" <> toCssText nes <> ")"
88+
Is nes -> ":is(" <> toCssText nes <> ")"
89+
Has nes -> ":has(" <> toCssText nes <> ")"
8890
NthChild nth -> ":nth-child(" <> toCssText nth <> ")"
8991
NthLastChild nth -> ":nth-last-child(" <> toCssText nth <> ")"
9092
NthLastOfType nth -> ":nth-last-of-type(" <> toCssText nth <> ")"

test/Spec.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ validSelectors =
245245
, "body > h2:nth-of-type(n+2):nth-last-of-type(n+2)"
246246
, "body > h2:not(:first-of-type):not(:last-of-type)"
247247
, ":where(ol, ul, menu:focus)"
248+
, "h1:has(+ p)"
249+
, ":is(ol, ul) :is(ol, ul) ol"
248250
, "div:where(ol, ul) :where(ol, ul, menu:hover) ol"
249251
, "h1, h2, h3"
250252
, "h1"

0 commit comments

Comments
 (0)