Skip to content

Commit 576ce3d

Browse files
feat: generateExportEntry option (css-modules#12)
1 parent 2e34607 commit 576ce3d

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

src/index.js

+45-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ function getSingleLocalNamesForComposes(root) {
1212
`composition is only allowed when selector is single :local class name not in "${root}"`
1313
);
1414
}
15+
1516
node = node.nodes[0];
17+
1618
if (
1719
node.type !== 'pseudo' ||
1820
node.value !== ':local' ||
@@ -26,7 +28,9 @@ function getSingleLocalNamesForComposes(root) {
2628
'" is weird'
2729
);
2830
}
31+
2932
node = node.first;
33+
3034
if (node.type !== 'selector' || node.length !== 1) {
3135
throw new Error(
3236
'composition is only allowed when selector is single :local class name not in "' +
@@ -36,7 +40,9 @@ function getSingleLocalNamesForComposes(root) {
3640
'" is weird'
3741
);
3842
}
43+
3944
node = node.first;
45+
4046
if (node.type !== 'class') {
4147
// 'id' is not possible, because you can't compose ids
4248
throw new Error(
@@ -47,6 +53,7 @@ function getSingleLocalNamesForComposes(root) {
4753
'" is weird'
4854
);
4955
}
56+
5057
return node.value;
5158
});
5259
}
@@ -77,6 +84,8 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
7784
return css => {
7885
const generateScopedName =
7986
(options && options.generateScopedName) || processor.generateScopedName;
87+
const generateExportEntry =
88+
(options && options.generateExportEntry) || processor.generateExportEntry;
8089

8190
const exports = Object.create(null);
8291

@@ -86,13 +95,18 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
8695
css.source.input.from,
8796
css.source.input.css
8897
);
98+
const exportEntry = generateExportEntry(
99+
rawName ? rawName : name,
100+
scopedName,
101+
css.source.input.from,
102+
css.source.input.css
103+
);
104+
const { key, value } = exportEntry;
89105

90-
exports[name] = exports[name] || [];
91-
92-
const unescapedScopedName = unescape(scopedName);
106+
exports[key] = exports[key] || [];
93107

94-
if (exports[name].indexOf(unescapedScopedName) < 0) {
95-
exports[name].push(unescapedScopedName);
108+
if (exports[key].indexOf(value) < 0) {
109+
exports[key].push(value);
96110
}
97111

98112
return scopedName;
@@ -119,6 +133,7 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
119133
});
120134
}
121135
}
136+
122137
throw new Error(
123138
`${node.type} ("${node}") is not allowed in a :local block`
124139
);
@@ -131,12 +146,14 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
131146
if (node.nodes.length !== 1) {
132147
throw new Error('Unexpected comma (",") in :local block');
133148
}
149+
134150
const selector = localizeNode(node.first, node.spaces);
135151
// move the spaces that were around the psuedo selector to the first
136152
// non-container node
137153
selector.first.spaces = node.spaces;
138154

139155
node.replaceWith(selector);
156+
140157
return;
141158
}
142159
/* falls through */
@@ -151,6 +168,7 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
151168

152169
// Find any :import and remember imported names
153170
const importedNames = {};
171+
154172
css.walkRules(rule => {
155173
if (/^:import\(.+\)$/.test(rule.selector)) {
156174
rule.walkDecls(decl => {
@@ -173,10 +191,11 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
173191
let parsedSelector = selectorParser().astSync(rule);
174192

175193
rule.selector = traverseNode(parsedSelector.clone()).toString();
176-
// console.log(rule.selector);
194+
177195
rule.walkDecls(/composes|compose-with/, decl => {
178196
const localNames = getSingleLocalNamesForComposes(parsedSelector);
179197
const classes = decl.value.split(/\s+/);
198+
180199
classes.forEach(className => {
181200
const global = /^global\(([^\)]+)\)$/.exec(className);
182201

@@ -200,14 +219,17 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
200219
);
201220
}
202221
});
222+
203223
decl.remove();
204224
});
205225

206226
rule.walkDecls(decl => {
207-
var tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);
227+
let tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);
228+
208229
tokens = tokens.map((token, idx) => {
209230
if (idx === 0 || tokens[idx - 1] === ',') {
210231
const localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token);
232+
211233
if (localMatch) {
212234
return (
213235
localMatch[1] +
@@ -221,14 +243,16 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
221243
return token;
222244
}
223245
});
246+
224247
decl.value = tokens.join('');
225248
});
226249
});
227250

228251
// Find any :local keyframes
229252
css.walkAtRules(atrule => {
230253
if (/keyframes$/i.test(atrule.name)) {
231-
var localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params);
254+
const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params);
255+
232256
if (localMatch) {
233257
atrule.params = exportScopedName(localMatch[1]);
234258
}
@@ -237,26 +261,37 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
237261

238262
// If we found any :locals, insert an :export rule
239263
const exportedNames = Object.keys(exports);
264+
240265
if (exportedNames.length > 0) {
241266
const exportRule = postcss.rule({ selector: ':export' });
267+
242268
exportedNames.forEach(exportedName =>
243269
exportRule.append({
244270
prop: exportedName,
245271
value: exports[exportedName].join(' '),
246272
raws: { before: '\n ' },
247273
})
248274
);
275+
249276
css.append(exportRule);
250277
}
251278
};
252279
});
253280

254-
processor.generateScopedName = function(exportedName, path) {
281+
processor.generateScopedName = function(name, path) {
255282
const sanitisedPath = path
256283
.replace(/\.[^\.\/\\]+$/, '')
257284
.replace(/[\W_]+/g, '_')
258285
.replace(/^_|_$/g, '');
259-
return `_${sanitisedPath}__${exportedName}`.trim();
286+
287+
return `_${sanitisedPath}__${name}`.trim();
288+
};
289+
290+
processor.generateExportEntry = function(name, scopedName) {
291+
return {
292+
key: unescape(name),
293+
value: unescape(scopedName),
294+
};
260295
};
261296

262297
module.exports = processor;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
._input__exportName {
2+
color: green;
3+
}
4+
5+
._input__exportName:hover {
6+
color: red;
7+
}
8+
9+
:export {
10+
_exportName_: __input__exportName_;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
generateExportEntry: function(name, scopedName) {
3+
return {
4+
key: `_${name}_`,
5+
value: `_${scopedName}_`
6+
}
7+
},
8+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
:local(.exportName) {
2+
color: green;
3+
}
4+
5+
:local(.exportName):hover {
6+
color: red;
7+
}

0 commit comments

Comments
 (0)