22
33const postcss = require ( 'postcss' ) ;
44const Tokenizer = require ( 'css-selector-tokenizer' ) ;
5+ const valueParser = require ( 'postcss-value-parser' ) ;
56
67function normalizeNodeArray ( nodes ) {
78 const array = [ ] ;
@@ -162,45 +163,48 @@ function localizeNode(node, context) {
162163}
163164
164165function localizeDeclNode ( node , context ) {
165- let newNode ;
166166 switch ( node . type ) {
167- case 'item ' :
167+ case 'word ' :
168168 if ( context . localizeNextItem ) {
169- newNode = Object . create ( node ) ;
170- newNode . name = ':local(' + newNode . name + ')' ;
169+ node . value = ':local(' + node . value + ')' ;
171170 context . localizeNextItem = false ;
172- return newNode ;
173171 }
174172 break ;
175173
176- case 'nested-item' :
177- const newNodes = node . nodes . map ( function ( n ) {
178- return localizeDeclValue ( n , context ) ;
179- } ) ;
180- node = Object . create ( node ) ;
181- node . nodes = newNodes ;
182- break ;
174+ case 'function' :
175+ if ( context . options && context . options . rewriteUrl && node . value . toLowerCase ( ) === 'url' ) {
176+ node . nodes . map ( ( nestedNode ) => {
177+ if ( nestedNode . type !== 'string' && nestedNode . type !== 'word' ) {
178+ return ;
179+ }
180+
181+ let newUrl = context . options . rewriteUrl ( context . global , nestedNode . value ) ;
182+
183+ switch ( nestedNode . type ) {
184+ case 'string' :
185+ if ( nestedNode . quote === '\'' ) {
186+ newUrl = newUrl . replace ( / ( \\ ) / g, '\\$1' ) . replace ( / ' / g, '\\\'' )
187+ }
188+
189+ if ( nestedNode . quote === '"' ) {
190+ newUrl = newUrl . replace ( / ( \\ ) / g, '\\$1' ) . replace ( / " / g, '\\"' )
191+ }
192+
193+ break ;
194+ case 'word' :
195+ newUrl = newUrl . replace ( / ( " | ' | \) | \\ ) / g, '\\$1' ) ;
196+ break ;
197+ }
183198
184- case 'url' :
185- if ( context . options && context . options . rewriteUrl ) {
186- newNode = Object . create ( node ) ;
187- newNode . url = context . options . rewriteUrl ( context . global , node . url ) ;
188- return newNode ;
199+ nestedNode . value = newUrl ;
200+ } ) ;
189201 }
190202 break ;
191203 }
192204 return node ;
193205}
194206
195- function localizeDeclValue ( valueNode , context ) {
196- const newValueNode = Object . create ( valueNode ) ;
197- newValueNode . nodes = valueNode . nodes . map ( function ( node ) {
198- return localizeDeclNode ( node , context ) ;
199- } ) ;
200- return newValueNode ;
201- }
202-
203- function localizeAnimationShorthandDeclValueNodes ( nodes , context ) {
207+ function localizeAnimationShorthandDeclValues ( decl , context ) {
204208 const validIdent = / ^ - ? [ _ a - z ] [ _ a - z 0 - 9 - ] * $ / i;
205209
206210 /*
@@ -240,9 +244,9 @@ function localizeAnimationShorthandDeclValueNodes(nodes, context) {
240244
241245 const didParseAnimationName = false ;
242246 const parsedAnimationKeywords = { } ;
243- return nodes . map ( function ( valueNode ) {
247+ const valueNodes = valueParser ( decl . value ) . walk ( ( node ) => {
244248 const value =
245- valueNode . type === 'item ' ? valueNode . name . toLowerCase ( ) : null ;
249+ node . type === 'word ' ? node . value . toLowerCase ( ) : null ;
246250
247251 let shouldParseAnimationName = false ;
248252
@@ -266,52 +270,43 @@ function localizeAnimationShorthandDeclValueNodes(nodes, context) {
266270 global : context . global ,
267271 localizeNextItem : shouldParseAnimationName && ! context . global
268272 } ;
269- return localizeDeclNode ( valueNode , subContext ) ;
273+ return localizeDeclNode ( node , subContext ) ;
270274 } ) ;
271- }
272275
273- function localizeAnimationShorthandDeclValues ( valuesNode , decl , context ) {
274- const newValuesNode = Object . create ( valuesNode ) ;
275- newValuesNode . nodes = valuesNode . nodes . map ( function ( valueNode , index ) {
276- const newValueNode = Object . create ( valueNode ) ;
277- newValueNode . nodes = localizeAnimationShorthandDeclValueNodes (
278- valueNode . nodes ,
279- context
280- ) ;
281- return newValueNode ;
282- } ) ;
283- decl . value = Tokenizer . stringifyValues ( newValuesNode ) ;
276+ decl . value = valueNodes . toString ( ) ;
284277}
285278
286- function localizeDeclValues ( localize , valuesNode , decl , context ) {
287- const newValuesNode = Object . create ( valuesNode ) ;
288- newValuesNode . nodes = valuesNode . nodes . map ( function ( valueNode ) {
279+ function localizeDeclValues ( localize , decl , context ) {
280+ const valueNodes = valueParser ( decl . value ) ;
281+ valueNodes . walk ( ( node , index , nodes ) => {
289282 const subContext = {
290283 options : context . options ,
291284 global : context . global ,
292285 localizeNextItem : localize && ! context . global
293286 } ;
294- return localizeDeclValue ( valueNode , subContext ) ;
287+ nodes [ index ] = localizeDeclNode ( node , subContext ) ;
295288 } ) ;
296- decl . value = Tokenizer . stringifyValues ( newValuesNode ) ;
289+ decl . value = valueNodes . toString ( ) ;
297290}
298291
299292function localizeDecl ( decl , context ) {
300- const valuesNode = Tokenizer . parseValues ( decl . value ) ;
301-
302- const isAnimation = / a n i m a t i o n ? $ / i. test ( decl . prop ) ;
293+ const isAnimation = / a n i m a t i o n $ / i. test ( decl . prop ) ;
303294
304295 if ( isAnimation ) {
305- return localizeAnimationShorthandDeclValues ( valuesNode , decl , context ) ;
296+ return localizeAnimationShorthandDeclValues ( decl , context ) ;
306297 }
307298
308299 const isAnimationName = / a n i m a t i o n ( - n a m e ) ? $ / i. test ( decl . prop ) ;
309300
310301 if ( isAnimationName ) {
311- return localizeDeclValues ( true , valuesNode , decl , context ) ;
302+ return localizeDeclValues ( true , decl , context ) ;
312303 }
313304
314- return localizeDeclValues ( false , valuesNode , decl , context ) ;
305+ const hasUrl = / u r l \( / i. test ( decl . value ) ;
306+
307+ if ( hasUrl ) {
308+ return localizeDeclValues ( false , decl , context ) ;
309+ }
315310}
316311
317312module . exports = postcss . plugin ( 'postcss-modules-local-by-default' , function (
0 commit comments