@@ -4,125 +4,104 @@ import Tokenizer from "css-selector-tokenizer";
4
4
5
5
const plugin = "postcss-modules-local-by-default" ;
6
6
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
+ } ;
23
15
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" ;
31
17
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" ) ;
38
21
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 ] ;
48
30
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 ] ;
52
36
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 ;
59
53
}
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 ] ;
67
55
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
+ ] ;
75
74
}
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 ;
98
75
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
+ } , [ ] ) ;
111
94
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 ) } ) ;
117
96
}
118
97
119
98
const localizeSelectors = ( selectors , mode ) => {
120
99
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
+ } )
124
104
) ;
125
- return Tokenizer . stringify ( node ) ;
126
105
} ;
127
106
128
107
const walkRules = ( css , callback ) => {
0 commit comments