@@ -26,20 +26,17 @@ function normalizeNodeArray(nodes) {
2626}
2727
2828function localizeNode ( rule , mode , localAliasMap ) {
29- const isScopePseudo = ( node ) =>
30- node . value === ":local" || node . value === ":global" ;
31- const isImportExportPseudo = ( node ) =>
32- node . value === ":import" || node . value === ":export" ;
33-
3429 const transform = ( node , context ) => {
3530 if ( context . ignoreNextSpacing && ! isSpacing ( node ) ) {
3631 throw new Error ( "Missing whitespace after " + context . ignoreNextSpacing ) ;
3732 }
33+
3834 if ( context . enforceNoSpacing && isSpacing ( node ) ) {
3935 throw new Error ( "Missing whitespace before " + context . enforceNoSpacing ) ;
4036 }
4137
4238 let newNodes ;
39+
4340 switch ( node . type ) {
4441 case "root" : {
4542 let resultingGlobal ;
@@ -101,8 +98,9 @@ function localizeNode(rule, mode, localAliasMap) {
10198 case "pseudo" : {
10299 let childContext ;
103100 const isNested = ! ! node . length ;
104- const isScoped = isScopePseudo ( node ) ;
105- const isImportExport = isImportExportPseudo ( node ) ;
101+ const isScoped = node . value === ":local" || node . value === ":global" ;
102+ const isImportExport =
103+ node . value === ":import" || node . value === ":export" ;
106104
107105 if ( isImportExport ) {
108106 context . hasLocals = true ;
@@ -303,91 +301,9 @@ function isWordAFunctionArgument(wordNode, functionNode) {
303301 : false ;
304302}
305303
306- function localizeAnimationShorthandDeclValues ( decl , context ) {
307- const validIdent = / ^ - ? [ _ a - z ] [ _ a - z 0 - 9 - ] * $ / i;
308-
309- /*
310- The spec defines some keywords that you can use to describe properties such as the timing
311- function. These are still valid animation names, so as long as there is a property that accepts
312- a keyword, it is given priority. Only when all the properties that can take a keyword are
313- exhausted can the animation name be set to the keyword. I.e.
314-
315- animation: infinite infinite;
316-
317- The animation will repeat an infinite number of times from the first argument, and will have an
318- animation name of infinite from the second.
319- */
320- const animationKeywords = {
321- $alternate : 1 ,
322- "$alternate-reverse" : 1 ,
323- $backwards : 1 ,
324- $both : 1 ,
325- $ease : 1 ,
326- "$ease-in" : 1 ,
327- "$ease-in-out" : 1 ,
328- "$ease-out" : 1 ,
329- $forwards : 1 ,
330- $infinite : 1 ,
331- $linear : 1 ,
332- $none : Infinity , // No matter how many times you write none, it will never be an animation name
333- $normal : 1 ,
334- $paused : 1 ,
335- $reverse : 1 ,
336- $running : 1 ,
337- "$step-end" : 1 ,
338- "$step-start" : 1 ,
339- $initial : Infinity ,
340- $inherit : Infinity ,
341- $unset : Infinity ,
342- } ;
343-
344- const didParseAnimationName = false ;
345- let parsedAnimationKeywords = { } ;
346- let stepsFunctionNode = null ;
347- const valueNodes = valueParser ( decl . value ) . walk ( ( node ) => {
348- /* If div-token appeared (represents as comma ','), a possibility of an animation-keywords should be reflesh. */
349- if ( node . type === "div" ) {
350- parsedAnimationKeywords = { } ;
351- }
352- if ( node . type === "function" && node . value . toLowerCase ( ) === "steps" ) {
353- stepsFunctionNode = node ;
354- }
355- const value =
356- node . type === "word" && ! isWordAFunctionArgument ( node , stepsFunctionNode )
357- ? node . value . toLowerCase ( )
358- : null ;
359-
360- let shouldParseAnimationName = false ;
361-
362- if ( ! didParseAnimationName && value && validIdent . test ( value ) ) {
363- if ( "$" + value in animationKeywords ) {
364- parsedAnimationKeywords [ "$" + value ] =
365- "$" + value in parsedAnimationKeywords
366- ? parsedAnimationKeywords [ "$" + value ] + 1
367- : 0 ;
368-
369- shouldParseAnimationName =
370- parsedAnimationKeywords [ "$" + value ] >=
371- animationKeywords [ "$" + value ] ;
372- } else {
373- shouldParseAnimationName = true ;
374- }
375- }
376-
377- const subContext = {
378- options : context . options ,
379- global : context . global ,
380- localizeNextItem : shouldParseAnimationName && ! context . global ,
381- localAliasMap : context . localAliasMap ,
382- } ;
383- return localizeDeclNode ( node , subContext ) ;
384- } ) ;
385-
386- decl . value = valueNodes . toString ( ) ;
387- }
388-
389304function localizeDeclValues ( localize , decl , context ) {
390305 const valueNodes = valueParser ( decl . value ) ;
306+
391307 valueNodes . walk ( ( node , index , nodes ) => {
392308 const subContext = {
393309 options : context . options ,
@@ -404,7 +320,89 @@ function localizeDecl(decl, context) {
404320 const isAnimation = / a n i m a t i o n $ / i. test ( decl . prop ) ;
405321
406322 if ( isAnimation ) {
407- return localizeAnimationShorthandDeclValues ( decl , context ) ;
323+ const validIdent = / ^ - ? [ _ a - z ] [ _ a - z 0 - 9 - ] * $ / i;
324+
325+ /*
326+ The spec defines some keywords that you can use to describe properties such as the timing
327+ function. These are still valid animation names, so as long as there is a property that accepts
328+ a keyword, it is given priority. Only when all the properties that can take a keyword are
329+ exhausted can the animation name be set to the keyword. I.e.
330+
331+ animation: infinite infinite;
332+
333+ The animation will repeat an infinite number of times from the first argument, and will have an
334+ animation name of infinite from the second.
335+ */
336+ const animationKeywords = {
337+ $alternate : 1 ,
338+ "$alternate-reverse" : 1 ,
339+ $backwards : 1 ,
340+ $both : 1 ,
341+ $ease : 1 ,
342+ "$ease-in" : 1 ,
343+ "$ease-in-out" : 1 ,
344+ "$ease-out" : 1 ,
345+ $forwards : 1 ,
346+ $infinite : 1 ,
347+ $linear : 1 ,
348+ $none : Infinity , // No matter how many times you write none, it will never be an animation name
349+ $normal : 1 ,
350+ $paused : 1 ,
351+ $reverse : 1 ,
352+ $running : 1 ,
353+ "$step-end" : 1 ,
354+ "$step-start" : 1 ,
355+ $initial : Infinity ,
356+ $inherit : Infinity ,
357+ $unset : Infinity ,
358+ } ;
359+
360+ const didParseAnimationName = false ;
361+ let parsedAnimationKeywords = { } ;
362+ let stepsFunctionNode = null ;
363+ const valueNodes = valueParser ( decl . value ) . walk ( ( node ) => {
364+ /* If div-token appeared (represents as comma ','), a possibility of an animation-keywords should be reflesh. */
365+ if ( node . type === "div" ) {
366+ parsedAnimationKeywords = { } ;
367+ }
368+ if ( node . type === "function" && node . value . toLowerCase ( ) === "steps" ) {
369+ stepsFunctionNode = node ;
370+ }
371+ const value =
372+ node . type === "word" &&
373+ ! isWordAFunctionArgument ( node , stepsFunctionNode )
374+ ? node . value . toLowerCase ( )
375+ : null ;
376+
377+ let shouldParseAnimationName = false ;
378+
379+ if ( ! didParseAnimationName && value && validIdent . test ( value ) ) {
380+ if ( "$" + value in animationKeywords ) {
381+ parsedAnimationKeywords [ "$" + value ] =
382+ "$" + value in parsedAnimationKeywords
383+ ? parsedAnimationKeywords [ "$" + value ] + 1
384+ : 0 ;
385+
386+ shouldParseAnimationName =
387+ parsedAnimationKeywords [ "$" + value ] >=
388+ animationKeywords [ "$" + value ] ;
389+ } else {
390+ shouldParseAnimationName = true ;
391+ }
392+ }
393+
394+ const subContext = {
395+ options : context . options ,
396+ global : context . global ,
397+ localizeNextItem : shouldParseAnimationName && ! context . global ,
398+ localAliasMap : context . localAliasMap ,
399+ } ;
400+ return localizeDeclNode ( node , subContext ) ;
401+ } ) ;
402+
403+ decl . value = valueNodes . toString ( ) ;
404+
405+ return ;
408406 }
409407
410408 const isAnimationName = / a n i m a t i o n ( - n a m e ) ? $ / i. test ( decl . prop ) ;
@@ -444,7 +442,7 @@ module.exports = (options = {}) => {
444442 const localAliasMap = new Map ( ) ;
445443
446444 return {
447- Once ( root ) {
445+ Root ( root ) {
448446 const { icssImports } = extractICSS ( root , false ) ;
449447
450448 Object . keys ( icssImports ) . forEach ( ( key ) => {
0 commit comments