2020-07-26 13:12:35 -04:00
use std ::cmp ::Ordering ;
2020-05-31 04:51:41 -04:00
use peekmore ::PeekMore ;
2020-04-12 19:37:12 -04:00
use codemap ::{ Span , Spanned } ;
2020-06-16 20:00:11 -04:00
use crate ::{
color ::Color ,
2020-07-26 13:12:35 -04:00
common ::{ Brackets , ListSeparator , Op , QuoteKind } ,
2020-06-16 20:00:11 -04:00
error ::SassResult ,
parse ::Parser ,
selector ::Selector ,
2020-08-01 14:33:22 -04:00
unit ::Unit ,
2020-06-16 20:00:11 -04:00
utils ::hex_char_for ,
{ Cow , Token } ,
} ;
2020-03-30 15:43:15 -04:00
2020-04-06 21:22:03 -04:00
use css_function ::is_special_function ;
2020-03-30 15:43:15 -04:00
pub ( crate ) use map ::SassMap ;
2020-02-08 18:43:18 -05:00
pub ( crate ) use number ::Number ;
2020-04-04 21:07:53 -04:00
pub ( crate ) use sass_function ::SassFunction ;
2020-01-25 09:58:53 -05:00
2020-06-16 19:38:30 -04:00
pub ( crate ) mod css_function ;
2020-03-30 15:43:15 -04:00
mod map ;
2020-02-08 18:43:18 -05:00
mod number ;
2020-04-04 21:07:53 -04:00
mod sass_function ;
2020-01-25 09:58:53 -05:00
2020-07-10 00:17:15 -04:00
#[ derive(Debug, Clone) ]
2020-01-25 09:58:53 -05:00
pub ( crate ) enum Value {
Important ,
True ,
False ,
Null ,
2020-07-26 19:38:41 -04:00
/// A `None` value for `Number` indicates a `NaN` value
Dimension ( Option < Number > , Unit , bool ) ,
2020-03-23 19:56:24 -04:00
List ( Vec < Value > , ListSeparator , Brackets ) ,
2020-04-21 18:54:19 -04:00
Color ( Box < Color > ) ,
2020-05-22 14:35:41 -04:00
String ( String , QuoteKind ) ,
2020-03-30 15:43:15 -04:00
Map ( SassMap ) ,
2020-04-12 19:37:12 -04:00
ArgList ( Vec < Spanned < Value > > ) ,
2020-04-03 21:38:34 -04:00
/// Returned by `get-function()`
2020-07-03 12:58:09 -04:00
FunctionRef ( SassFunction ) ,
2020-01-25 09:58:53 -05:00
}
2020-07-10 00:17:15 -04:00
impl PartialEq for Value {
fn eq ( & self , other : & Self ) -> bool {
match self {
Value ::String ( s1 , .. ) = > match other {
Value ::String ( s2 , .. ) = > s1 = = s2 ,
_ = > false ,
} ,
2020-07-26 19:38:41 -04:00
Value ::Dimension ( Some ( n ) , unit , _ ) = > match other {
Value ::Dimension ( Some ( n2 ) , unit2 , _ ) = > {
2020-07-10 00:17:15 -04:00
if ! unit . comparable ( unit2 ) {
false
} else if unit = = unit2 {
n = = n2
} else if unit = = & Unit ::None | | unit2 = = & Unit ::None {
false
} else {
2020-08-01 14:33:22 -04:00
n = = & n2 . clone ( ) . convert ( unit2 , unit )
2020-07-10 00:17:15 -04:00
}
}
_ = > false ,
} ,
2020-07-26 19:38:41 -04:00
Value ::Dimension ( None , .. ) = > false ,
2020-07-10 00:17:15 -04:00
Value ::List ( list1 , sep1 , brackets1 ) = > match other {
Value ::List ( list2 , sep2 , brackets2 ) = > {
if sep1 ! = sep2 | | brackets1 ! = brackets2 | | list1 . len ( ) ! = list2 . len ( ) {
false
} else {
for ( a , b ) in list1 . iter ( ) . zip ( list2 ) {
if a ! = b {
return false ;
}
}
true
}
}
_ = > false ,
} ,
Value ::Null = > matches! ( other , Value ::Null ) ,
Value ::True = > matches! ( other , Value ::True ) ,
Value ::False = > matches! ( other , Value ::False ) ,
Value ::Important = > matches! ( other , Value ::Important ) ,
Value ::FunctionRef ( fn1 ) = > {
if let Value ::FunctionRef ( fn2 ) = other {
fn1 = = fn2
} else {
false
}
}
Value ::Map ( map1 ) = > {
if let Value ::Map ( map2 ) = other {
map1 = = map2
} else {
false
}
}
Value ::Color ( color1 ) = > {
if let Value ::Color ( color2 ) = other {
color1 = = color2
} else {
false
}
}
Value ::ArgList ( list1 ) = > {
if let Value ::ArgList ( list2 ) = other {
list1 = = list2
} else {
false
}
}
}
}
}
impl Eq for Value { }
2020-07-03 12:38:20 -04:00
fn visit_quoted_string ( buf : & mut String , force_double_quote : bool , string : & str ) {
2020-04-19 13:51:34 -04:00
let mut has_single_quote = false ;
let mut has_double_quote = false ;
let mut buffer = String ::new ( ) ;
if force_double_quote {
buffer . push ( '"' ) ;
}
let mut iter = string . chars ( ) . peekable ( ) ;
while let Some ( c ) = iter . next ( ) {
match c {
'\'' = > {
if force_double_quote {
buffer . push ( '\'' ) ;
} else if has_double_quote {
return visit_quoted_string ( buf , true , string ) ;
} else {
has_single_quote = true ;
buffer . push ( '\'' ) ;
}
}
'"' = > {
if force_double_quote {
buffer . push ( '\\' ) ;
buffer . push ( '"' ) ;
} else if has_single_quote {
return visit_quoted_string ( buf , true , string ) ;
} else {
has_double_quote = true ;
buffer . push ( '"' ) ;
}
}
'\x00' ..= '\x08' | '\x0A' ..= '\x1F' = > {
buffer . push ( '\\' ) ;
if c as u32 > 0xF {
2021-07-03 19:15:31 -04:00
buffer . push ( hex_char_for ( c as u32 > > 4 ) ) ;
2020-04-19 13:51:34 -04:00
}
buffer . push ( hex_char_for ( c as u32 & 0xF ) ) ;
2020-06-18 01:08:30 -04:00
let next = match iter . peek ( ) {
Some ( v ) = > v ,
None = > break ,
} ;
2020-04-19 13:51:34 -04:00
if next . is_ascii_hexdigit ( ) | | next = = & ' ' | | next = = & '\t' {
buffer . push ( ' ' ) ;
}
}
'\\' = > {
buffer . push ( '\\' ) ;
buffer . push ( '\\' ) ;
}
_ = > buffer . push ( c ) ,
}
}
if force_double_quote {
buffer . push ( '"' ) ;
} else {
let quote = if has_double_quote { '\'' } else { '"' } ;
buffer = format! ( " {} {} {} " , quote , buffer , quote ) ;
}
buf . push_str ( & buffer ) ;
}
2020-04-12 19:37:12 -04:00
impl Value {
2020-07-03 12:38:20 -04:00
pub fn is_null ( & self ) -> bool {
match self {
2020-05-22 20:47:53 -04:00
Value ::Null = > true ,
2020-05-22 14:35:41 -04:00
Value ::String ( i , QuoteKind ::None ) if i . is_empty ( ) = > true ,
2020-07-03 13:00:31 -04:00
Value ::List ( v , _ , Brackets ::Bracketed ) if v . is_empty ( ) = > false ,
2020-07-08 23:49:30 -04:00
Value ::List ( v , .. ) = > v . iter ( ) . map ( Value ::is_null ) . all ( | f | f ) ,
Value ::ArgList ( v , .. ) if v . is_empty ( ) = > false ,
Value ::ArgList ( v , .. ) = > v . iter ( ) . map ( | v | v . node . is_null ( ) ) . all ( | f | f ) ,
2020-04-26 18:27:08 -04:00
_ = > false ,
2020-07-03 12:38:20 -04:00
}
2020-04-12 19:37:12 -04:00
}
2020-04-18 20:11:49 -04:00
2020-05-05 11:08:34 -04:00
pub fn to_css_string ( & self , span : Span ) -> SassResult < Cow < 'static , str > > {
2020-04-12 19:37:12 -04:00
Ok ( match self {
2020-07-03 13:00:31 -04:00
Value ::Important = > Cow ::const_str ( " !important " ) ,
2020-07-26 23:45:00 -04:00
Value ::Dimension ( num , unit , _ ) = > match unit {
2020-07-04 11:04:51 -04:00
Unit ::Mul ( .. ) | Unit ::Div ( .. ) = > {
2020-07-26 23:45:00 -04:00
if let Some ( num ) = num {
return Err (
( format! ( " {} {} isn't a valid CSS value. " , num , unit ) , span ) . into ( )
) ;
}
2021-07-03 19:15:31 -04:00
return Err ( ( format! ( " NaN {} isn't a valid CSS value. " , unit ) , span ) . into ( ) ) ;
2020-07-26 23:45:00 -04:00
}
_ = > {
if let Some ( num ) = num {
Cow ::owned ( format! ( " {} {} " , num , unit ) )
} else {
Cow ::owned ( format! ( " NaN {} " , unit ) )
}
2020-03-16 21:29:00 -04:00
}
} ,
2020-07-03 13:00:31 -04:00
Value ::Map ( .. ) | Value ::FunctionRef ( .. ) = > {
2020-04-26 23:11:04 -04:00
return Err ( (
format! ( " {} isn't a valid CSS value. " , self . inspect ( span ) ? ) ,
span ,
)
. into ( ) )
}
2020-07-03 13:00:31 -04:00
Value ::List ( vals , sep , brackets ) = > match brackets {
2020-05-25 13:09:20 -04:00
Brackets ::None = > Cow ::owned (
2020-03-23 19:56:24 -04:00
vals . iter ( )
2020-07-03 12:38:20 -04:00
. filter ( | x | ! x . is_null ( ) )
2020-04-12 19:37:12 -04:00
. map ( | x | x . to_css_string ( span ) )
2020-05-05 11:08:34 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
2020-03-23 19:56:24 -04:00
. join ( sep . as_str ( ) ) ,
) ,
2020-05-25 13:09:20 -04:00
Brackets ::Bracketed = > Cow ::owned ( format! (
2020-05-05 11:08:34 -04:00
" [{}] " ,
vals . iter ( )
2020-07-03 12:38:20 -04:00
. filter ( | x | ! x . is_null ( ) )
2020-05-05 11:08:34 -04:00
. map ( | x | x . to_css_string ( span ) )
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
. join ( sep . as_str ( ) ) ,
) ) ,
2020-03-23 19:56:24 -04:00
} ,
2020-07-03 13:00:31 -04:00
Value ::Color ( c ) = > Cow ::owned ( c . to_string ( ) ) ,
Value ::String ( string , QuoteKind ::None ) = > {
2020-04-19 13:51:34 -04:00
let mut after_newline = false ;
let mut buf = String ::with_capacity ( string . len ( ) ) ;
for c in string . chars ( ) {
match c {
2020-04-20 12:12:39 -04:00
'\n' = > {
buf . push ( ' ' ) ;
after_newline = true ;
}
2020-04-19 13:51:34 -04:00
' ' = > {
if ! after_newline {
buf . push ( ' ' ) ;
2020-02-24 19:49:24 -05:00
}
}
2020-04-19 13:51:34 -04:00
_ = > {
buf . push ( c ) ;
after_newline = false ;
}
2020-02-24 19:49:24 -05:00
}
}
2020-05-25 13:09:20 -04:00
Cow ::owned ( buf )
2020-04-19 13:51:34 -04:00
}
2020-07-03 13:00:31 -04:00
Value ::String ( string , QuoteKind ::Quoted ) = > {
2020-04-19 13:51:34 -04:00
let mut buf = String ::with_capacity ( string . len ( ) ) ;
2020-07-03 12:38:20 -04:00
visit_quoted_string ( & mut buf , false , string ) ;
2020-05-25 13:09:20 -04:00
Cow ::owned ( buf )
2020-02-24 19:49:24 -05:00
}
2020-07-03 13:00:31 -04:00
Value ::True = > Cow ::const_str ( " true " ) ,
Value ::False = > Cow ::const_str ( " false " ) ,
Value ::Null = > Cow ::const_str ( " " ) ,
2020-07-06 18:10:22 -04:00
Value ::ArgList ( args ) if args . is_empty ( ) = > {
return Err ( ( " () isn't a valid CSS value. " , span ) . into ( ) ) ;
}
2020-07-03 13:00:31 -04:00
Value ::ArgList ( args ) = > Cow ::owned (
2020-05-05 11:08:34 -04:00
args . iter ( )
2020-07-03 12:38:20 -04:00
. filter ( | x | ! x . is_null ( ) )
2021-07-03 19:15:31 -04:00
. map ( | a | a . node . to_css_string ( span ) )
2020-05-25 13:09:20 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
2020-05-05 11:08:34 -04:00
. join ( " , " ) ,
) ,
2020-04-12 19:37:12 -04:00
} )
2020-01-26 15:04:16 -05:00
}
2020-07-03 12:38:20 -04:00
pub fn is_true ( & self ) -> bool {
2020-11-16 03:25:55 -05:00
! matches! ( self , Value ::Null | Value ::False )
2020-01-25 09:58:53 -05:00
}
2020-02-02 21:11:22 -05:00
pub fn unquote ( self ) -> Self {
match self {
2020-07-03 13:00:31 -04:00
Value ::String ( s1 , _ ) = > Value ::String ( s1 , QuoteKind ::None ) ,
Value ::List ( v , sep , bracket ) = > {
Value ::List ( v . into_iter ( ) . map ( Value ::unquote ) . collect ( ) , sep , bracket )
2020-04-19 22:54:56 -04:00
}
2020-02-24 16:58:48 -05:00
v = > v ,
2020-02-02 21:11:22 -05:00
}
2020-01-25 09:58:53 -05:00
}
2020-04-21 18:22:26 -04:00
pub const fn span ( self , span : Span ) -> Spanned < Self > {
2020-04-12 19:37:12 -04:00
Spanned { node : self , span }
}
2020-07-03 12:38:20 -04:00
pub fn kind ( & self ) -> & 'static str {
2020-02-03 07:56:21 -05:00
match self {
2020-07-03 13:00:31 -04:00
Value ::Color ( .. ) = > " color " ,
Value ::String ( .. ) | Value ::Important = > " string " ,
Value ::Dimension ( .. ) = > " number " ,
Value ::List ( .. ) = > " list " ,
Value ::FunctionRef ( .. ) = > " function " ,
Value ::ArgList ( .. ) = > " arglist " ,
Value ::True | Value ::False = > " bool " ,
Value ::Null = > " null " ,
Value ::Map ( .. ) = > " map " ,
2020-02-03 07:56:21 -05:00
}
}
2020-04-06 21:22:03 -04:00
pub fn is_special_function ( & self ) -> bool {
match self {
2020-07-03 13:00:31 -04:00
Value ::String ( s , QuoteKind ::None ) = > is_special_function ( s ) ,
2020-04-06 21:22:03 -04:00
_ = > false ,
}
}
2020-02-08 15:53:49 -05:00
pub fn bool ( b : bool ) -> Self {
if b {
Value ::True
} else {
Value ::False
}
}
2020-07-26 13:12:35 -04:00
pub fn cmp ( & self , other : & Self , span : Span , op : Op ) -> SassResult < Ordering > {
Ok ( match self {
2020-07-26 19:38:41 -04:00
Value ::Dimension ( None , .. ) = > todo! ( ) ,
Value ::Dimension ( Some ( num ) , unit , _ ) = > match & other {
Value ::Dimension ( None , .. ) = > todo! ( ) ,
Value ::Dimension ( Some ( num2 ) , unit2 , _ ) = > {
2020-07-26 13:12:35 -04:00
if ! unit . comparable ( unit2 ) {
return Err (
( format! ( " Incompatible units {} and {} . " , unit2 , unit ) , span ) . into ( ) ,
) ;
}
if unit = = unit2 | | unit = = & Unit ::None | | unit2 = = & Unit ::None {
num . cmp ( num2 )
} else {
2020-08-01 14:33:22 -04:00
num . cmp ( & num2 . clone ( ) . convert ( unit2 , unit ) )
2020-07-26 13:12:35 -04:00
}
}
v = > {
return Err ( (
format! (
" Undefined operation \" {} {} {} \" . " ,
v . inspect ( span ) ? ,
op ,
other . inspect ( span ) ?
) ,
span ,
)
. into ( ) )
}
} ,
_ = > {
return Err ( (
format! (
" Undefined operation \" {} {} {} \" . " ,
self . inspect ( span ) ? ,
op ,
other . inspect ( span ) ?
) ,
span ,
)
. into ( ) )
}
} )
}
2020-07-07 00:01:34 -04:00
pub fn not_equals ( & self , other : & Self ) -> bool {
match self {
Value ::String ( s1 , .. ) = > match other {
Value ::String ( s2 , .. ) = > s1 ! = s2 ,
_ = > true ,
} ,
2020-07-26 19:38:41 -04:00
Value ::Dimension ( Some ( n ) , unit , _ ) = > match other {
Value ::Dimension ( Some ( n2 ) , unit2 , _ ) = > {
2020-07-07 01:13:15 -04:00
if ! unit . comparable ( unit2 ) {
2020-07-07 00:01:34 -04:00
true
} else if unit = = unit2 {
n ! = n2
} else if unit = = & Unit ::None | | unit2 = = & Unit ::None {
true
} else {
2020-08-01 14:33:22 -04:00
n ! = & n2 . clone ( ) . convert ( unit2 , unit )
2020-07-07 00:01:34 -04:00
}
}
_ = > true ,
} ,
Value ::List ( list1 , sep1 , brackets1 ) = > match other {
Value ::List ( list2 , sep2 , brackets2 ) = > {
if sep1 ! = sep2 | | brackets1 ! = brackets2 | | list1 . len ( ) ! = list2 . len ( ) {
true
} else {
for ( a , b ) in list1 . iter ( ) . zip ( list2 ) {
if a . not_equals ( b ) {
return true ;
}
}
false
}
}
_ = > true ,
} ,
s = > s ! = other ,
}
}
2020-04-26 18:27:08 -04:00
// TODO:
// https://github.com/sass/dart-sass/blob/d4adea7569832f10e3a26d0e420ae51640740cfb/lib/src/ast/sass/expression/list.dart#L39
2020-05-06 11:50:35 -04:00
pub fn inspect ( & self , span : Span ) -> SassResult < Cow < 'static , str > > {
2020-04-12 19:37:12 -04:00
Ok ( match self {
2020-04-06 00:27:09 -04:00
Value ::List ( v , _ , brackets ) if v . is_empty ( ) = > match brackets {
2020-05-25 13:09:20 -04:00
Brackets ::None = > Cow ::const_str ( " () " ) ,
Brackets ::Bracketed = > Cow ::const_str ( " [] " ) ,
2020-04-06 00:27:09 -04:00
} ,
2020-04-20 02:55:55 -04:00
Value ::List ( v , sep , brackets ) if v . len ( ) = = 1 = > match brackets {
Brackets ::None = > match sep {
2020-04-21 18:22:26 -04:00
ListSeparator ::Space = > v [ 0 ] . inspect ( span ) ? ,
2020-05-25 13:09:20 -04:00
ListSeparator ::Comma = > Cow ::owned ( format! ( " ( {} ,) " , v [ 0 ] . inspect ( span ) ? ) ) ,
2020-04-20 02:55:55 -04:00
} ,
Brackets ::Bracketed = > match sep {
2020-05-25 13:09:20 -04:00
ListSeparator ::Space = > Cow ::owned ( format! ( " [ {} ] " , v [ 0 ] . inspect ( span ) ? ) ) ,
ListSeparator ::Comma = > Cow ::owned ( format! ( " [ {} ,] " , v [ 0 ] . inspect ( span ) ? ) ) ,
2020-04-20 02:55:55 -04:00
} ,
} ,
2020-07-03 13:00:31 -04:00
Value ::List ( vals , sep , brackets ) = > Cow ::owned ( match brackets {
2020-04-21 18:22:26 -04:00
Brackets ::None = > vals
. iter ( )
. map ( | x | x . inspect ( span ) )
2020-05-06 11:50:35 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
2020-04-21 18:22:26 -04:00
. join ( sep . as_str ( ) ) ,
2020-04-20 03:07:02 -04:00
Brackets ::Bracketed = > format! (
" [{}] " ,
vals . iter ( )
. map ( | x | x . inspect ( span ) )
2020-05-06 11:50:35 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
2020-04-20 03:07:02 -04:00
. join ( sep . as_str ( ) ) ,
) ,
2020-05-06 11:50:35 -04:00
} ) ,
2020-07-03 12:58:09 -04:00
Value ::FunctionRef ( f ) = > Cow ::owned ( format! ( " get-function( \" {} \" ) " , f . name ( ) ) ) ,
2020-05-25 13:09:20 -04:00
Value ::Null = > Cow ::const_str ( " null " ) ,
Value ::Map ( map ) = > Cow ::owned ( format! (
2020-04-18 20:11:49 -04:00
" ({}) " ,
map . iter ( )
2020-07-05 07:31:10 -04:00
. map ( | ( k , v ) | Ok ( format! ( " {} : {} " , k . inspect ( span ) ? , v . inspect ( span ) ? ) ) )
2020-04-18 20:11:49 -04:00
. collect ::< SassResult < Vec < String > > > ( ) ?
. join ( " , " )
2020-05-06 11:50:35 -04:00
) ) ,
2020-07-26 19:38:41 -04:00
Value ::Dimension ( Some ( num ) , unit , _ ) = > Cow ::owned ( format! ( " {} {} " , num , unit ) ) ,
2020-07-26 23:45:00 -04:00
Value ::Dimension ( None , unit , .. ) = > Cow ::owned ( format! ( " NaN {} " , unit ) ) ,
2020-07-06 18:10:22 -04:00
Value ::ArgList ( args ) if args . is_empty ( ) = > Cow ::const_str ( " () " ) ,
2020-07-06 21:41:48 -04:00
Value ::ArgList ( args ) if args . len ( ) = = 1 = > Cow ::owned ( format! (
" ({},) " ,
args . iter ( )
. filter ( | x | ! x . is_null ( ) )
2021-07-03 19:15:31 -04:00
. map ( | a | a . node . inspect ( span ) )
2020-07-06 21:41:48 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
. join ( " , " ) ,
) ) ,
2020-07-05 07:31:10 -04:00
Value ::ArgList ( args ) = > Cow ::owned (
args . iter ( )
. filter ( | x | ! x . is_null ( ) )
2021-07-03 19:15:31 -04:00
. map ( | a | a . node . inspect ( span ) )
2020-07-05 07:31:10 -04:00
. collect ::< SassResult < Vec < Cow < 'static , str > > > > ( ) ?
. join ( " , " ) ,
) ,
Value ::Important
| Value ::True
| Value ::False
| Value ::Color ( .. )
| Value ::String ( .. ) = > self . to_css_string ( span ) ? ,
2020-04-12 19:37:12 -04:00
} )
2020-04-06 00:27:09 -04:00
}
2020-05-31 04:51:41 -04:00
pub fn as_list ( self ) -> Vec < Value > {
match self {
Value ::List ( v , .. ) = > v ,
2020-07-02 17:25:52 -04:00
Value ::Map ( m ) = > m . as_list ( ) ,
2020-06-17 05:24:42 -04:00
Value ::ArgList ( v ) = > v . into_iter ( ) . map ( | val | val . node ) . collect ( ) ,
2020-05-31 04:51:41 -04:00
v = > vec! [ v ] ,
}
}
/// Parses `self` as a selector list, in the same manner as the
/// `selector-parse()` function.
///
/// Returns a `SassError` if `self` isn't a type that can be parsed as a
/// selector, or if parsing fails. If `allow_parent` is `true`, this allows
/// parent selectors. Otherwise, they're considered parse errors.
///
/// `name` is the argument name. It's used for error reporting.
pub fn to_selector (
self ,
2020-06-16 19:38:30 -04:00
parser : & mut Parser < '_ > ,
2020-05-31 04:51:41 -04:00
name : & str ,
allows_parent : bool ,
) -> SassResult < Selector > {
2020-06-16 19:38:30 -04:00
let string = match self . clone ( ) . selector_string ( parser . span_before ) ? {
2020-05-31 04:51:41 -04:00
Some ( v ) = > v ,
2020-06-16 19:38:30 -04:00
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 ( ) ) ,
2020-05-31 04:51:41 -04:00
} ;
2020-07-24 20:23:54 -04:00
Ok ( Parser {
2020-06-16 19:38:30 -04:00
toks : & mut string
. chars ( )
. map ( | c | Token ::new ( parser . span_before , c ) )
. collect ::< Vec < Token > > ( )
. into_iter ( )
. peekmore ( ) ,
map : parser . map ,
path : parser . path ,
scopes : parser . scopes ,
global_scope : parser . global_scope ,
super_selectors : parser . super_selectors ,
span_before : parser . span_before ,
2020-06-26 06:12:50 -04:00
content : parser . content ,
2020-07-05 19:16:44 +08:00
flags : parser . flags ,
2020-06-16 19:38:30 -04:00
at_root : parser . at_root ,
at_root_has_selector : parser . at_root_has_selector ,
2020-06-18 16:56:03 -04:00
extender : parser . extender ,
2020-07-08 17:52:37 -04:00
content_scopes : parser . content_scopes ,
2020-07-15 12:37:19 +01:00
options : parser . options ,
2020-07-25 19:22:12 -04:00
modules : parser . modules ,
2020-08-06 21:00:34 -04:00
module_config : parser . module_config ,
2020-06-16 19:38:30 -04:00
}
2020-07-24 20:23:54 -04:00
. parse_selector ( allows_parent , true , String ::new ( ) ) ?
. 0 )
2020-05-31 04:51:41 -04:00
}
fn selector_string ( self , span : Span ) -> SassResult < Option < String > > {
2020-07-03 12:38:20 -04:00
Ok ( Some ( match self {
2020-07-03 13:00:31 -04:00
Value ::String ( text , .. ) = > text ,
Value ::List ( list , sep , .. ) if ! list . is_empty ( ) = > {
2020-05-31 04:51:41 -04:00
let mut result = Vec ::new ( ) ;
match sep {
ListSeparator ::Comma = > {
for complex in list {
if let Value ::String ( text , .. ) = complex {
result . push ( text ) ;
} else if let Value ::List ( _ , ListSeparator ::Space , .. ) = complex {
result . push ( match complex . selector_string ( span ) ? {
Some ( v ) = > v ,
None = > return Ok ( None ) ,
} ) ;
} else {
return Ok ( None ) ;
}
}
}
ListSeparator ::Space = > {
for compound in list {
if let Value ::String ( text , .. ) = compound {
result . push ( text ) ;
} else {
return Ok ( None ) ;
}
}
}
}
result . join ( sep . as_str ( ) )
}
_ = > return Ok ( None ) ,
} ) )
}
2020-01-25 09:58:53 -05:00
}