@@ -64,11 +64,12 @@ const ident = `(-?([a-z]|${escape})(\\w|${escape})*|--(\\w|${escape})*)`;
64
64
const integer = '[-+]?\\d+' ;
65
65
const number = `((${ integer } )(\\.\\d+)?|[-+]?(\\.\\d+))(e[-+]?${ integer } )?` ;
66
66
const percentage = `(${ number } )(%)` ;
67
+ const escapeRegEx = new RegExp ( `${ escape } ` , 'i' ) ;
67
68
const identRegEx = new RegExp ( `^${ ident } $` , 'i' ) ;
68
69
const numberRegEx = new RegExp ( `^${ number } $` ) ;
69
70
const percentageRegEx = new RegExp ( `^${ percentage } $` ) ;
70
71
const stringRegEx = / ^ ( " [ ^ " ] * " | ' [ ^ ' ] * ' ) $ / ;
71
- const urlRegEx = / ^ u r l \( \s * ( [ ^ ) ] * ) \s * \) $ / ;
72
+ const urlRegEx = new RegExp ( ` ^url\\( ${ ws } ([^"'() \\t ${ newline } \\\\]| ${ escape } )+ ${ ws } \ \)$` , 'i' ) ;
72
73
const whitespaceRegEx = new RegExp ( `^${ whitespace } $` ) ;
73
74
const trailingWhitespaceRegEx = new RegExp ( `.*${ whitespace } $` ) ;
74
75
@@ -105,6 +106,7 @@ const gradientRegEx = new RegExp(
105
106
) ;
106
107
const lengthRegEx = new RegExp ( `^${ length } $` , 'i' ) ;
107
108
const numericRegEx = new RegExp ( `^(${ number } )(%|${ ident } )?$` , 'i' ) ;
109
+ const resourceRegEx = new RegExp ( `^(src|url)\\(${ ws } (.*)${ ws } \\)$` , 'i' ) ;
108
110
const timeRegEx = new RegExp ( `^(${ number } )(m?s)$` , 'i' ) ;
109
111
110
112
/**
@@ -582,47 +584,46 @@ exports.parseDashedIdentifier = function parseDashedIdentifier(val) {
582
584
* TODO: <image-set()>, <cross-fade()>, <element()>.
583
585
*/
584
586
exports . parseImage = function parseImage ( val ) {
585
- return exports . parseUrl ( val ) || exports . parseGradient ( val ) ;
587
+ return exports . parseResource ( val ) || exports . parseGradient ( val ) ;
586
588
} ;
587
589
588
590
/**
589
591
* https://drafts.csswg.org/css-values-4/#urls
590
592
* https://drafts.csswg.org/cssom/#ref-for-url-value
593
+ *
594
+ * url(<url>)
595
+ * url(<string> <url-modifier>?)
596
+ * src(<string> <url-modifier>?)
597
+ * src(<custom-var> <url-modifier>?)
598
+ *
599
+ * TODO: handle <url-modifier> (<ident> or <fn>).
591
600
*/
592
- exports . parseUrl = function parseUrl ( val ) {
601
+ exports . parseResource = function parseResource ( val ) {
593
602
if ( val === '' ) {
594
603
return val ;
595
604
}
596
- var res = urlRegEx . exec ( val ) ;
597
- // does it match the regex?
605
+ const res = resourceRegEx . exec ( val ) ;
598
606
if ( res ) {
599
- var str = res [ 1 ] ;
600
- // if it starts with single or double quotes, does it end with the same?
601
- if ( ( str [ 0 ] === '"' || str [ 0 ] === "'" ) && str [ 0 ] !== str [ str . length - 1 ] ) {
607
+ let [ , type , urlOrString ] = res ;
608
+ type = type . toLowerCase ( ) ;
609
+ urlOrString = urlOrString . replace ( escapeRegEx , m => m . trim ( ) ) ;
610
+ if ( urlOrString . replace ( / " | ' / g, '' ) . trim ( ) === '' ) {
602
611
return undefined ;
603
612
}
604
- if ( str [ 0 ] === '"' || str [ 0 ] === "'" ) {
605
- str = str . substr ( 1 , str . length - 2 ) ;
606
- }
607
-
608
- var i ;
609
- for ( i = 0 ; i < str . length ; i ++ ) {
610
- switch ( str [ i ] ) {
611
- case '(' :
612
- case ')' :
613
- case ' ' :
614
- case '\t' :
615
- case '\n' :
616
- case "'" :
617
- case '"' :
618
- return undefined ;
619
- case '\\' :
620
- i ++ ;
621
- break ;
613
+ const variable = exports . parseCustomVariable ( urlOrString ) ;
614
+ if ( variable ) {
615
+ if ( type === 'src' ) {
616
+ return `src(${ variable } )` ;
622
617
}
618
+ return undefined ;
619
+ }
620
+ const string = exports . parseString ( urlOrString ) ;
621
+ if ( string ) {
622
+ return `${ type } (${ string } )` ;
623
+ }
624
+ if ( type === 'url' && urlRegEx . test ( `url(${ urlOrString } )` ) ) {
625
+ return `url("${ urlOrString } ")` ;
623
626
}
624
-
625
- return 'url(' + str + ')' ;
626
627
}
627
628
return exports . parseCustomVariable ( val ) ;
628
629
} ;
0 commit comments