11import  postcss  from  'postcss' ; 
22import  valueParser  from  'postcss-value-parser' ; 
3+ import  _  from  'lodash' ; 
34
45const  pluginName  =  'postcss-url-parser' ; 
56
6- function  getArg ( nodes )  { 
7-   return  nodes . length  !==  0  &&  nodes [ 0 ] . type  ===  'string' 
8-     ? nodes [ 0 ] . value 
9-     : valueParser . stringify ( nodes ) ; 
7+ const  isUrlFunc  =  / u r l / i; 
8+ const  isImageSetFunc  =  / ^ (?: - w e b k i t - ) ? i m a g e - s e t $ / i; 
9+ const  needParseDecl  =  / (?: u r l | (?: - w e b k i t - ) ? i m a g e - s e t ) \( / i; 
10+ 
11+ function  getNodeFromUrlFunc ( node )  { 
12+   return  node . nodes  &&  node . nodes [ 0 ] ; 
13+ } 
14+ 
15+ function  getUrlFromUrlFunc ( node )  { 
16+   return  node . nodes . length  !==  0  &&  node . nodes [ 0 ] . type  ===  'string' 
17+     ? node . nodes [ 0 ] . value 
18+     : valueParser . stringify ( node . nodes ) ; 
1019} 
1120
1221function  walkUrls ( parsed ,  callback )  { 
1322  parsed . walk ( ( node )  =>  { 
14-     if  ( node . type  !==  'function'   ||   node . value . toLowerCase ( )   !==   'url' )  { 
23+     if  ( node . type  !==  'function' )  { 
1524      return ; 
1625    } 
1726
18-     /* eslint-disable */ 
19-     node . before  =  '' ; 
20-     node . after  =  '' ; 
21-     /* eslint-enable */ 
27+     if  ( isUrlFunc . test ( node . value ) )  { 
28+       callback ( getNodeFromUrlFunc ( node ) ,  getUrlFromUrlFunc ( node ) ,  false ) ; 
2229
23-     callback ( node ,  getArg ( node . nodes ) ) ; 
30+       // Do not traverse inside `url` 
31+       // eslint-disable-next-line consistent-return 
32+       return  false ; 
33+     } 
34+ 
35+     if  ( isImageSetFunc . test ( node . value ) )  { 
36+       node . nodes . forEach ( ( nNode )  =>  { 
37+         if  ( nNode . type  ===  'function'  &&  isUrlFunc . test ( nNode . value ) )  { 
38+           callback ( getNodeFromUrlFunc ( nNode ) ,  getUrlFromUrlFunc ( nNode ) ,  false ) ; 
39+         } 
40+ 
41+         if  ( nNode . type  ===  'string' )  { 
42+           callback ( nNode ,  nNode . value ,  true ) ; 
43+         } 
44+       } ) ; 
2445
25-     // Do not traverse inside url 
26-     // eslint-disable-next-line consistent-return 
27-     return  false ; 
46+       // Do not traverse inside `image-set` 
47+       // eslint-disable-next-line consistent-return 
48+       return  false ; 
49+     } 
2850  } ) ; 
2951} 
3052
3153function  walkDeclsWithUrl ( css ,  result ,  filter )  { 
3254  const  items  =  [ ] ; 
3355
3456  css . walkDecls ( ( decl )  =>  { 
35-     if  ( ! / u r l \( / i . test ( decl . value ) )  { 
57+     if  ( ! needParseDecl . test ( decl . value ) )  { 
3658      return ; 
3759    } 
3860
3961    const  parsed  =  valueParser ( decl . value ) ; 
4062    const  urls  =  [ ] ; 
4163
42-     walkUrls ( parsed ,  ( node ,  url )  =>  { 
64+     walkUrls ( parsed ,  ( node ,  url ,   needQuotes )  =>  { 
4365      if  ( url . trim ( ) . replace ( / \\ [ \r \n ] / g,  '' ) . length  ===  0 )  { 
4466        result . warn ( `Unable to find uri in '${ decl . toString ( ) }  ,  { 
4567          node : decl , 
@@ -52,7 +74,7 @@ function walkDeclsWithUrl(css, result, filter) {
5274        return ; 
5375      } 
5476
55-       urls . push ( url ) ; 
77+       urls . push ( {   url,  needQuotes  } ) ; 
5678    } ) ; 
5779
5880    if  ( urls . length  ===  0 )  { 
@@ -65,52 +87,49 @@ function walkDeclsWithUrl(css, result, filter) {
6587  return  items ; 
6688} 
6789
68- function  flatten ( array )  { 
69-   return  array . reduce ( ( acc ,  d )  =>  [ ...acc ,  ...d ] ,  [ ] ) ; 
70- } 
71- 
72- function  uniq ( array )  { 
73-   return  array . reduce ( 
74-     ( acc ,  d )  =>  ( acc . indexOf ( d )  ===  - 1  ? [ ...acc ,  d ]  : acc ) , 
75-     [ ] 
76-   ) ; 
77- } 
78- 
7990export  default  postcss . plugin ( 
8091  pluginName , 
8192  ( options  =  { } )  => 
8293    function  process ( css ,  result )  { 
8394      const  traversed  =  walkDeclsWithUrl ( css ,  result ,  options . filter ) ; 
84-       const  paths  =  uniq ( flatten ( traversed . map ( ( item )  =>  item . urls ) ) ) ; 
95+       const  paths  =  _ . uniqWith ( 
96+         _ . flatten ( traversed . map ( ( item )  =>  item . urls ) ) , 
97+         _ . isEqual 
98+       ) ; 
8599
86100      if  ( paths . length  ===  0 )  { 
87101        return ; 
88102      } 
89103
90-       const  urls  =  { } ; 
104+       const  placeholders  =  [ ] ; 
91105
92106      paths . forEach ( ( path ,  index )  =>  { 
93107        const  placeholder  =  `___CSS_LOADER_URL___${ index }  ; 
108+         const  {  url,  needQuotes }  =  path ; 
94109
95-         urls [ path ]   =   placeholder ; 
110+         placeholders . push ( {   placeholder,  path  } ) ; 
96111
97112        result . messages . push ( { 
98113          pluginName, 
99114          type : 'url' , 
100-           item : {  url :  path ,  placeholder } , 
115+           item : {  url,  placeholder,  needQuotes  } , 
101116        } ) ; 
102117      } ) ; 
103118
104119      traversed . forEach ( ( item )  =>  { 
105-         walkUrls ( item . parsed ,  ( node ,  url )  =>  { 
106-           const  value  =  urls [ url ] ; 
120+         walkUrls ( item . parsed ,  ( node ,  url ,   needQuotes )  =>  { 
121+           const  value  =  _ . find ( placeholders ,   {   path :  {   url,  needQuotes  }   } ) ; 
107122
108123          if  ( ! value )  { 
109124            return ; 
110125          } 
111126
127+           const  {  placeholder }  =  value ; 
128+ 
129+           // eslint-disable-next-line no-param-reassign 
130+           node . type  =  'word' ; 
112131          // eslint-disable-next-line no-param-reassign 
113-           node . nodes  =  [ {   type :  'word' ,  value  } ] ; 
132+           node . value  =  placeholder ; 
114133        } ) ; 
115134
116135        // eslint-disable-next-line no-param-reassign 
0 commit comments