@@ -19,20 +19,21 @@ function normalizeNodeArray(nodes) {
19
19
}
20
20
} ) ;
21
21
22
- if ( array . length > 0 && array [ array . length - 1 ] . type === 'spacing' ) {
22
+ if ( array . length > 0 && isSpacing ( array [ array . length - 1 ] ) ) {
23
23
array . pop ( ) ;
24
24
}
25
25
return array ;
26
26
}
27
27
28
28
function checkForInconsistentRule ( node , current , context ) {
29
- if ( context . isGlobal !== context . lastIsGlobal )
29
+ if ( context . global !== context . lastIsGlobal )
30
30
throw new Error (
31
31
'Inconsistent rule global/local result in rule "' +
32
32
String ( node ) +
33
33
'" (multiple selectors must result in the same mode for the rule)'
34
34
) ;
35
35
}
36
+ const isSpacing = node => node . type === 'combinator' && node . value === ' ' ;
36
37
37
38
function trimSelectors ( selector ) {
38
39
let last ;
@@ -45,169 +46,191 @@ function trimSelectors(selector) {
45
46
}
46
47
47
48
function localizeNodez ( rule , mode , options ) {
48
- // console.log(mode);
49
49
const isScopePseudo = node =>
50
50
node . value === ':local' || node . value === ':global' ;
51
51
52
52
const transform = ( node , context ) => {
53
+ if ( context . ignoreNextSpacing && ! isSpacing ( node ) ) {
54
+ throw new Error ( 'Missing whitespace after ' + context . ignoreNextSpacing ) ;
55
+ }
56
+ if ( context . enforceNoSpacing && isSpacing ( node ) ) {
57
+ throw new Error ( 'Missing whitespace before ' + context . enforceNoSpacing ) ;
58
+ }
59
+
60
+ let newNodes ;
53
61
switch ( node . type ) {
54
62
case 'root' : {
55
- const childContext = { ...context } ;
56
- let overallIsGlobal ;
57
-
58
- node . each ( childNode => {
59
- // isGlobal and hasLocals should not carry over across selectors:
60
- // `:global .foo, .bar -> .foo, :local(.bar)`
61
- childContext . isGlobal = context . isGlobal ;
62
- childContext . hasLocals = false ;
63
-
64
- transform ( childNode , childContext ) ;
65
-
66
- console . log ( overallIsGlobal , childContext ) ;
67
-
68
- if ( overallIsGlobal == null ) {
69
- overallIsGlobal = childContext . isGlobal ;
70
- } else {
71
- if ( overallIsGlobal !== childContext . isGlobal )
72
- throw new Error (
73
- 'Inconsistent rule global/local result in rule "' +
74
- String ( node ) +
75
- '" (multiple selectors must result in the same mode for the rule)'
76
- ) ;
63
+ let resultingGlobal ;
64
+ context . hasPureGlobals = false ;
65
+ newNodes = node . nodes . map ( function ( n ) {
66
+ const nContext = {
67
+ global : context . global ,
68
+ lastWasSpacing : true ,
69
+ hasLocals : false ,
70
+ explicit : false ,
71
+ } ;
72
+ n = transform ( n , nContext ) ;
73
+ if ( typeof resultingGlobal === 'undefined' ) {
74
+ resultingGlobal = nContext . global ;
75
+ } else if ( resultingGlobal !== nContext . global ) {
76
+ throw new Error (
77
+ 'Inconsistent rule global/local result in rule "' +
78
+ node +
79
+ '" (multiple selectors must result in the same mode for the rule)'
80
+ ) ;
77
81
}
78
-
79
- if ( childContext . hasLocals ) {
80
- context . hasPureGlobals = false ;
82
+ if ( ! nContext . hasLocals ) {
83
+ context . hasPureGlobals = true ;
81
84
}
85
+ return n ;
82
86
} ) ;
87
+ context . global = resultingGlobal ;
83
88
89
+ node . nodes = normalizeNodeArray ( newNodes ) ;
90
+ // console.log(node.nodes);
84
91
break ;
85
92
}
86
93
case 'selector' : {
87
- node . each ( childNode => transform ( childNode , context ) ) ;
88
-
89
- trimSelectors ( node ) ;
94
+ newNodes = node . map ( childNode => transform ( childNode , context ) ) ;
90
95
96
+ node = node . clone ( ) ;
97
+ node . nodes = normalizeNodeArray ( newNodes ) ;
98
+ console . log ( 'SECLE' , node . toString ( ) ) ;
91
99
break ;
92
100
}
93
101
case 'combinator' : {
94
- if (
95
- node . value === ' ' &&
96
- ( context . shouldTrimTrainingWhitespace || ! node . next ( ) )
97
- ) {
98
- //console.log('COMBIN', node.spaces) ;
99
- context . shouldTrimTrainingWhitespace = false ;
100
- node . remove ( ) ;
102
+ if ( ! isSpacing ( node ) ) break ;
103
+
104
+ if ( context . ignoreNextSpacing ) {
105
+ context . ignoreNextSpacing = false ;
106
+ context . lastWasSpacing = false ;
107
+ context . enforceNoSpacing = false ;
108
+ return null ;
101
109
}
110
+ context . lastWasSpacing = true ;
102
111
break ;
103
112
}
104
113
case 'pseudo' : {
105
- if ( ! isScopePseudo ( node ) ) {
106
- // This needs to not update `isGlobal` for tests to pass
107
- // the behavior seems _wrong_ tho.
108
- const childContext = { ...context } ;
109
- console . log ( 'PSEUEDO' , node . value , context ) ;
110
- node . each ( childNode => transform ( childNode , context ) ) ;
111
- break ;
112
- }
113
-
114
- if ( context . inside ) {
115
- throw new Error (
116
- `A ${ node . value } is not allowed inside of a ${ context . inside } (...)`
117
- ) ;
118
- }
119
-
114
+ let childContext ;
120
115
const isNested = ! ! node . length ;
121
- const isGlobal = node . value === ':global' ;
122
- if ( ! isNested ) {
123
- context . isGlobal = isGlobal ;
116
+ const isScoped = isScopePseudo ( node ) ;
124
117
125
- context . shouldTrimTrainingWhitespace = ! node . spaces . before ;
126
- // console.log(node.spaces);
127
- node . remove ( ) ;
128
- return null ;
129
- }
130
-
131
- const childContext = {
132
- ...context ,
133
- isGlobal,
134
- inside : node . value ,
135
- hasLocals : false ,
136
- } ;
137
-
138
- // The nodes of a psuedo will be Selectors, which we want to flatten
139
- // into the parent
140
- const nodes = node
141
- . clone ( )
142
- . map ( childNode => transform ( childNode , childContext ) )
143
- . reduce (
144
- ( acc , next ) =>
145
- acc . concat ( next . type === 'selector' ? next . nodes : next ) ,
146
- [ ]
147
- ) ;
148
- // console.log(context);
149
- if ( childContext . hasLocals ) {
150
- context . hasLocals = true ;
151
- }
118
+ // :local(.foo)
119
+ if ( isNested ) {
120
+ if ( isScoped ) {
121
+ if ( context . inside ) {
122
+ throw new Error (
123
+ `A ${ node . value } is not allowed inside of a ${
124
+ context . inside
125
+ } (...)`
126
+ ) ;
127
+ }
128
+
129
+ childContext = {
130
+ global : node . value === ':global' ,
131
+ inside : node . value ,
132
+ hasLocals : false ,
133
+ explicit : true ,
134
+ } ;
135
+ // console.log('PSUDI', node.nodes);
136
+
137
+ newNodes = node
138
+ . map ( childNode => transform ( childNode , childContext ) )
139
+ . reduce ( ( acc , next ) => acc . concat ( next . nodes ) , [ ] ) ;
140
+
141
+ if ( newNodes . length ) {
142
+ const { before, after } = node . spaces ;
143
+
144
+ const first = newNodes [ 0 ] ;
145
+ const last = newNodes [ newNodes . length - 1 ] ;
146
+
147
+ first . spaces = { before, after : first . spaces . after } ;
148
+ last . spaces = { before : last . spaces . before , after } ;
149
+ }
150
+ console . log ( 'PSUDI' , node ) ;
151
+ node = newNodes ;
152
+
153
+ // // don't leak spacing
154
+ // node[0].spaces.before = '';
155
+ // node[node.length - 1].spaces.after = '';
156
+ break ;
157
+ } else {
158
+ childContext = {
159
+ global : context . global ,
160
+ inside : context . inside ,
161
+ lastWasSpacing : true ,
162
+ hasLocals : false ,
163
+ explicit : context . explicit ,
164
+ } ;
165
+ newNodes = node . map ( childNode =>
166
+ transform ( childNode , childContext )
167
+ ) ;
152
168
153
- // console.log('asfasfasf', nodes);
169
+ node = node . clone ( ) ;
170
+ node . nodes = normalizeNodeArray ( newNodes ) ;
154
171
155
- if ( nodes . length ) {
156
- const { before, after } = node . spaces ;
172
+ if ( childContext . hasLocals ) {
173
+ context . hasLocals = true ;
174
+ }
175
+ }
176
+ break ;
157
177
158
- const first = nodes [ 0 ] ;
159
- const last = nodes [ node . length - 1 ] ;
178
+ //:local .foo .bar
179
+ } else if ( isScoped ) {
180
+ if ( context . inside ) {
181
+ throw new Error (
182
+ `A ${ node . value } is not allowed inside of a ${
183
+ context . inside
184
+ } (...)`
185
+ ) ;
186
+ }
160
187
161
- first . spaces = { before, after : first . spaces . after } ;
162
- last . spaces = { before : last . spaces . before , after } ;
188
+ const next = node . next ( ) ;
189
+ console . log ( 'SPACESS' , next , node . spaces ) ;
190
+ if ( next ) next . spaces = node . spaces ;
191
+
192
+ context . ignoreNextSpacing = context . lastWasSpacing
193
+ ? node . value
194
+ : false ;
195
+ context . enforceNoSpacing = context . lastWasSpacing
196
+ ? false
197
+ : node . value ;
198
+ context . global = node . value === ':global' ;
199
+ context . explicit = true ;
200
+ return null ;
163
201
}
164
-
165
- nodes . forEach ( childNode => {
166
- node . parent . insertBefore ( node , childNode ) ;
167
- } ) ;
168
- node . remove ( ) ;
169
- // const parent = node.parent;
170
- // node.replaceWith(nodes[0].nodes);
171
- // console.log('asfasfasf', nodes, String(parent.parent));
172
- return nodes ;
202
+ break ;
173
203
}
174
204
case 'id' :
175
205
case 'class' : {
176
- const spaces = { ...node . spaces } ;
177
-
178
- if ( context . shouldTrimTrainingWhitespace ) {
179
- // console.log('HEREEEEEE', spaces);
180
- spaces . before = '' ;
181
- context . shouldTrimTrainingWhitespace = false ;
182
- }
183
-
184
- if ( ! context . isGlobal ) {
185
- // console.log('REPLCE', node.spaces);
206
+ if ( ! context . global ) {
207
+ console . log ( 'REPLCE' , node . spaces ) ;
186
208
const innerNode = node . clone ( ) ;
209
+ console . log ( innerNode ) ;
187
210
innerNode . spaces = { before : '' , after : '' } ;
188
211
189
- // console.log(node);
190
- node . replaceWith (
191
- selectorParser . pseudo ( {
192
- value : ':local' ,
193
- nodes : [ innerNode ] ,
194
- spaces,
195
- } )
196
- ) ;
212
+ node = selectorParser . pseudo ( {
213
+ value : ':local' ,
214
+ nodes : [ innerNode ] ,
215
+ spaces : node . spaces ,
216
+ } ) ;
197
217
// console.log('HERE');
198
218
context . hasLocals = true ;
199
219
}
200
220
201
221
break ;
202
222
}
203
223
}
224
+
225
+ context . lastWasSpacing = false ;
226
+ context . ignoreNextSpacing = false ;
227
+ context . enforceNoSpacing = false ;
204
228
return node ;
205
229
} ;
206
230
207
- const isGlobal = mode === 'global' ;
208
231
const rootContext = {
209
- isGlobal ,
210
- hasPureGlobals : true ,
232
+ global : mode === 'global' ,
233
+ hasPureGlobals : false ,
211
234
} ;
212
235
213
236
const updatedRule = selectorParser ( root => {
@@ -239,7 +262,7 @@ function localizeDeclNode(node, context) {
239
262
}
240
263
241
264
let newUrl = context . options . rewriteUrl (
242
- context . isGlobal ,
265
+ context . global ,
243
266
nestedNode . value
244
267
) ;
245
268
@@ -349,8 +372,8 @@ function localizeAnimationShorthandDeclValues(decl, context) {
349
372
350
373
const subContext = {
351
374
options : context . options ,
352
- isGlobal : context . isGlobal ,
353
- localizeNextItem : shouldParseAnimationName && ! context . isGlobal ,
375
+ global : context . global ,
376
+ localizeNextItem : shouldParseAnimationName && ! context . global ,
354
377
} ;
355
378
return localizeDeclNode ( node , subContext ) ;
356
379
} ) ;
@@ -363,8 +386,8 @@ function localizeDeclValues(localize, decl, context) {
363
386
valueNodes . walk ( ( node , index , nodes ) => {
364
387
const subContext = {
365
388
options : context . options ,
366
- isGlobal : context . isGlobal ,
367
- localizeNextItem : localize && ! context . isGlobal ,
389
+ global : context . global ,
390
+ localizeNextItem : localize && ! context . global ,
368
391
} ;
369
392
nodes [ index ] = localizeDeclNode ( node , subContext ) ;
370
393
} ) ;
@@ -433,15 +456,15 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function(
433
456
atrule . walkDecls ( function ( decl ) {
434
457
localizeDecl ( decl , {
435
458
options : options ,
436
- isGlobal : globalKeyframes ,
459
+ global : globalKeyframes ,
437
460
} ) ;
438
461
} ) ;
439
462
} else if ( atrule . nodes ) {
440
463
atrule . nodes . forEach ( function ( decl ) {
441
464
if ( decl . type === 'decl' ) {
442
465
localizeDecl ( decl , {
443
466
options : options ,
444
- isGlobal : globalMode ,
467
+ global : globalMode ,
445
468
} ) ;
446
469
}
447
470
} ) ;
0 commit comments