@@ -85,13 +85,19 @@ const plugin = (options = {}) => {
85
85
const generateExportEntry =
86
86
( options && options . generateExportEntry ) || plugin . generateExportEntry ;
87
87
const exportGlobals = options && options . exportGlobals ;
88
+ const exportEmptyLocals =
89
+ ! options ||
90
+ ( typeof options . exportEmptyLocals === "undefined" ||
91
+ options . exportEmptyLocals === null
92
+ ? true
93
+ : options . exportEmptyLocals ) ;
88
94
89
95
return {
90
96
postcssPlugin : "postcss-modules-scope" ,
91
97
Once ( root , { rule } ) {
92
98
const exports = Object . create ( null ) ;
93
99
94
- function exportScopedName ( name , rawName ) {
100
+ function exportScopedName ( name , rawName , includeSelfReference ) {
95
101
const scopedName = generateScopedName (
96
102
rawName ? rawName : name ,
97
103
root . source . input . from ,
@@ -107,30 +113,32 @@ const plugin = (options = {}) => {
107
113
108
114
exports [ key ] = exports [ key ] || [ ] ;
109
115
110
- if ( exports [ key ] . indexOf ( value ) < 0 ) {
116
+ if ( includeSelfReference && exports [ key ] . indexOf ( value ) < 0 ) {
111
117
exports [ key ] . push ( value ) ;
112
118
}
113
119
114
120
return scopedName ;
115
121
}
116
122
117
- function localizeNode ( node ) {
123
+ function localizeNode ( node , exportSelfReference ) {
118
124
switch ( node . type ) {
119
125
case "selector" :
120
- node . nodes = node . map ( localizeNode ) ;
126
+ node . nodes = node . map ( ( n ) => localizeNode ( n , exportSelfReference ) ) ;
121
127
return node ;
122
128
case "class" :
123
129
return selectorParser . className ( {
124
130
value : exportScopedName (
125
131
node . value ,
126
- node . raws && node . raws . value ? node . raws . value : null
132
+ node . raws && node . raws . value ? node . raws . value : null ,
133
+ exportSelfReference
127
134
) ,
128
135
} ) ;
129
136
case "id" : {
130
137
return selectorParser . id ( {
131
138
value : exportScopedName (
132
139
node . value ,
133
- node . raws && node . raws . value ? node . raws . value : null
140
+ node . raws && node . raws . value ? node . raws . value : null ,
141
+ exportSelfReference
134
142
) ,
135
143
} ) ;
136
144
}
@@ -141,15 +149,15 @@ const plugin = (options = {}) => {
141
149
) ;
142
150
}
143
151
144
- function traverseNode ( node ) {
152
+ function traverseNode ( node , exportSelfReference ) {
145
153
switch ( node . type ) {
146
154
case "pseudo" :
147
155
if ( node . value === ":local" ) {
148
156
if ( node . nodes . length !== 1 ) {
149
157
throw new Error ( 'Unexpected comma (",") in :local block' ) ;
150
158
}
151
159
152
- const selector = localizeNode ( node . first ) ;
160
+ const selector = localizeNode ( node . first , exportSelfReference ) ;
153
161
// move the spaces that were around the psuedo selector to the first
154
162
// non-container node
155
163
selector . first . spaces = node . spaces ;
@@ -172,7 +180,7 @@ const plugin = (options = {}) => {
172
180
/* falls through */
173
181
case "root" :
174
182
case "selector" : {
175
- node . each ( traverseNode ) ;
183
+ node . each ( ( n ) => traverseNode ( n , exportSelfReference ) ) ;
176
184
break ;
177
185
}
178
186
case "id" :
@@ -197,8 +205,14 @@ const plugin = (options = {}) => {
197
205
// Find any :local selectors
198
206
root . walkRules ( ( rule ) => {
199
207
let parsedSelector = selectorParser ( ) . astSync ( rule ) ;
208
+ const containsOwnDeclarations = rule . nodes . some (
209
+ ( node ) => node . prop !== "composes" && node . prop !== "compose-with"
210
+ ) ;
200
211
201
- rule . selector = traverseNode ( parsedSelector . clone ( ) ) . toString ( ) ;
212
+ rule . selector = traverseNode (
213
+ parsedSelector . clone ( ) ,
214
+ exportEmptyLocals || containsOwnDeclarations
215
+ ) . toString ( ) ;
202
216
203
217
rule . walkDecls ( / c o m p o s e s | c o m p o s e - w i t h / i, ( decl ) => {
204
218
const localNames = getSingleLocalNamesForComposes ( parsedSelector ) ;
@@ -249,7 +263,7 @@ const plugin = (options = {}) => {
249
263
const input = localMatch . input ;
250
264
const matchPattern = localMatch [ 0 ] ;
251
265
const matchVal = localMatch [ 1 ] ;
252
- const newVal = exportScopedName ( matchVal ) ;
266
+ const newVal = exportScopedName ( matchVal , undefined , true ) ;
253
267
254
268
result = input . replace ( matchPattern , newVal ) ;
255
269
} else {
@@ -274,11 +288,13 @@ const plugin = (options = {}) => {
274
288
return ;
275
289
}
276
290
277
- atRule . params = exportScopedName ( localMatch [ 1 ] ) ;
291
+ atRule . params = exportScopedName ( localMatch [ 1 ] , undefined , true ) ;
278
292
} ) ;
279
293
280
294
// If we found any :locals, insert an :export rule
281
- const exportedNames = Object . keys ( exports ) ;
295
+ const exportedNames = Object . keys ( exports ) . filter (
296
+ ( exportedName ) => exports [ exportedName ] . length !== 0
297
+ ) ;
282
298
283
299
if ( exportedNames . length > 0 ) {
284
300
const exportRule = rule ( { selector : ":export" } ) ;
0 commit comments