allow !optional
in @extend
This commit is contained in:
parent
5634681fa2
commit
67cbf9591a
@ -15,7 +15,10 @@ use crate::{
|
||||
ComplexSelectorComponent, ExtendRule, ExtendedSelector, Extender, Selector, SelectorParser,
|
||||
},
|
||||
style::Style,
|
||||
utils::{read_until_closing_curly_brace, read_until_semicolon_or_closing_curly_brace},
|
||||
utils::{
|
||||
peek_ident_no_interpolation, read_until_closing_curly_brace,
|
||||
read_until_semicolon_or_closing_curly_brace,
|
||||
},
|
||||
value::Value,
|
||||
Options, {Cow, Token},
|
||||
};
|
||||
@ -269,6 +272,7 @@ impl<'a> Parser<'a> {
|
||||
self.at_root = false;
|
||||
let selector = self
|
||||
.parse_selector(!self.super_selectors.is_empty(), false, init)?
|
||||
.0
|
||||
.resolve_parent_selectors(
|
||||
self.super_selectors.last(),
|
||||
!at_root || self.at_root_has_selector,
|
||||
@ -299,7 +303,7 @@ impl<'a> Parser<'a> {
|
||||
allows_parent: bool,
|
||||
from_fn: bool,
|
||||
mut string: String,
|
||||
) -> SassResult<Selector> {
|
||||
) -> SassResult<(Selector, bool)> {
|
||||
let mut span = if let Some(tok) = self.toks.peek() {
|
||||
tok.pos()
|
||||
} else {
|
||||
@ -310,6 +314,8 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let mut found_curly = false;
|
||||
|
||||
let mut optional = false;
|
||||
|
||||
// we resolve interpolation and strip comments
|
||||
while let Some(tok) = self.toks.next() {
|
||||
span = span.merge(tok.pos());
|
||||
@ -333,6 +339,16 @@ impl<'a> Parser<'a> {
|
||||
found_curly = true;
|
||||
break;
|
||||
}
|
||||
'!' => {
|
||||
if peek_ident_no_interpolation(self.toks, false, self.span_before)?.node
|
||||
== "optional"
|
||||
{
|
||||
self.toks.truncate_iterator_to_cursor();
|
||||
optional = true;
|
||||
} else {
|
||||
string.push('!');
|
||||
}
|
||||
}
|
||||
c => string.push(c),
|
||||
}
|
||||
}
|
||||
@ -368,7 +384,7 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
.parse()?;
|
||||
|
||||
Ok(Selector(selector))
|
||||
Ok((Selector(selector), optional))
|
||||
}
|
||||
|
||||
/// Eat and return the contents of a comment.
|
||||
@ -637,7 +653,7 @@ impl<'a> Parser<'a> {
|
||||
self.super_selectors.last().clone()
|
||||
} else {
|
||||
at_root_has_selector = true;
|
||||
self.parse_selector(true, false, String::new())?
|
||||
self.parse_selector(true, false, String::new())?.0
|
||||
}
|
||||
.resolve_parent_selectors(self.super_selectors.last(), false)?;
|
||||
|
||||
@ -692,7 +708,7 @@ impl<'a> Parser<'a> {
|
||||
// if !self.in_style_rule && !self.in_mixin && !self.in_content_block {
|
||||
// return Err(("@extend may only be used within style rules.", self.span_before).into());
|
||||
// }
|
||||
let value = Parser {
|
||||
let (value, is_optional) = Parser {
|
||||
toks: &mut read_until_semicolon_or_closing_curly_brace(self.toks)?
|
||||
.into_iter()
|
||||
.peekmore(),
|
||||
@ -712,17 +728,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
.parse_selector(false, true, String::new())?;
|
||||
|
||||
let is_optional = if let Some(Token { kind: '!', .. }) = self.toks.peek() {
|
||||
self.toks.next();
|
||||
assert_eq!(
|
||||
self.parse_identifier_no_interpolation(false)?.node,
|
||||
"optional"
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
self.whitespace();
|
||||
|
||||
if let Some(Token { kind: ';', .. }) = self.toks.peek() {
|
||||
|
@ -457,7 +457,7 @@ impl Value {
|
||||
Some(v) => v,
|
||||
None => return Err((format!("${}: {} is not a valid selector: it must be a string, a list of strings, or a list of lists of strings.", name, self.inspect(parser.span_before)?), parser.span_before).into()),
|
||||
};
|
||||
Parser {
|
||||
Ok(Parser {
|
||||
toks: &mut string
|
||||
.chars()
|
||||
.map(|c| Token::new(parser.span_before, c))
|
||||
@ -478,7 +478,8 @@ impl Value {
|
||||
content_scopes: parser.content_scopes,
|
||||
options: parser.options,
|
||||
}
|
||||
.parse_selector(allows_parent, true, String::new())
|
||||
.parse_selector(allows_parent, true, String::new())?
|
||||
.0)
|
||||
}
|
||||
|
||||
fn selector_string(self, span: Span) -> SassResult<Option<String>> {
|
||||
|
@ -1428,13 +1428,11 @@ test!(
|
||||
"a.bar {\n a: b;\n}\n\n.bar, b.foo {\n c: d;\n}\n"
|
||||
);
|
||||
test!(
|
||||
#[ignore = "!optional extend is not yet implemented"]
|
||||
optional_extend_succeeds_when_extendee_doesnt_exist,
|
||||
".foo {@extend .bar !optional}",
|
||||
""
|
||||
);
|
||||
test!(
|
||||
#[ignore = "!optional extend is not yet implemented"]
|
||||
optional_extend_succeeds_when_extension_fails,
|
||||
"a.bar {a: b}
|
||||
b.foo {@extend .bar !optional}
|
||||
|
Loading…
x
Reference in New Issue
Block a user