@@ -64,11 +64,12 @@ const ident = `(-?([a-z]|${escape})(\\w|${escape})*|--(\\w|${escape})*)`;
6464const integer = '[-+]?\\d+' ;
6565const number = `((${ integer } )(\\.\\d+)?|[-+]?(\\.\\d+))(e[-+]?${ integer } )?` ;
6666const percentage = `(${ number } )(%)` ;
67+ const escapeRegEx = new RegExp ( `${ escape } ` , 'i' ) ;
6768const identRegEx = new RegExp ( `^${ ident } $` , 'i' ) ;
6869const numberRegEx = new RegExp ( `^${ number } $` ) ;
6970const percentageRegEx = new RegExp ( `^${ percentage } $` ) ;
7071const stringRegEx = / ^ ( " [ ^ " ] * " | ' [ ^ ' ] * ' ) $ / ;
71- const urlRegEx = / ^ u r l \( \s * ( [ ^ ) ] * ) \s * \) $ / ;
72+ const urlRegEx = new RegExp ( ` ^url\\( ${ ws } ([^"'() \\t ${ newline } \\\\]| ${ escape } )+ ${ ws } \ \)$` , 'i' ) ;
7273const whitespaceRegEx = new RegExp ( `^${ whitespace } $` ) ;
7374const trailingWhitespaceRegEx = new RegExp ( `.*${ whitespace } $` ) ;
7475
@@ -105,6 +106,7 @@ const gradientRegEx = new RegExp(
105106) ;
106107const lengthRegEx = new RegExp ( `^${ length } $` , 'i' ) ;
107108const numericRegEx = new RegExp ( `^(${ number } )(%|${ ident } )?$` , 'i' ) ;
109+ const resourceRegEx = new RegExp ( `^(src|url)\\(${ ws } (.*)${ ws } \\)$` , 'i' ) ;
108110const timeRegEx = new RegExp ( `^(${ number } )(m?s)$` , 'i' ) ;
109111
110112/**
@@ -582,47 +584,46 @@ exports.parseDashedIdentifier = function parseDashedIdentifier(val) {
582584 * TODO: <image-set()>, <cross-fade()>, <element()>.
583585 */
584586exports . parseImage = function parseImage ( val ) {
585- return exports . parseUrl ( val ) || exports . parseGradient ( val ) ;
587+ return exports . parseResource ( val ) || exports . parseGradient ( val ) ;
586588} ;
587589
588590/**
589591 * https://drafts.csswg.org/css-values-4/#urls
590592 * 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>).
591600 */
592- exports . parseUrl = function parseUrl ( val ) {
601+ exports . parseResource = function parseResource ( val ) {
593602 if ( val === '' ) {
594603 return val ;
595604 }
596- var res = urlRegEx . exec ( val ) ;
597- // does it match the regex?
605+ const res = resourceRegEx . exec ( val ) ;
598606 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 ( ) === '' ) {
602611 return undefined ;
603612 }
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 } )` ;
622617 }
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 } ")` ;
623626 }
624-
625- return 'url(' + str + ')' ;
626627 }
627628 return exports . parseCustomVariable ( val ) ;
628629} ;
0 commit comments