@@ -85,13 +85,19 @@ const plugin = (options = {}) => {
8585 const generateExportEntry =
8686 ( options && options . generateExportEntry ) || plugin . generateExportEntry ;
8787 const exportGlobals = options && options . exportGlobals ;
88+ const exportEmptyLocals =
89+ ! options ||
90+ ( typeof options . exportEmptyLocals === "undefined" ||
91+ options . exportEmptyLocals === null
92+ ? true
93+ : options . exportEmptyLocals ) ;
8894
8995 return {
9096 postcssPlugin : "postcss-modules-scope" ,
9197 Once ( root , { rule } ) {
9298 const exports = Object . create ( null ) ;
9399
94- function exportScopedName ( name , rawName ) {
100+ function exportScopedName ( name , rawName , includeSelfReference ) {
95101 const scopedName = generateScopedName (
96102 rawName ? rawName : name ,
97103 root . source . input . from ,
@@ -107,30 +113,32 @@ const plugin = (options = {}) => {
107113
108114 exports [ key ] = exports [ key ] || [ ] ;
109115
110- if ( exports [ key ] . indexOf ( value ) < 0 ) {
116+ if ( includeSelfReference && exports [ key ] . indexOf ( value ) < 0 ) {
111117 exports [ key ] . push ( value ) ;
112118 }
113119
114120 return scopedName ;
115121 }
116122
117- function localizeNode ( node ) {
123+ function localizeNode ( node , exportSelfReference ) {
118124 switch ( node . type ) {
119125 case "selector" :
120- node . nodes = node . map ( localizeNode ) ;
126+ node . nodes = node . map ( ( n ) => localizeNode ( n , exportSelfReference ) ) ;
121127 return node ;
122128 case "class" :
123129 return selectorParser . className ( {
124130 value : exportScopedName (
125131 node . value ,
126- node . raws && node . raws . value ? node . raws . value : null
132+ node . raws && node . raws . value ? node . raws . value : null ,
133+ exportSelfReference
127134 ) ,
128135 } ) ;
129136 case "id" : {
130137 return selectorParser . id ( {
131138 value : exportScopedName (
132139 node . value ,
133- node . raws && node . raws . value ? node . raws . value : null
140+ node . raws && node . raws . value ? node . raws . value : null ,
141+ exportSelfReference
134142 ) ,
135143 } ) ;
136144 }
@@ -141,15 +149,15 @@ const plugin = (options = {}) => {
141149 ) ;
142150 }
143151
144- function traverseNode ( node ) {
152+ function traverseNode ( node , exportSelfReference ) {
145153 switch ( node . type ) {
146154 case "pseudo" :
147155 if ( node . value === ":local" ) {
148156 if ( node . nodes . length !== 1 ) {
149157 throw new Error ( 'Unexpected comma (",") in :local block' ) ;
150158 }
151159
152- const selector = localizeNode ( node . first ) ;
160+ const selector = localizeNode ( node . first , exportSelfReference ) ;
153161 // move the spaces that were around the psuedo selector to the first
154162 // non-container node
155163 selector . first . spaces = node . spaces ;
@@ -172,7 +180,7 @@ const plugin = (options = {}) => {
172180 /* falls through */
173181 case "root" :
174182 case "selector" : {
175- node . each ( traverseNode ) ;
183+ node . each ( ( n ) => traverseNode ( n , exportSelfReference ) ) ;
176184 break ;
177185 }
178186 case "id" :
@@ -197,8 +205,14 @@ const plugin = (options = {}) => {
197205 // Find any :local selectors
198206 root . walkRules ( ( rule ) => {
199207 let parsedSelector = selectorParser ( ) . astSync ( rule ) ;
208+ const containsOwnDeclarations = rule . nodes . some (
209+ ( node ) => node . prop !== "composes" && node . prop !== "compose-with"
210+ ) ;
200211
201- rule . selector = traverseNode ( parsedSelector . clone ( ) ) . toString ( ) ;
212+ rule . selector = traverseNode (
213+ parsedSelector . clone ( ) ,
214+ exportEmptyLocals || containsOwnDeclarations
215+ ) . toString ( ) ;
202216
203217 rule . walkDecls ( / c o m p o s e s | c o m p o s e - w i t h / i, ( decl ) => {
204218 const localNames = getSingleLocalNamesForComposes ( parsedSelector ) ;
@@ -249,7 +263,7 @@ const plugin = (options = {}) => {
249263 const input = localMatch . input ;
250264 const matchPattern = localMatch [ 0 ] ;
251265 const matchVal = localMatch [ 1 ] ;
252- const newVal = exportScopedName ( matchVal ) ;
266+ const newVal = exportScopedName ( matchVal , undefined , true ) ;
253267
254268 result = input . replace ( matchPattern , newVal ) ;
255269 } else {
@@ -274,11 +288,13 @@ const plugin = (options = {}) => {
274288 return ;
275289 }
276290
277- atRule . params = exportScopedName ( localMatch [ 1 ] ) ;
291+ atRule . params = exportScopedName ( localMatch [ 1 ] , undefined , true ) ;
278292 } ) ;
279293
280294 // 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+ ) ;
282298
283299 if ( exportedNames . length > 0 ) {
284300 const exportRule = rule ( { selector : ":export" } ) ;
0 commit comments