@@ -4,125 +4,104 @@ import Tokenizer from "css-selector-tokenizer";
44
55const plugin = "postcss-modules-local-by-default" ;
66
7- function normalizeNodeArray ( nodes ) {
8- var array = [ ] ;
9- nodes . forEach ( x => {
10- if ( Array . isArray ( x ) ) {
11- normalizeNodeArray ( x ) . forEach ( item => {
12- array . push ( item ) ;
13- } ) ;
14- } else if ( x ) {
15- array . push ( x ) ;
16- }
17- } ) ;
18- if ( array . length > 0 && array [ array . length - 1 ] . type === "spacing" ) {
19- array . pop ( ) ;
20- }
21- return array ;
22- }
7+ const trimNodes = nodes => {
8+ const firstIndex = nodes . findIndex ( node => node . type !== "spacing" ) ;
9+ const lastIndex = nodes
10+ . slice ( )
11+ . reverse ( )
12+ . findIndex ( node => node . type !== "spacing" ) ;
13+ return nodes . slice ( firstIndex , nodes . length - lastIndex ) ;
14+ } ;
2315
24- function localizeNode ( node , context ) {
25- if ( context . ignoreNextSpacing && node . type !== "spacing" ) {
26- throw Error ( `Missing whitespace after :${ context . ignoreNextSpacing } ` ) ;
27- }
28- if ( context . enforceNoSpacing && node . type === "spacing" ) {
29- throw Error ( `Missing whitespace before :${ context . enforceNoSpacing } ` ) ;
30- }
16+ const isSpacing = node => node . type === "spacing" || node . type === "operator" ;
3117
32- switch ( node . type ) {
33- case "selector" :
34- node . nodes = normalizeNodeArray (
35- node . nodes . map ( n => localizeNode ( n , context ) )
36- ) ;
37- break ;
18+ const isModifier = node =>
19+ node . type === "pseudo-class" &&
20+ ( node . name === "local" || node . name === "global" ) ;
3821
39- case "spacing" :
40- if ( context . ignoreNextSpacing ) {
41- context . ignoreNextSpacing = false ;
42- context . lastWasSpacing = false ;
43- context . enforceNoSpacing = false ;
44- return null ;
45- }
46- context . lastWasSpacing = true ;
47- return node ;
22+ function localizeNode ( node , { mode, inside } ) {
23+ const newNodes = node . nodes . reduce ( ( acc , n , index , nodes ) => {
24+ switch ( n . type ) {
25+ case "spacing" :
26+ if ( isModifier ( nodes [ index + 1 ] ) ) {
27+ return [ ...acc , Object . assign ( { } , n , { value : "" } ) ] ;
28+ }
29+ return [ ...acc , n ] ;
4830
49- case "operator" :
50- context . lastWasSpacing = true ;
51- return node ;
31+ case "operator" :
32+ if ( isModifier ( nodes [ index + 1 ] ) ) {
33+ return [ ...acc , Object . assign ( { } , n , { after : "" } ) ] ;
34+ }
35+ return [ ...acc , n ] ;
5236
53- case "pseudo-class" :
54- if ( node . name === "local" || node . name === "global" ) {
55- if ( context . inside ) {
56- throw Error (
57- `A :${ node . name } is not allowed inside of a :${ context . inside } (...)`
58- ) ;
37+ case "pseudo-class" :
38+ if ( isModifier ( n ) ) {
39+ if ( inside ) {
40+ throw Error (
41+ `A :${ n . name } is not allowed inside of a :${ inside } (...)`
42+ ) ;
43+ }
44+ if ( index !== 0 && ! isSpacing ( nodes [ index - 1 ] ) ) {
45+ throw Error ( `Missing whitespace before :${ n . name } ` ) ;
46+ }
47+ if ( index !== nodes . length - 1 && ! isSpacing ( nodes [ index + 1 ] ) ) {
48+ throw Error ( `Missing whitespace after :${ n . name } ` ) ;
49+ }
50+ // set mode
51+ mode = n . name ;
52+ return acc ;
5953 }
60- context . ignoreNextSpacing = context . lastWasSpacing ? node . name : false ;
61- context . enforceNoSpacing = context . lastWasSpacing ? false : node . name ;
62- context . global = node . name === "global" ;
63- context . explicit = true ;
64- return null ;
65- }
66- break ;
54+ return [ ...acc , n ] ;
6755
68- case "nested-pseudo-class" :
69- var subContext ;
70- if ( node . name === "local" || node . name === "global" ) {
71- if ( context . inside ) {
72- throw Error (
73- `A :${ node . name } (...) is not allowed inside of a :${ context . inside } (...)`
74- ) ;
56+ case "nested-pseudo-class" :
57+ if ( n . name === "local" || n . name === "global" ) {
58+ if ( inside ) {
59+ throw Error (
60+ `A :${ n . name } (...) is not allowed inside of a :${ inside } (...)`
61+ ) ;
62+ }
63+ return [
64+ ...acc ,
65+ ...localizeNode ( n . nodes [ 0 ] , { mode : n . name , inside : n . name } ) . nodes
66+ ] ;
67+ } else {
68+ return [
69+ ...acc ,
70+ Object . assign ( { } , n , {
71+ nodes : localizeNode ( n . nodes [ 0 ] , { mode, inside } ) . nodes
72+ } )
73+ ] ;
7574 }
76- subContext = {
77- global : node . name === "global" ,
78- inside : node . name ,
79- hasLocals : false ,
80- explicit : true
81- } ;
82- node = node . nodes . map ( n => localizeNode ( n , subContext ) ) ;
83- // don't leak spacing
84- node [ 0 ] . before = undefined ;
85- node [ node . length - 1 ] . after = undefined ;
86- } else {
87- subContext = {
88- global : context . global ,
89- inside : context . inside ,
90- lastWasSpacing : true ,
91- hasLocals : false ,
92- explicit : context . explicit
93- } ;
94- node . nodes = node . nodes . map ( n => localizeNode ( n , subContext ) ) ;
95- }
96- context . hasLocals = subContext . hasLocals ;
97- break ;
9875
99- case "id" :
100- case "class" :
101- if ( ! context . global ) {
102- node = {
103- type : "nested-pseudo-class" ,
104- name : "local" ,
105- nodes : [ node ]
106- } ;
107- context . hasLocals = true ;
108- }
109- break ;
110- }
76+ case "id" :
77+ case "class" :
78+ if ( mode === "local" ) {
79+ return [
80+ ...acc ,
81+ {
82+ type : "nested-pseudo-class" ,
83+ name : "local" ,
84+ nodes : [ n ]
85+ }
86+ ] ;
87+ }
88+ return [ ...acc , n ] ;
89+
90+ default :
91+ return [ ...acc , n ] ;
92+ }
93+ } , [ ] ) ;
11194
112- // reset context
113- context . lastWasSpacing = false ;
114- context . ignoreNextSpacing = false ;
115- context . enforceNoSpacing = false ;
116- return node ;
95+ return Object . assign ( { } , node , { nodes : trimNodes ( newNodes ) } ) ;
11796}
11897
11998const localizeSelectors = ( selectors , mode ) => {
12099 const node = Tokenizer . parse ( selectors ) ;
121- const global = mode === "global" ;
122- node . nodes = node . nodes . map ( n =>
123- localizeNode ( n , { global, lastWasSpacing : true , hasLocals : false } )
100+ return Tokenizer . stringify (
101+ Object . assign ( { } , node , {
102+ nodes : node . nodes . map ( n => localizeNode ( n , { mode } ) )
103+ } )
124104 ) ;
125- return Tokenizer . stringify ( node ) ;
126105} ;
127106
128107const walkRules = ( css , callback ) => {
0 commit comments