feat(css/parser): Support new nesting spec (#6337)

This commit is contained in:
Alexander Akait 2022-11-03 18:08:23 +03:00 committed by GitHub
parent d90b0c600d
commit e0967efa6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 13232 additions and 2264 deletions

View File

@ -4,7 +4,7 @@ use swc_common::{ast_node, EqIgnoreSpan, Span};
use crate::{
AlphaValue, AtRule, CalcSum, CmykComponent, Color, ComplexSelector, DashedIdent, Delimiter,
Dimension, Hue, Ident, Integer, KeyframeBlock, LayerName, Number, Percentage, Ratio,
SelectorList, Str, TokenAndSpan, UnicodeRange, Url,
RelativeSelectorList, SelectorList, Str, TokenAndSpan, UnicodeRange, Url,
};
#[ast_node("Stylesheet")]
@ -38,10 +38,12 @@ pub struct QualifiedRule {
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum QualifiedRulePrelude {
#[tag("ListOfComponentValues")]
ListOfComponentValues(ListOfComponentValues),
#[tag("SelectorList")]
SelectorList(SelectorList),
#[tag("RelativeSelectorList")]
RelativeSelectorList(RelativeSelectorList),
#[tag("ListOfComponentValues")]
ListOfComponentValues(ListOfComponentValues),
}
#[ast_node]

View File

@ -93,6 +93,10 @@ where
emit!(self, n);
formatting_space!(self);
}
QualifiedRulePrelude::RelativeSelectorList(n) => {
emit!(self, n);
formatting_space!(self);
}
QualifiedRulePrelude::ListOfComponentValues(n) => {
emit!(
&mut *self.with_ctx(Ctx {

View File

@ -24,8 +24,7 @@
.foo {
color: red;
@media (min-width: 480px) {
& h1,
& h2 {
& h1, & h2 {
color: blue;
}
}

View File

@ -83,8 +83,8 @@ body:first-of-type .selector {}
$property: value;color: red;
}
.selector {
color: red;
&property: value;}
&property: value;color: red;
}
.selector {
*property: value;color: red;
}

View File

@ -1 +1 @@
.selector:not(*:root){}@media screen and (min-width:0\0){}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}@media \\0 screen {}@media all and (-webkit-min-device-pixel-ratio:0)and (min-resolution:.001dpcm){.selector{}}body:empty .selector{}body:last-child .selector,x:-moz-any-link{}@media \0 all{}body:last-child .selector,x:-moz-any-link,x:default{}body:not(:-moz-handler-blocked) .selector{}@media screen and (-moz-images-in-menus:0){}@media screen and (min--moz-device-pixel-ratio:0){}_::-moz-progress-bar,body:last-child .selector{}@media all and (min--moz-device-pixel-ratio:0)and (min-resolution:.001dpcm){}@media all and (-moz-images-in-menus:0)and (min-resolution:.001dpcm){}@media all and (min--moz-device-pixel-ratio:0){@media(min-width:0px){}}@media all and (-moz-images-in-menus:0){@media(min-width:0px){}}@supports(-moz-appearance:meterbar){}_::-moz-range-track,body:last-child .selector{}@supports(-moz-appearance:meterbar)and (display:flex){}@supports(-moz-appearance:meterbar)and (cursor:zoom-in){}@supports(-moz-appearance:meterbar)and (background-attachment:local){}@supports(-moz-appearance:meterbar)and (image-orientation:90deg){}@supports(-moz-appearance:meterbar)and (all:initial){}@supports(-moz-appearance:meterbar)and (list-style-type:japanese-formal){}@media all and (min--moz-device-pixel-ratio:0)and (min-resolution:30dpcm){}@supports(-moz-appearance:meterbar)and (background-blend-mode:difference,normal){}_:-moz-tree-row(hover),.selector{}_::selection,.selector:not([attr*=""]){}@supports(-webkit-appearance:none){}* html .selector{}.unused-class.selector{}html>body .selector{}*:first-child+html .selector{}.selector,x:-ie7{}*+html .selector{}body *.selector{}.selector\ {}html>body .selector{}head~body .selector{}_::selection,.selector:not([attr*=""]){}:root .selector{}body:last-child .selector{}body:nth-of-type(1) .selector{}body:first-of-type .selector{}.selector:not([attr*=""]){}.selector{_property:value}.selector{-property:value}.selector{property:value\9}.selector{property:value\9}.selector{!property: value;color:red}.selector{$property: value;color:red}.selector{color:red;&property: value;}.selector{*property: value;color:red}.selector{)property: value;color:red}.selector{=property: value;color:red}.selector{%property: value;color:red}.selector{+property: value;color:red}.selector{color:red;@property: value;}.selector{,property: value;color:red}.selector{.property: value;color:red}.selector{/property: value;color:red}.selector{`property: value;color:red}.selector{]property: value;color:red}.selector{#property: value;color:red}.selector{~property: value;color:red}.selector{?property: value;color:red}.selector{:property: value;color:red}.selector{|property: value;color:red}.selector{property:value !ie}@media screen\9{}@media \0screen\,screen\9 {}@media \0screen{}@media screen and (min-width:0\0){}_:-ms-input-placeholder,:root .selector{}_:-ms-fullscreen,:root .selector{}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){}@media screen{@media(min-width:0px){}}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}html:first-child .selector{}_:-o-prefocus,body:last-child .selector{}@media all and (-webkit-min-device-pixel-ratio:1e4),not all and (-webkit-min-device-pixel-ratio:0){}@media(min-resolution:.001dpcm){_:-o-prefocus,.selector{}}*|html[xmlns*=""] .selector{}@media all and (-webkit-min-device-pixel-ratio:0)and (min-resolution:.001dpcm){.selector{}}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}@media screen and (min-width:0\0){}@media screen{@media(min-width:0px){}}html:first-child .selector{}html[xmlns*=""] body:last-child .selector{}html[xmlns*=""]:root .selector{}*|html[xmlns*=""] .selector{}_::-moz-svg-foreign-content,:root .selector{}@media \\0 screen {}a{*color : black;_background:white;font-size:big;$(var)-size: 100%;}a{*b:c}div{color:red}selector{property:value;property:normal-value}div{color:red}
.selector:not(*:root){}@media screen and (min-width:0\0){}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}@media \\0 screen {}@media all and (-webkit-min-device-pixel-ratio:0)and (min-resolution:.001dpcm){.selector{}}body:empty .selector{}body:last-child .selector,x:-moz-any-link{}@media \0 all{}body:last-child .selector,x:-moz-any-link,x:default{}body:not(:-moz-handler-blocked) .selector{}@media screen and (-moz-images-in-menus:0){}@media screen and (min--moz-device-pixel-ratio:0){}_::-moz-progress-bar,body:last-child .selector{}@media all and (min--moz-device-pixel-ratio:0)and (min-resolution:.001dpcm){}@media all and (-moz-images-in-menus:0)and (min-resolution:.001dpcm){}@media all and (min--moz-device-pixel-ratio:0){@media(min-width:0px){}}@media all and (-moz-images-in-menus:0){@media(min-width:0px){}}@supports(-moz-appearance:meterbar){}_::-moz-range-track,body:last-child .selector{}@supports(-moz-appearance:meterbar)and (display:flex){}@supports(-moz-appearance:meterbar)and (cursor:zoom-in){}@supports(-moz-appearance:meterbar)and (background-attachment:local){}@supports(-moz-appearance:meterbar)and (image-orientation:90deg){}@supports(-moz-appearance:meterbar)and (all:initial){}@supports(-moz-appearance:meterbar)and (list-style-type:japanese-formal){}@media all and (min--moz-device-pixel-ratio:0)and (min-resolution:30dpcm){}@supports(-moz-appearance:meterbar)and (background-blend-mode:difference,normal){}_:-moz-tree-row(hover),.selector{}_::selection,.selector:not([attr*=""]){}@supports(-webkit-appearance:none){}* html .selector{}.unused-class.selector{}html>body .selector{}*:first-child+html .selector{}.selector,x:-ie7{}*+html .selector{}body *.selector{}.selector\ {}html>body .selector{}head~body .selector{}_::selection,.selector:not([attr*=""]){}:root .selector{}body:last-child .selector{}body:nth-of-type(1) .selector{}body:first-of-type .selector{}.selector:not([attr*=""]){}.selector{_property:value}.selector{-property:value}.selector{property:value\9}.selector{property:value\9}.selector{!property: value;color:red}.selector{$property: value;color:red}.selector{&property: value;color:red}.selector{*property: value;color:red}.selector{)property: value;color:red}.selector{=property: value;color:red}.selector{%property: value;color:red}.selector{+property: value;color:red}.selector{color:red;@property: value;}.selector{,property: value;color:red}.selector{.property: value;color:red}.selector{/property: value;color:red}.selector{`property: value;color:red}.selector{]property: value;color:red}.selector{#property: value;color:red}.selector{~property: value;color:red}.selector{?property: value;color:red}.selector{:property: value;color:red}.selector{|property: value;color:red}.selector{property:value !ie}@media screen\9{}@media \0screen\,screen\9 {}@media \0screen{}@media screen and (min-width:0\0){}_:-ms-input-placeholder,:root .selector{}_:-ms-fullscreen,:root .selector{}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){}@media screen{@media(min-width:0px){}}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}html:first-child .selector{}_:-o-prefocus,body:last-child .selector{}@media all and (-webkit-min-device-pixel-ratio:1e4),not all and (-webkit-min-device-pixel-ratio:0){}@media(min-resolution:.001dpcm){_:-o-prefocus,.selector{}}*|html[xmlns*=""] .selector{}@media all and (-webkit-min-device-pixel-ratio:0)and (min-resolution:.001dpcm){.selector{}}.selector:not(*:root){}@supports(-webkit-appearance:none){}.selector{(;property: value;);}.selector{[;property: value;];}@media screen and (min-width:0\0){}@media screen{@media(min-width:0px){}}html:first-child .selector{}html[xmlns*=""] body:last-child .selector{}html[xmlns*=""]:root .selector{}*|html[xmlns*=""] .selector{}_::-moz-svg-foreign-content,:root .selector{}@media \\0 screen {}a{*color : black;_background:white;font-size:big;$(var)-size: 100%;}a{*b:c}div{color:red}selector{property:value;property:normal-value}div{color:red}

View File

@ -1,12 +1,7 @@
use std::iter::once;
use swc_common::{util::take::Take, DUMMY_SP};
use swc_css_ast::{
AtRule, AtRulePrelude, ComplexSelector, ComplexSelectorChildren, ComponentValue,
CompoundSelector, ForgivingComplexSelector, ForgivingSelectorList, PseudoClassSelector,
PseudoClassSelectorChildren, QualifiedRule, QualifiedRulePrelude, Rule, SelectorList,
SimpleBlock, StyleBlock, SubclassSelector,
};
use swc_css_ast::*;
use swc_css_visit::{VisitMut, VisitMutWith};
pub fn nesting() -> impl VisitMut {
@ -16,48 +11,6 @@ pub fn nesting() -> impl VisitMut {
struct NestingHandler {}
impl NestingHandler {
fn append_compound(
&mut self,
prelude: &SelectorList,
to: &mut ComplexSelector,
base: &ComplexSelector,
c: &CompoundSelector,
) {
if c.nesting_selector.is_some() {
let len = base.children.len();
to.children
.extend(
base.children
.iter()
.cloned()
.enumerate()
.map(|(idx, mut children)| {
if idx == len - 1 {
if let ComplexSelectorChildren::CompoundSelector(compound) =
&mut children
{
if c.type_selector.is_some() {
compound.type_selector = c.type_selector.clone();
}
let mut subclass = c.subclass_selectors.clone();
self.process_subclass_selectors(prelude, &mut subclass);
compound.subclass_selectors.extend(subclass);
}
}
children
}),
);
} else {
to.children
.push(ComplexSelectorChildren::CompoundSelector(c.clone()));
}
}
fn process_subclass_selectors(
&mut self,
prelude: &SelectorList,
@ -107,14 +60,11 @@ impl NestingHandler {
) {
let mut new_selectors = vec![];
//
'complex: for complex in selectors.take() {
for compound in &complex.children {
match compound {
ComplexSelectorChildren::CompoundSelector(compound) => {
if compound.nesting_selector.is_some() {
//
for prelude_children in &prelude.children {
let mut new = ComplexSelector {
span: Default::default(),
@ -150,14 +100,128 @@ impl NestingHandler {
*selectors = new_selectors;
}
fn append_compound(
&mut self,
prelude: &SelectorList,
to: &mut ComplexSelector,
base: &ComplexSelector,
c: &CompoundSelector,
) {
if c.nesting_selector.is_some() {
let len = base.children.len();
to.children
.extend(
base.children
.iter()
.cloned()
.enumerate()
.map(|(idx, mut children)| {
if idx == len - 1 {
if let ComplexSelectorChildren::CompoundSelector(compound) =
&mut children
{
if c.type_selector.is_some() {
compound.type_selector = c.type_selector.clone();
}
let mut subclass = c.subclass_selectors.clone();
self.process_subclass_selectors(prelude, &mut subclass);
compound.subclass_selectors.extend(subclass);
}
}
children
}),
);
} else {
to.children
.push(ComplexSelectorChildren::CompoundSelector(c.clone()));
}
}
fn relative_selector_list_to_selector_list(
&mut self,
base: &SelectorList,
relative_selector_list: &RelativeSelectorList,
) -> SelectorList {
let mut children = vec![];
for base_complex in &base.children {
for relative_selector in &relative_selector_list.children {
let mut complex_selector = ComplexSelector {
span: relative_selector.span,
children: Default::default(),
};
let is_non_relative = relative_selector.combinator.is_none()
&& relative_selector.selector.children.iter().any(|s| match s {
ComplexSelectorChildren::CompoundSelector(s) => {
s.nesting_selector.is_some()
}
_ => false,
});
if let Some(combinator) = &relative_selector.combinator {
complex_selector
.children
.extend(base_complex.children.clone());
complex_selector
.children
.push(ComplexSelectorChildren::Combinator(combinator.clone()))
} else if !is_non_relative {
complex_selector
.children
.extend(base_complex.children.clone());
complex_selector
.children
.push(ComplexSelectorChildren::Combinator(Combinator {
span: DUMMY_SP,
value: CombinatorValue::Descendant,
}))
}
for relative_complex_selector_children in &relative_selector.selector.children {
match relative_complex_selector_children {
ComplexSelectorChildren::CompoundSelector(compound) => {
self.append_compound(
base,
&mut complex_selector,
base_complex,
compound,
);
}
ComplexSelectorChildren::Combinator(combinator) => {
complex_selector
.children
.push(ComplexSelectorChildren::Combinator(combinator.clone()));
}
}
}
children.push(complex_selector);
}
}
SelectorList {
span: relative_selector_list.span,
children,
}
}
/// Prepend current selector
fn process_prelude(&mut self, prelude: &QualifiedRulePrelude, to: &mut QualifiedRulePrelude) {
fn process_prelude(&mut self, base: &QualifiedRulePrelude, to: &mut QualifiedRulePrelude) {
if let (
QualifiedRulePrelude::SelectorList(prelude),
QualifiedRulePrelude::SelectorList(selectors),
) = (prelude, to)
QualifiedRulePrelude::SelectorList(base),
QualifiedRulePrelude::RelativeSelectorList(relative_selector_list),
) = (base, &to)
{
self.process_complex_selectors(prelude, &mut selectors.children);
let selector_list =
self.relative_selector_list_to_selector_list(base, relative_selector_list);
*to = QualifiedRulePrelude::SelectorList(selector_list);
}
}
@ -167,14 +231,21 @@ impl NestingHandler {
for value in rule.block.value.take() {
match value {
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(mut q)) => {
self.process_prelude(&rule.prelude, &mut q.prelude);
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(mut nested)) => {
self.process_prelude(&rule.prelude, &mut nested.prelude);
nested_rules.push(Rule::QualifiedRule(nested));
nested_rules.push(Rule::QualifiedRule(q));
continue;
}
ComponentValue::StyleBlock(StyleBlock::AtRule(ref at_rule)) => {
if let Some(AtRulePrelude::MediaPrelude(..)) = at_rule.prelude.as_deref() {
if let Some(
AtRulePrelude::MediaPrelude(..)
| AtRulePrelude::SupportsPrelude(..)
| AtRulePrelude::ContainerPrelude(..)
| AtRulePrelude::DocumentPrelude(..),
) = at_rule.prelude.as_deref()
{
if let Some(block) = &at_rule.block {
let mut decls_of_media = vec![];
let mut nested_of_media = vec![];
@ -183,6 +254,7 @@ impl NestingHandler {
match n {
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(n)) => {
let mut q = n.clone();
self.process_prelude(&rule.prelude, &mut q.prelude);
let rules = self.extract_nested_rules(&mut q);
@ -209,6 +281,7 @@ impl NestingHandler {
..block.clone()
},
});
nested_of_media.insert(
0,
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(rule)),
@ -222,6 +295,7 @@ impl NestingHandler {
}),
..*at_rule.clone()
})));
continue;
}
}
@ -231,6 +305,7 @@ impl NestingHandler {
block_values.push(value);
}
rule.block.value = block_values;
nested_rules
@ -239,13 +314,15 @@ impl NestingHandler {
impl VisitMut for NestingHandler {
fn visit_mut_rules(&mut self, n: &mut Vec<Rule>) {
n.visit_mut_children_with(self);
let mut new = vec![];
for n in n.take() {
match n {
Rule::QualifiedRule(mut n) => {
let rules = self.extract_nested_rules(&mut n);
let mut rules = self.extract_nested_rules(&mut n);
rules.visit_mut_with(self);
new.push(Rule::QualifiedRule(n));
new.extend(rules);
}
@ -254,18 +331,20 @@ impl VisitMut for NestingHandler {
}
}
}
*n = new;
}
fn visit_mut_component_values(&mut self, n: &mut Vec<ComponentValue>) {
n.visit_mut_children_with(self);
let mut new = vec![];
for n in n.take() {
match n {
ComponentValue::StyleBlock(StyleBlock::QualifiedRule(mut n)) => {
let rules = self.extract_nested_rules(&mut n);
let mut rules = self.extract_nested_rules(&mut n);
rules.visit_mut_with(self);
new.push(ComponentValue::StyleBlock(StyleBlock::QualifiedRule(n)));
new.extend(rules.into_iter().map(rule_to_component_value));
}
@ -275,6 +354,7 @@ impl VisitMut for NestingHandler {
}
}
}
*n = new;
}
}

View File

@ -67,3 +67,242 @@ figure {
color: blue;
&__bar { color: red; }
}
.foo {
color: red;
> bar {
color: green;
> baz {
color: blue;
}
}
}
.foo {
color: red;
& > bar {
color: green;
& > baz {
color: blue;
}
}
}
.foo {
color: red;
&.bar {
color: green;
&.one, &.two {
color: blue;
}
}
}
.foo {
color: red;
& > bar-1, & > bar-2 {
color: green;
> baz-1, > baz-2 {
color: blue;
}
}
}
.foo {
color: blue;
& > .bar { color: red; }
> .baz { color: green; }
}
.foo {
color: blue;
&.bar { color: red; }
}
.foo, .bar {
color: blue;
+ .baz, &.qux { color: red; }
}
.foo {
color: blue;
& .bar & .baz & .qux { color: red; }
}
.foo {
color: red;
.parent & {
color: blue;
}
}
/* TODO FIX ME */
.foo {
color: red;
:not(&) {
color: blue;
}
}
.foo {
color: red;
+ .bar + & { color: blue; }
}
.foo {
color: blue;
& { padding: 2ch; }
}
.error, #id {
&:hover > .baz { color: red; }
}
.ancestor .el {
.other-ancestor & { color: red; }
}
figure {
margin: 0;
> figcaption {
background: hsl(0 0% 0% / 50%);
> p {
font-size: .9rem;
}
}
}
/* TODO FIX ME */
@layer base {
html {
block-size: 100%;
& body {
min-block-size: 100%;
}
}
}
/* TODO FIX ME */
@layer base {
html {
block-size: 100%;
@layer base.support {
& body {
min-block-size: 100%;
}
}
}
}
.foo {
display: grid;
@media (orientation: landscape) {
grid-auto-flow: column;
}
}
/* TODO FIX ME */
.foo {
display: grid;
@media (orientation: landscape) {
grid-auto-flow: column;
@media (min-width > 1024px) {
max-inline-size: 1024px;
}
}
}
.foo {
display: grid;
@supports (grid-auto-flow: column) {
grid-auto-flow: column;
}
}
/* TODO FIX ME */
.foo {
display: grid;
@supports (grid-auto-flow: column) {
grid-auto-flow: column;
@supports (max-inline-size: 1024px) {
max-inline-size: 1024px;
}
}
}
.foo {
display: grid;
@container (min-width: 700px) {
grid-auto-flow: column;
}
}
/* TODO FIX ME */
.foo {
display: grid;
@container (min-width: 700px) {
grid-auto-flow: column;
@container (min-width: 400px) {
max-inline-size: 1024px;
}
}
}
article {
color: green;
& { color: blue; }
color: red;
}
/* TODO FIX ME */
.foo, .foo::before, .foo::after {
color: red;
&:hover { color: blue; }
}
.foo {
color: red;
.bar {
color: blue;
}
}
.foo {
color: red;
[test="test"] {
color: blue;
}
}
.foo {
color: red;
#id {
color: blue;
}
}

View File

@ -31,8 +31,8 @@ table.colortable th {
color: blue;
}
.foo + .baz,
.bar + .baz,
.foo.qux,
.bar + .baz,
.bar.qux {
color: red;
}
@ -73,3 +73,228 @@ figure > figcaption > p {
__bar.foo {
color: red;
}
.foo {
color: red;
}
.foo > bar {
color: green;
}
.foo > bar > baz {
color: blue;
}
.foo {
color: red;
}
.foo > bar {
color: green;
}
.foo > bar > baz {
color: blue;
}
.foo {
color: red;
}
.foo.bar {
color: green;
}
.foo.bar.one,
.foo.bar.two {
color: blue;
}
.foo {
color: red;
}
.foo > bar-1,
.foo > bar-2 {
color: green;
}
.foo > bar-1 > baz-1,
.foo > bar-1 > baz-2,
.foo > bar-2 > baz-1,
.foo > bar-2 > baz-2 {
color: blue;
}
.foo {
color: blue;
}
.foo > .bar {
color: red;
}
.foo > .baz {
color: green;
}
.foo {
color: blue;
}
.foo.bar {
color: red;
}
.foo,
.bar {
color: blue;
}
.foo + .baz,
.foo.qux,
.bar + .baz,
.bar.qux {
color: red;
}
.foo {
color: blue;
}
.foo .bar .foo .baz .foo .qux {
color: red;
}
.foo {
color: red;
}
.parent .foo {
color: blue;
}
.foo {
color: red;
}
.foo :not(&) {
color: blue;
}
.foo {
color: red;
}
.foo + .bar + .foo {
color: blue;
}
.foo {
color: blue;
}
.foo {
padding: 2ch;
}
.error,
#id {}
.error:hover > .baz,
#id:hover > .baz {
color: red;
}
.ancestor .el {}
.other-ancestor .ancestor .el {
color: red;
}
figure {
margin: 0;
}
figure > figcaption {
background: hsl(0 0% 0% / 50%);
}
figure > figcaption > p {
font-size: .9rem;
}
@layer base {
html {
block-size: 100%;
& body {
min-block-size: 100%;
}
}
}
@layer base {
html {
block-size: 100%;
@layer base.support {
& body {
min-block-size: 100%;
}
}
}
}
.foo {
display: grid;
}
@media (orientation: landscape) {
.foo {
grid-auto-flow: column;
}
}
.foo {
display: grid;
}
@media (orientation: landscape) {
.foo {
grid-auto-flow: column;
@media (min-width > 1024px) {
max-inline-size: 1024px;
}
}
}
.foo {
display: grid;
}
@supports (grid-auto-flow: column) {
.foo {
grid-auto-flow: column;
}
}
.foo {
display: grid;
}
@supports (grid-auto-flow: column) {
.foo {
grid-auto-flow: column;
@supports (max-inline-size: 1024px) {
max-inline-size: 1024px;
}
}
}
.foo {
display: grid;
}
@container (min-width: 700px) {
.foo {
grid-auto-flow: column;
}
}
.foo {
display: grid;
}
@container (min-width: 700px) {
.foo {
grid-auto-flow: column;
@container (min-width: 400px) {
max-inline-size: 1024px;
}
}
}
article {
color: green;
color: red;
}
article {
color: blue;
}
.foo,
.foo::before,
.foo::after {
color: red;
}
.foo:hover,
.foo::before:hover,
.foo::after:hover {
color: blue;
}
.foo {
color: red;
}
.foo .bar {
color: blue;
}
.foo {
color: red;
}
.foo [test="test"] {
color: blue;
}
.foo {
color: red;
}
.foo #id {
color: blue;
}

View File

@ -1,3 +1,8 @@
.foo {
&:is(.bar, &.baz) { color: red; }
}
}
/* TODO FIX ME */
.foo {
& :is(.bar, &.baz) { color: red; }
}

View File

@ -2,3 +2,7 @@
.foo:is(.bar, .foo.baz) {
color: red;
}
.foo {}
.foo :is(.bar, &.baz) {
color: red;
}

View File

@ -155,6 +155,21 @@ impl Compressor {
}
}
fn merge_relative_selector_list(
&self,
left: &RelativeSelectorList,
right: &RelativeSelectorList,
) -> RelativeSelectorList {
let mut children = left.children.clone();
children.extend(right.children.clone());
RelativeSelectorList {
span: Span::new(left.span_lo(), right.span_hi(), SyntaxContext::empty()),
children,
}
}
fn merge_simple_block(&self, left: &SimpleBlock, right: &SimpleBlock) -> SimpleBlock {
let mut value = left.value.clone();
@ -168,21 +183,31 @@ impl Compressor {
}
fn can_merge_qualified_rules(&self, left: &QualifiedRule, right: &QualifiedRule) -> bool {
let left_selector_list = match &left.prelude {
QualifiedRulePrelude::SelectorList(selector_list) => selector_list,
_ => return false,
};
let right_selector_list = match &right.prelude {
QualifiedRulePrelude::SelectorList(selector_list) => selector_list,
_ => return false,
};
match (&left.prelude, &right.prelude) {
(
QualifiedRulePrelude::SelectorList(left_selector_list),
QualifiedRulePrelude::SelectorList(right_selector_list),
) => {
let mut checker = CompatibilityChecker::default();
let mut checker = CompatibilityChecker::default();
left_selector_list.visit_with(&mut checker);
right_selector_list.visit_with(&mut checker);
left_selector_list.visit_with(&mut checker);
right_selector_list.visit_with(&mut checker);
checker.allow_to_merge
}
(
QualifiedRulePrelude::RelativeSelectorList(left_relative_selector_list),
QualifiedRulePrelude::RelativeSelectorList(right_relative_selector_list),
) => {
let mut checker = CompatibilityChecker::default();
checker.allow_to_merge
left_relative_selector_list.visit_with(&mut checker);
right_relative_selector_list.visit_with(&mut checker);
checker.allow_to_merge
}
_ => false,
}
}
fn try_merge_qualified_rules(
@ -197,26 +222,42 @@ impl Compressor {
// Merge when declarations are exactly equal
// e.g. h1 { color: red } h2 { color: red }
if left.block.eq_ignore_span(&right.block) {
if let (
QualifiedRulePrelude::SelectorList(prev_selector_list),
QualifiedRulePrelude::SelectorList(current_selector_list),
) = (&left.prelude, &right.prelude)
{
let selector_list =
self.merge_selector_list(prev_selector_list, current_selector_list);
let mut qualified_rule = QualifiedRule {
span: Span::new(
left.span.span_lo(),
right.span.span_lo(),
SyntaxContext::empty(),
),
prelude: QualifiedRulePrelude::SelectorList(selector_list),
block: left.block.clone(),
};
match (&left.prelude, &right.prelude) {
(
QualifiedRulePrelude::SelectorList(prev_selector_list),
QualifiedRulePrelude::SelectorList(current_selector_list),
) => {
let selector_list =
self.merge_selector_list(prev_selector_list, current_selector_list);
let mut qualified_rule = QualifiedRule {
span: Span::new(left.span_lo(), right.span_hi(), SyntaxContext::empty()),
prelude: QualifiedRulePrelude::SelectorList(selector_list),
block: left.block.clone(),
};
qualified_rule.visit_mut_children_with(self);
qualified_rule.visit_mut_children_with(self);
return Some(qualified_rule);
return Some(qualified_rule);
}
(
QualifiedRulePrelude::RelativeSelectorList(prev_relative_selector_list),
QualifiedRulePrelude::RelativeSelectorList(current_relative_selector_list),
) => {
let relative_selector_list = self.merge_relative_selector_list(
prev_relative_selector_list,
current_relative_selector_list,
);
let mut qualified_rule = QualifiedRule {
span: Span::new(left.span_lo(), right.span_hi(), SyntaxContext::empty()),
prelude: QualifiedRulePrelude::RelativeSelectorList(relative_selector_list),
block: left.block.clone(),
};
qualified_rule.visit_mut_children_with(self);
return Some(qualified_rule);
}
_ => {}
}
}
@ -225,11 +266,7 @@ impl Compressor {
if left.prelude.eq_ignore_span(&right.prelude) {
let block = self.merge_simple_block(&left.block, &right.block);
let mut qualified_rule = QualifiedRule {
span: Span::new(
left.span.span_lo(),
right.span.span_hi(),
SyntaxContext::empty(),
),
span: Span::new(left.span_lo(), right.span_hi(), SyntaxContext::empty()),
prelude: left.prelude.clone(),
block,
};

View File

@ -41,8 +41,8 @@ pub struct ParserConfig {
#[serde(default)]
pub css_modules: bool,
/// If this is `true`, the nested selectors without `&` will be parsed as
/// valid selectors
/// If this is `true`, the nested selector starts with an identifier will be
/// parsed as valid selectors (i.e. `ul { color: red; li { color: blue } }`)
///
/// Defaults to `false`.
#[serde(default)]
@ -68,6 +68,7 @@ impl Default for BlockContentsGrammar {
struct Ctx {
is_top_level: bool,
block_contents_grammar: BlockContentsGrammar,
mixed_with_declarations: bool,
in_keyframes_at_rule: bool,
in_supports_at_rule: bool,
@ -75,7 +76,6 @@ struct Ctx {
in_page_at_rule: bool,
in_container_at_rule: bool,
in_font_feature_values_at_rule: bool,
is_trying_legacy_nesting: bool,
}
#[derive(Debug, Clone)]

View File

@ -307,46 +307,34 @@ where
Ok(QualifiedRulePrelude::ListOfComponentValues(
list_of_component_values,
))
} else if p.ctx.mixed_with_declarations {
match p.parse_according_to_grammar::<RelativeSelectorList>(
&list_of_component_values,
|parser| parser.parse(),
) {
Ok(relative_selector_list) => Ok(
QualifiedRulePrelude::RelativeSelectorList(relative_selector_list),
),
Err(err) => {
p.errors.push(err);
Ok(QualifiedRulePrelude::ListOfComponentValues(
list_of_component_values,
))
}
}
} else {
match p.parse_according_to_grammar::<SelectorList>(
&list_of_component_values,
|parser| parser.parse(),
) {
Ok(selector_list) => {
if p.ctx.is_trying_legacy_nesting {
let selector_list = p
.legacy_nested_selector_list_to_modern_selector_list(
selector_list,
)?;
Ok(QualifiedRulePrelude::SelectorList(selector_list))
} else {
Ok(QualifiedRulePrelude::SelectorList(selector_list))
}
}
Ok(selector_list) => Ok(QualifiedRulePrelude::SelectorList(selector_list)),
Err(err) => {
if p.ctx.is_trying_legacy_nesting {
match p.parse_according_to_grammar::<RelativeSelectorList>(
&list_of_component_values,
|parser| parser.parse(),
) {
Ok(relative_selector_list) => {
let selector_list = p
.legacy_relative_selector_list_to_modern_selector_list(
relative_selector_list,
)?;
p.errors.push(err);
Ok(QualifiedRulePrelude::SelectorList(selector_list))
}
_ => Err(err),
}
} else {
p.errors.push(err);
Ok(QualifiedRulePrelude::ListOfComponentValues(
list_of_component_values,
))
}
Ok(QualifiedRulePrelude::ListOfComponentValues(
list_of_component_values,
))
}
}
}
@ -369,6 +357,21 @@ where
}
match cur!(self) {
// <semicolon-token>
// If mixed with declarations is true, this is a parse error; return nothing.
// Otherwise, append a <semicolon-token> to the qualified rules prelude.
tok!(";") => {
if self.ctx.mixed_with_declarations {
return Err(Error::new(
span!(self, span.lo),
ErrorKind::EofButExpected("'{'"),
));
} else {
let component_value = self.parse_as::<ComponentValue>()?;
prelude.push(component_value);
}
}
// <{-token>
// Consume a simple block and assign it to the qualified rules block. Return the
// qualified rule.
@ -466,13 +469,23 @@ where
rules.push(StyleBlock::AtRule(Box::new(at_rule)));
}
// <ident-token>
// Initialize a temporary list initially filled with the current input token. As
// long as the next input token is anything other than a <semicolon-token> or
// <function-token>
// <function>
//
// Reconsume the current input token. Initialize a temporary list, initially empty.
// As long as the next input token is anything other than a <semicolon-token> or
// <EOF-token>, consume a component value and append it to the temporary list.
// Consume a declaration from the temporary list. If anything was returned, append
// it to decls.
tok!("ident") => {
if self.config.legacy_nesting {
tok!("ident") | tok!("function") => {
// Legacy nested parsing conflict with custom properties, but selectors can't
// start with `--`, so it is safe to ignore them.
//
// Constructions like `a { prop: {value}; }` still affected this problem, but
// `{`/`}` doesn't used in declarations
if self.config.legacy_nesting
&& matches!(self.input.cur(), Some(Token::Ident { value, .. }) if !value.starts_with("--"))
{
if let Some(legacy_nested) = self.try_to_parse_legacy_nesting() {
rules.push(StyleBlock::QualifiedRule(Box::new(legacy_nested)));
@ -508,82 +521,48 @@ where
declarations.push(decl_or_list_of_component_values);
}
// <delim-token> with a value of "&" (U+0026 AMPERSAND)
// Reconsume the current input token. Consume a qualified rule. If anything was
// returned, append it to rules.
tok!("&") => {
// anything else
// Reconsume the current input token. Consume a qualified rule, with mixed with
// declarations set to true. If anything was returned, append it to rules.
_ => {
let state = self.input.state();
let qualified_rule = match self.parse() {
Ok(v) => StyleBlock::QualifiedRule(v),
let qualified_rule = self
.with_ctx(Ctx {
mixed_with_declarations: true,
..self.ctx
})
.parse_as::<Box<QualifiedRule>>();
match qualified_rule {
Ok(i) => rules.push(StyleBlock::QualifiedRule(i)),
Err(err) => {
self.errors.push(err);
self.input.reset(&state);
let span = self.input.cur_span();
let mut children = vec![];
while !is_one_of!(self, EOF, "}") {
if let Some(token_and_span) = self.input.bump() {
children.push(ComponentValue::PreservedToken(token_and_span));
}
self.errors
.push(Error::new(span, ErrorKind::Unexpected("token")));
if is!(self, ";") {
if let Some(token_and_span) = self.input.bump() {
children
.push(ComponentValue::PreservedToken(token_and_span));
}
// For recovery mode
let mut list_of_component_values = ListOfComponentValues {
span: Default::default(),
children: vec![],
};
break;
}
// TODO verify error recovery (copied from prev spec)
while !is_one_of!(self, ";", EOF) {
let component_value = self.parse_as::<ComponentValue>()?;
list_of_component_values.children.push(component_value);
}
StyleBlock::ListOfComponentValues(ListOfComponentValues {
span: span!(self, span.lo),
children,
})
list_of_component_values.span = span!(self, span.lo);
declarations
.push(StyleBlock::ListOfComponentValues(list_of_component_values));
}
};
rules.push(qualified_rule);
}
// anything else
// This is a parse error. Reconsume the current input token. As long as the next
// input token is anything other than a <semicolon-token> or <EOF-token>, consume a
// component value and throw away the returned value.
_ => {
if self.config.legacy_nesting {
if let Some(legacy_nested) = self.try_to_parse_legacy_nesting() {
rules.push(StyleBlock::QualifiedRule(Box::new(legacy_nested)));
continue;
}
}
let span = self.input.cur_span();
self.errors.push(Error::new(
span,
ErrorKind::Expected(
"whitespace, semicolon, EOF, at-keyword, '&' or ident token",
),
));
// For recovery mode
let mut list_of_component_values = ListOfComponentValues {
span: Default::default(),
children: vec![],
};
while !is_one_of!(self, ";", EOF) {
let component_value = self.parse_as::<ComponentValue>()?;
list_of_component_values.children.push(component_value);
}
list_of_component_values.span = span!(self, span.lo);
declarations.push(StyleBlock::ListOfComponentValues(list_of_component_values));
}
}
}
@ -720,9 +699,21 @@ where
fn parse(&mut self) -> PResult<Declaration> {
// To consume a declaration:
// Consume the next input token. Create a new declaration with its name set
// to the value of the current input token and its value initially set to an
// empty list.
// Let decl be a new declaration, with an initially empty name and a value set
// to an empty list.
// TODO improve me
// Consume a component value.
// <ident-token>
// Set decls name to the value of the <ident-token>.
//
// anything else
// This is a parse error.
//
// While the next input token is anything but a <semicolon-token> or
// <eof-token>, consume a component value and throw it away.
//
// Return nothing.
let span = self.input.cur_span();
let is_dashed_ident = match cur!(self) {
Token::Ident { value, .. } => value.starts_with("--"),
@ -742,19 +733,19 @@ where
important: None,
};
// 1. While the next input token is a <whitespace-token>, consume the next input
// 2. While the next input token is a <whitespace-token>, consume the next input
// token.
self.input.skip_ws();
// 2. If the next input token is anything other than a <colon-token>, this is a
// 3. If the next input token is anything other than a <colon-token>, this is a
// parse error. Return nothing. Otherwise, consume the next input token.
expect!(self, ":");
// 3. While the next input token is a <whitespace-token>, consume the next input
// 4. While the next input token is a <whitespace-token>, consume the next input
// token.
self.input.skip_ws();
// 4. As long as the next input token is anything other than an <EOF-token>,
// 5. As long as the next input token is anything other than an <EOF-token>,
// consume a component value and append it to the declarations value.
let mut last_whitespaces = (0, 0, 0);
let mut exclamation_point_span = None;
@ -840,7 +831,7 @@ where
declaration.value.push(component_value);
}
// 5. If the last two non-<whitespace-token>s in the declarations value are a
// 6. If the last two non-<whitespace-token>s in the declarations value are a
// <delim-token> with the value "!" followed by an <ident-token> with a value
// that is an ASCII case-insensitive match for "important", remove them from the
// declarations value and set the declarations important flag to true.
@ -867,7 +858,7 @@ where
declaration.important = Some(ImportantFlag { span, value });
}
// 6. While the last token in the declarations value is a <whitespace-token>,
// 7. While the last token in the declarations value is a <whitespace-token>,
// remove that token.
let len = if declaration.important.is_some() {
declaration.value.len()
@ -884,7 +875,7 @@ where
if is_dashed_ident {
// Don't parse custom properties
//
// 7. Return the declaration.
// 8. Return the declaration.
return Ok(declaration);
}
@ -914,7 +905,7 @@ where
}
};
// 7. Return the declaration.
// 8. Return the declaration.
Ok(declaration)
}
}

View File

@ -73,11 +73,12 @@ where
pub(super) fn try_to_parse_legacy_nesting(&mut self) -> Option<QualifiedRule> {
let state = self.input.state();
let ctx = Ctx {
is_trying_legacy_nesting: true,
..self.ctx
};
let qualified_rule = self.with_ctx(ctx).parse_as::<QualifiedRule>();
let qualified_rule = self
.with_ctx(Ctx {
mixed_with_declarations: true,
..self.ctx
})
.parse_as::<QualifiedRule>();
match qualified_rule {
Ok(qualified_rule) => Some(qualified_rule),
@ -88,84 +89,6 @@ where
}
}
}
pub(super) fn legacy_nested_selector_list_to_modern_selector_list(
&mut self,
mut selector_list: SelectorList,
) -> PResult<SelectorList> {
for s in selector_list.children.iter_mut() {
if s.children.iter().any(|s| match s {
ComplexSelectorChildren::CompoundSelector(s) => s.nesting_selector.is_some(),
_ => false,
}) {
continue;
}
s.children.insert(
0,
ComplexSelectorChildren::CompoundSelector(CompoundSelector {
span: DUMMY_SP,
nesting_selector: Some(NestingSelector { span: DUMMY_SP }),
type_selector: Default::default(),
subclass_selectors: Default::default(),
}),
);
s.children.insert(
1,
ComplexSelectorChildren::Combinator(Combinator {
span: DUMMY_SP,
value: CombinatorValue::Descendant,
}),
);
}
Ok(selector_list)
}
pub(super) fn legacy_relative_selector_list_to_modern_selector_list(
&mut self,
relative_selector_list: RelativeSelectorList,
) -> PResult<SelectorList> {
let mut selector_list = SelectorList {
span: relative_selector_list.span,
children: Vec::with_capacity(relative_selector_list.children.len()),
};
for relative_selector in relative_selector_list.children.into_iter() {
let mut complex_selector = relative_selector.selector.clone();
complex_selector.children.insert(
0,
ComplexSelectorChildren::CompoundSelector(CompoundSelector {
span: DUMMY_SP,
nesting_selector: Some(NestingSelector { span: DUMMY_SP }),
type_selector: Default::default(),
subclass_selectors: Default::default(),
}),
);
match relative_selector.combinator {
Some(combinator) => {
complex_selector
.children
.insert(1, ComplexSelectorChildren::Combinator(combinator));
}
_ => {
complex_selector.children.insert(
1,
ComplexSelectorChildren::Combinator(Combinator {
span: DUMMY_SP,
value: CombinatorValue::Descendant,
}),
);
}
}
selector_list.children.push(complex_selector);
}
Ok(selector_list)
}
}
pub(super) struct WithCtx<'w, I: 'w + ParserInput> {

View File

@ -1033,7 +1033,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 295,
"end": 300,
@ -1041,51 +1041,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 295,
"end": 300,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 295,
"end": 300,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 295,
"end": 300,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 295,
"end": 296,
"end": 300,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 296,
"end": 300,
"start": 295,
"end": 296,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 297,
"start": 296,
"end": 300,
"ctxt": 0
},
"value": "baz",
"raw": "baz"
"text": {
"type": "Ident",
"span": {
"start": 297,
"end": 300,
"ctxt": 0
},
"value": "baz",
"raw": "baz"
}
}
}
]
}
]
]
}
]
}
}
]
},

View File

@ -1115,7 +1115,13 @@
29 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/at-rule/nest/input.css:27:9]
27 | &.baz {
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/at-rule/nest/input.css:27:9]
27 | &.baz {
: ^^^^^

View File

@ -67,3 +67,110 @@ figure {
color: blue;
&__bar { color: red; }
}
.foo {
color: red;
.bar {
color: blue;
}
}
.foo {
color: red;
+ .bar {
color: blue;
}
}
.foo {
color: blue;
& > .bar { color: red; }
> .baz { color: green; }
}
div {
color: red;
& input { margin: 1em; }
/* valid, no longer starts with an identifier */
:is(input) { margin: 1em; }
/* valid, starts with a colon,
and equivalent to the previous rule. */
}
.foo, .bar {
color: blue;
+ .baz, &.qux { color: red; }
}
.foo {
color: blue;
& .bar & .baz & .qux { color: red; }
}
.foo {
color: red;
.parent & {
color: blue;
}
}
.foo {
color: red;
:not(&) {
color: blue;
}
}
.foo {
color: red;
+ .bar + & { color: blue; }
}
.ancestor .el {
.other-ancestor & { color: red; }
}
.foo {
& :is(.bar, &.baz) { color: red; }
}
@layer base {
html {
block-size: 100%;
& body {
min-block-size: 100%;
}
}
}
@layer base {
html {
block-size: 100%;
@layer base.support {
& body {
min-block-size: 100%;
}
}
}
}
article {
color: green;
& { color: blue; }
color: red;
}
.foo {
color: red;
@media (min-width: 480px) {
& h1, & h2 {
color: blue;
}
}
}

View File

@ -1164,7 +1164,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 477,
"end": 487,
@ -1172,152 +1172,170 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 477,
"end": 481,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 477,
"end": 478,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 477,
"end": 481,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 477,
"end": 478,
"ctxt": 0
}
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 477,
"end": 478,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 478,
"end": 479,
"ctxt": 0
{
"type": "Combinator",
"span": {
"start": 478,
"end": 479,
"ctxt": 0
},
"value": " "
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 479,
"end": 481,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": {
"type": "TagNameSelector",
{
"type": "CompoundSelector",
"span": {
"start": 479,
"end": 481,
"ctxt": 0
},
"name": {
"type": "WqName",
"nestingSelector": null,
"typeSelector": {
"type": "TagNameSelector",
"span": {
"start": 479,
"end": 481,
"ctxt": 0
},
"prefix": null,
"value": {
"type": "Ident",
"name": {
"type": "WqName",
"span": {
"start": 479,
"end": 481,
"ctxt": 0
},
"value": "h1",
"raw": "h1"
"prefix": null,
"value": {
"type": "Ident",
"span": {
"start": 479,
"end": 481,
"ctxt": 0
},
"value": "h1",
"raw": "h1"
}
}
}
},
"subclassSelectors": []
}
]
},
"subclassSelectors": []
}
]
}
},
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 483,
"end": 487,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 483,
"end": 484,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 483,
"end": 487,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 483,
"end": 484,
"ctxt": 0
}
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 483,
"end": 484,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 484,
"end": 485,
"ctxt": 0
{
"type": "Combinator",
"span": {
"start": 484,
"end": 485,
"ctxt": 0
},
"value": " "
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 485,
"end": 487,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": {
"type": "TagNameSelector",
{
"type": "CompoundSelector",
"span": {
"start": 485,
"end": 487,
"ctxt": 0
},
"name": {
"type": "WqName",
"nestingSelector": null,
"typeSelector": {
"type": "TagNameSelector",
"span": {
"start": 485,
"end": 487,
"ctxt": 0
},
"prefix": null,
"value": {
"type": "Ident",
"name": {
"type": "WqName",
"span": {
"start": 485,
"end": 487,
"ctxt": 0
},
"value": "h2",
"raw": "h2"
"prefix": null,
"value": {
"type": "Ident",
"span": {
"start": 485,
"end": 487,
"ctxt": 0
},
"value": "h2",
"raw": "h2"
}
}
}
},
"subclassSelectors": []
}
]
},
"subclassSelectors": []
}
]
}
}
]
},
@ -1584,7 +1602,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 594,
"end": 602,
@ -1592,71 +1610,80 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 594,
"end": 602,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 594,
"end": 595,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 594,
"end": 602,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 594,
"end": 595,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 595,
"end": 596,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 596,
"end": 602,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 596,
"end": 602,
"start": 594,
"end": 595,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 595,
"end": 596,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 596,
"end": 602,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 597,
"start": 596,
"end": 602,
"ctxt": 0
},
"value": "class",
"raw": "class"
"text": {
"type": "Ident",
"span": {
"start": 597,
"end": 602,
"ctxt": 0
},
"value": "class",
"raw": "class"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -1954,7 +1981,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 725,
"end": 733,
@ -1962,71 +1989,80 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 725,
"end": 733,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 725,
"end": 726,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 725,
"end": 733,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 725,
"end": 726,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 726,
"end": 727,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 727,
"end": 733,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 727,
"end": 733,
"start": 725,
"end": 726,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 726,
"end": 727,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 727,
"end": 733,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 728,
"start": 727,
"end": 733,
"ctxt": 0
},
"value": "class",
"raw": "class"
"text": {
"type": "Ident",
"span": {
"start": 728,
"end": 733,
"ctxt": 0
},
"value": "class",
"raw": "class"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -2200,7 +2236,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 789,
"end": 794,
@ -2208,51 +2244,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 789,
"end": 794,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 789,
"end": 794,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 789,
"end": 794,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 789,
"end": 790,
"end": 794,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 790,
"end": 794,
"start": 789,
"end": 790,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 791,
"start": 790,
"end": 794,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 791,
"end": 794,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -2439,7 +2484,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 895,
"end": 903,
@ -2447,71 +2492,80 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 895,
"end": 903,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 895,
"end": 896,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 895,
"end": 903,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 895,
"end": 896,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 896,
"end": 897,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 897,
"end": 903,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 897,
"end": 903,
"start": 895,
"end": 896,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 896,
"end": 897,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 897,
"end": 903,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 898,
"start": 897,
"end": 903,
"ctxt": 0
},
"value": "class",
"raw": "class"
"text": {
"type": "Ident",
"span": {
"start": 898,
"end": 903,
"ctxt": 0
},
"value": "class",
"raw": "class"
}
}
}
]
}
]
]
}
]
}
}
]
},

View File

@ -1456,12 +1456,18 @@
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/style-block/input.css:33:9]
33 | & h1, & h2 { color: blue; }
: ^^^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:33:9]
33 | & h1, & h2 { color: blue; }
: ^^^^
`----
x ComplexSelector
,-[$DIR/tests/fixture/style-block/input.css:33:9]
33 | & h1, & h2 { color: blue; }
@ -1516,6 +1522,12 @@
: ^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:33:9]
33 | & h1, & h2 { color: blue; }
: ^^^^
`----
x ComplexSelector
,-[$DIR/tests/fixture/style-block/input.css:33:9]
33 | & h1, & h2 { color: blue; }
@ -1879,7 +1891,13 @@
: ^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/style-block/input.css:41:9]
41 | & .class { color: red }
: ^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:41:9]
41 | & .class { color: red }
: ^^^^^^^^
@ -2290,7 +2308,13 @@
: ^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/style-block/input.css:51:9]
51 | & .class { color: red }
: ^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:51:9]
51 | & .class { color: red }
: ^^^^^^^^
@ -2554,7 +2578,13 @@
60 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/style-block/input.css:58:5]
58 | &.foo {
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:58:5]
58 | &.foo {
: ^^^^^
@ -2831,7 +2861,13 @@
: ^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/fixture/style-block/input.css:65:9]
65 | & .class { color: red }
: ^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/fixture/style-block/input.css:65:9]
65 | & .class { color: red }
: ^^^^^^^^

View File

@ -1,24 +1,54 @@
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:5:1]
5 | <!--
: ^^^^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:14:1]
14 | <!--
: ^^^^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:25:1]
25 | <!--
: ^^^^
`----
x Invalid selector
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:1:1]
1 | <!-- 123 -->
: ^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:5:1]
5 | ,-> <!--
6 | |
7 | | test
8 | |
9 | `-> -->
10 | }
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:14:1]
14 | ,-> <!--
15 | |
16 | | test
17 | |
18 | | -->
19 | |
20 | `-> color: blue;
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:25:1]
25 | ,-> <!--
26 | |
27 | | test
28 | |
29 | `-> -->;
`----
x Unexpected token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:5:1]
5 | <!--
: ^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:14:1]
14 | <!--
: ^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/cdo-and-cdc/input.css:25:1]
25 | <!--
: ^^^^
`----

View File

@ -8522,37 +8522,6 @@
"token": "LBrace"
},
"value": [
{
"type": "Declaration",
"span": {
"start": 2568,
"end": 2578,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 2568,
"end": 2573,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"value": [
{
"type": "Ident",
"span": {
"start": 2575,
"end": 2578,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
},
{
"type": "ListOfComponentValues",
"span": {
@ -8634,6 +8603,37 @@
"token": "Semi"
}
]
},
{
"type": "Declaration",
"span": {
"start": 2568,
"end": 2578,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 2568,
"end": 2573,
"ctxt": 0
},
"value": "color",
"raw": "color"
},
"value": [
{
"type": "Ident",
"span": {
"start": 2575,
"end": 2578,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}

View File

@ -11,173 +11,334 @@
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:13:1]
13 | .selector { (;property: value;); }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:14:1]
14 | .selector { [;property: value;]; }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:104:5]
104 | !property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:108:5]
108 | $property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:116:5]
116 | *property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:120:5]
120 | )property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:124:5]
124 | =property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:128:5]
128 | %property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:132:5]
132 | +property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:140:5]
140 | ,property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:144:5]
144 | .property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:148:5]
148 | /property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:152:5]
152 | `property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:156:5]
156 | ]property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:160:5]
160 | #property: value;
: ^^^^^^^^^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:164:5]
164 | ~property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:168:5]
168 | ?property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:172:5]
172 | :property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:176:5]
176 | |property: value;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:204:1]
204 | .selector { (;property: value;); }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:205:1]
205 | .selector { [;property: value;]; }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:225:1]
225 | .selector { (;property: value;); }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:226:1]
226 | .selector { [;property: value;]; }
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:244:5]
244 | *color : black;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:247:5]
247 | $(var)-size: 100%;
: ^
`----
x Expected whitespace, semicolon, EOF, at-keyword, '&' or ident token
,-[$DIR/tests/recovery/hacks/input.css:250:1]
250 | a{*b:c}
: ^
`----
x Unexpected '!' in <declaration-value>
,-[$DIR/tests/recovery/hacks/input.css:180:1]
180 | .selector { property: value !ie; }
: ^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:13:1]
13 | .selector { (;property: value;); }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:14:1]
14 | .selector { [;property: value;]; }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:104:5]
104 | !property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:108:5]
108 | $property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:112:5]
112 | ,-> &property: value;
113 | `-> color: red;
114 | }
112 | &property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:116:5]
116 | *property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:120:5]
120 | )property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:124:5]
124 | =property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:128:5]
128 | %property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:132:5]
132 | +property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:140:5]
140 | ,property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:144:5]
144 | .property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:148:5]
148 | /property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:152:5]
152 | `property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:156:5]
156 | ]property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:160:5]
160 | #property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:164:5]
164 | ~property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:168:5]
168 | ?property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:172:5]
172 | :property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:176:5]
176 | |property: value;
: ^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:204:1]
204 | .selector { (;property: value;); }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:205:1]
205 | .selector { [;property: value;]; }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:225:1]
225 | .selector { (;property: value;); }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:226:1]
226 | .selector { [;property: value;]; }
: ^^^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:244:5]
244 | *color : black;
: ^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:247:5]
247 | $(var)-size: 100%;
: ^^^^^^^^^^^^^^^^^
`----
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/hacks/input.css:250:1]
250 | a{*b:c}
: ^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:13:1]
13 | .selector { (;property: value;); }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:14:1]
14 | .selector { [;property: value;]; }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:104:5]
104 | !property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:108:5]
108 | $property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:112:5]
112 | &property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:116:5]
116 | *property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:120:5]
120 | )property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:124:5]
124 | =property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:128:5]
128 | %property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:132:5]
132 | +property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:140:5]
140 | ,property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:144:5]
144 | .property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:148:5]
148 | /property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:152:5]
152 | `property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:156:5]
156 | ]property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:160:5]
160 | #property: value;
: ^^^^^^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:164:5]
164 | ~property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:168:5]
168 | ?property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:172:5]
172 | :property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:176:5]
176 | |property: value;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:204:1]
204 | .selector { (;property: value;); }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:205:1]
205 | .selector { [;property: value;]; }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:225:1]
225 | .selector { (;property: value;); }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:226:1]
226 | .selector { [;property: value;]; }
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:244:5]
244 | *color : black;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:247:5]
247 | $(var)-size: 100%;
: ^
`----
x Unexpected token
,-[$DIR/tests/recovery/hacks/input.css:250:1]
250 | a{*b:c}
: ^
`----
x Unexpected tokens in at-rule prelude

View File

@ -8227,48 +8227,6 @@
: ^
`----
x ComponentValue
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x StyleBlock
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x Declaration
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x DeclarationName
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^
`----
x Ident
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/hacks/input.css:112:5]
112 | &property: value;
@ -8353,6 +8311,48 @@
: ^
`----
x ComponentValue
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x StyleBlock
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x Declaration
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^^^^^^
`----
x DeclarationName
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^
`----
x Ident
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/hacks/input.css:113:5]
113 | color: red;
: ^^^
`----
x Rule
,-[$DIR/tests/recovery/hacks/input.css:115:1]
115 | ,-> .selector {

View File

@ -119,7 +119,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 32,
"end": 37,
@ -127,51 +127,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 32,
"end": 37,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 32,
"end": 37,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 32,
"end": 37,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 32,
"end": 33,
"end": 37,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 33,
"end": 37,
"start": 32,
"end": 33,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 34,
"start": 33,
"end": 37,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 34,
"end": 37,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -423,7 +432,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 150,
"end": 158,
@ -431,71 +440,80 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 150,
"end": 158,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 150,
"end": 151,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 150,
"end": 158,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 150,
"end": 151,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 151,
"end": 152,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 152,
"end": 158,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 152,
"end": 158,
"start": 150,
"end": 151,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 151,
"end": 152,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 152,
"end": 158,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 153,
"start": 152,
"end": 158,
"ctxt": 0
},
"value": "class",
"raw": "class"
"text": {
"type": "Ident",
"span": {
"start": 153,
"end": 158,
"ctxt": 0
},
"value": "class",
"raw": "class"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -738,7 +756,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 254,
"end": 259,
@ -746,51 +764,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 254,
"end": 259,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 254,
"end": 259,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 254,
"end": 259,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 254,
"end": 255,
"end": 259,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 255,
"end": 259,
"start": 254,
"end": 255,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 256,
"start": 255,
"end": 259,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 256,
"end": 259,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -1010,7 +1037,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 373,
"end": 381,
@ -1018,71 +1045,80 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 373,
"end": 381,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 373,
"end": 374,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 373,
"end": 381,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 373,
"end": 374,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 374,
"end": 375,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 375,
"end": 381,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 375,
"end": 381,
"start": 373,
"end": 374,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": []
},
{
"type": "Combinator",
"span": {
"start": 374,
"end": 375,
"ctxt": 0
},
"value": " "
},
{
"type": "CompoundSelector",
"span": {
"start": 375,
"end": 381,
"ctxt": 0
},
"nestingSelector": null,
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 376,
"start": 375,
"end": 381,
"ctxt": 0
},
"value": "class",
"raw": "class"
"text": {
"type": "Ident",
"span": {
"start": 376,
"end": 381,
"ctxt": 0
},
"value": "class",
"raw": "class"
}
}
}
]
}
]
]
}
]
}
}
]
},
@ -1425,7 +1461,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 499,
"end": 504,
@ -1433,51 +1469,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 499,
"end": 504,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 499,
"end": 504,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 499,
"end": 504,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 499,
"end": 500,
"end": 504,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 500,
"end": 504,
"start": 499,
"end": 500,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 501,
"start": 500,
"end": 504,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 501,
"end": 504,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},

View File

@ -32,6 +32,11 @@
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:39:5]
39 | & test;
: ^^^^^^^^
40 | }
: ^^^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:39:5]
39 | & test;
: ^
`----

View File

@ -221,7 +221,13 @@
7 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:4:5]
4 | &.foo {
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:4:5]
4 | &.foo {
: ^^^^^
@ -572,7 +578,13 @@
15 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:12:9]
12 | & .class {
: ^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:12:9]
12 | & .class {
: ^^^^^^^^
@ -911,7 +923,13 @@
25 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:22:5]
22 | &.foo {
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:22:5]
22 | &.foo {
: ^^^^^
@ -1243,7 +1261,13 @@
33 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:30:9]
30 | & .class {
: ^^^^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:30:9]
30 | & .class {
: ^^^^^^^^
@ -1647,7 +1671,13 @@
46 | `-> }
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:44:5]
44 | &.foo {
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/basic/input.css:44:5]
44 | &.foo {
: ^^^^^

View File

@ -111,37 +111,6 @@
],
"important": null
},
{
"type": "Declaration",
"span": {
"start": 42,
"end": 58,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 42,
"end": 52,
"ctxt": 0
},
"value": "background",
"raw": "background"
},
"value": [
{
"type": "Ident",
"span": {
"start": 54,
"end": 57,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
},
{
"type": "ListOfComponentValues",
"span": {
@ -200,6 +169,37 @@
"token": "Semi"
}
]
},
{
"type": "Declaration",
"span": {
"start": 42,
"end": 58,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 42,
"end": 52,
"ctxt": 0
},
"value": "background",
"raw": "background"
},
"value": [
{
"type": "Ident",
"span": {
"start": 54,
"end": 57,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}
@ -355,7 +355,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 93,
"end": 94,
@ -363,32 +363,41 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 93,
"end": 94,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 93,
"end": 94,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 93,
"end": 94,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 93,
"end": 94,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
}
]
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 93,
"end": 94,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
}
]
}
}
]
},
@ -451,7 +460,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 132,
"end": 137,
@ -459,51 +468,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 132,
"end": 137,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 132,
"end": 137,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 132,
"end": 137,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 132,
"end": 133,
"end": 137,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 133,
"end": 137,
"start": 132,
"end": 133,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 134,
"start": 133,
"end": 137,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 134,
"end": 137,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},

View File

@ -1,7 +1,12 @@
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:3:5]
3 | ,-> & test;
4 | `-> background: red
5 | }
3 | & test;
: ^^^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:3:5]
3 | & test;
: ^
`----

View File

@ -126,51 +126,6 @@
: ^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x StyleBlock
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x Declaration
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x DeclarationName
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:3:5]
3 | & test;
@ -231,6 +186,51 @@
: ^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x StyleBlock
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x Declaration
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^^^^^^^
5 | }
`----
x DeclarationName
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^^^^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:4:5]
4 | background: red
: ^^^
`----
x Rule
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:7:1]
7 | ,-> article {
@ -411,7 +411,13 @@
: ^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:9:5]
9 | & { color: blue; }
: ^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:9:5]
9 | & { color: blue; }
: ^
@ -507,7 +513,13 @@
: ^^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:11:5]
11 | &.foo { color: yellow; } /* valid! */
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested-2/input.css:11:5]
11 | &.foo { color: yellow; } /* valid! */
: ^^^^^

View File

@ -111,37 +111,6 @@
],
"important": null
},
{
"type": "Declaration",
"span": {
"start": 42,
"end": 57,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 42,
"end": 52,
"ctxt": 0
},
"value": "background",
"raw": "background"
},
"value": [
{
"type": "Ident",
"span": {
"start": 54,
"end": 57,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
},
{
"type": "ListOfComponentValues",
"span": {
@ -200,6 +169,37 @@
"token": "Semi"
}
]
},
{
"type": "Declaration",
"span": {
"start": 42,
"end": 57,
"ctxt": 0
},
"name": {
"type": "Ident",
"span": {
"start": 42,
"end": 52,
"ctxt": 0
},
"value": "background",
"raw": "background"
},
"value": [
{
"type": "Ident",
"span": {
"start": 54,
"end": 57,
"ctxt": 0
},
"value": "red",
"raw": "red"
}
],
"important": null
}
]
}
@ -355,7 +355,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 94,
"end": 95,
@ -363,32 +363,41 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 94,
"end": 95,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 94,
"end": 95,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 94,
"end": 95,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 94,
"end": 95,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
}
]
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 94,
"end": 95,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": []
}
]
}
}
]
},
@ -451,7 +460,7 @@
"ctxt": 0
},
"prelude": {
"type": "SelectorList",
"type": "RelativeSelectorList",
"span": {
"start": 133,
"end": 138,
@ -459,51 +468,60 @@
},
"children": [
{
"type": "ComplexSelector",
"type": "RelativeSelector",
"span": {
"start": 133,
"end": 138,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 133,
"end": 138,
"ctxt": 0
},
"nestingSelector": {
"type": "NestingSelector",
"combinator": null,
"selector": {
"type": "ComplexSelector",
"span": {
"start": 133,
"end": 138,
"ctxt": 0
},
"children": [
{
"type": "CompoundSelector",
"span": {
"start": 133,
"end": 134,
"end": 138,
"ctxt": 0
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
},
"nestingSelector": {
"type": "NestingSelector",
"span": {
"start": 134,
"end": 138,
"start": 133,
"end": 134,
"ctxt": 0
},
"text": {
"type": "Ident",
}
},
"typeSelector": null,
"subclassSelectors": [
{
"type": "ClassSelector",
"span": {
"start": 135,
"start": 134,
"end": 138,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
"text": {
"type": "Ident",
"span": {
"start": 135,
"end": 138,
"ctxt": 0
},
"value": "foo",
"raw": "foo"
}
}
}
]
}
]
]
}
]
}
}
]
},

View File

@ -1,7 +1,12 @@
x Unexpected end of file, but expected '{'
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:3:5]
3 | ,-> & test;
4 | `-> background: red;
5 | }
3 | & test;
: ^^^^^^
`----
x Unexpected token
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:3:5]
3 | & test;
: ^
`----

View File

@ -126,48 +126,6 @@
: ^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x StyleBlock
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x Declaration
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x DeclarationName
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:3:5]
3 | & test;
@ -228,6 +186,48 @@
: ^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x StyleBlock
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x Declaration
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^^^^^^
`----
x DeclarationName
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^^^^^^^^
`----
x ComponentValue
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^
`----
x Ident
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:4:5]
4 | background: red;
: ^^^
`----
x Rule
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:7:1]
7 | ,-> article {
@ -408,7 +408,13 @@
: ^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:9:5]
9 | & { color: blue; }
: ^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:9:5]
9 | & { color: blue; }
: ^
@ -504,7 +510,13 @@
: ^^^^^^^^^^^^^^^^^^^^^^^^
`----
x SelectorList
x RelativeSelectorList
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:11:5]
11 | &.foo { color: yellow; } /* valid! */
: ^^^^^
`----
x RelativeSelector
,-[$DIR/tests/recovery/style-blocks-contents/invalid-nested/input.css:11:5]
11 | &.foo { color: yellow; } /* valid! */
: ^^^^^

View File

@ -119,8 +119,9 @@ define!({
}
pub enum QualifiedRulePrelude {
ListOfComponentValues(ListOfComponentValues),
SelectorList(SelectorList),
RelativeSelectorList(RelativeSelectorList),
ListOfComponentValues(ListOfComponentValues),
}
pub enum StyleBlock {