Skip to content
This repository was archived by the owner on Oct 30, 2020. It is now read-only.

Commit b0a97b4

Browse files
committed
add option namedExport
- allow named exports via `namedExport` flag - add warnings if `namedExport` is used without camelCase option for css-loader and classes would get lost
1 parent b851c0b commit b0a97b4

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

src/cssModuleToInterface.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,34 @@ const cssModuleToTypescriptInterfaceProperties = (cssModuleKeys, indent = ' ')
1212
.join('\n');
1313
};
1414

15+
const cssModuleToNamedExports = (cssModuleKeys) => {
16+
return cssModuleKeys
17+
.map((key) => `export const ${key}: string;`)
18+
.join('\n');
19+
};
20+
21+
const allWordsRegexp = /^\w+$/i;
22+
export const filterNonWordClasses = (cssModuleKeys) => {
23+
const filteredClassNames = cssModuleKeys.filter(classname => allWordsRegexp.test(classname));
24+
if (filteredClassNames.length === cssModuleKeys.length) {
25+
return [filteredClassNames, []];
26+
}
27+
const nonWordClassNames = cssModuleKeys.filter(classname => !allWordsRegexp.test(classname));
28+
return [filteredClassNames, nonWordClassNames];
29+
}
30+
1531
export const filenameToTypingsFilename = (filename) => {
1632
const dirName = path.dirname(filename);
1733
const baseName = path.basename(filename);
1834
return path.join(dirName, `${baseName}.d.ts`);
1935
};
2036

37+
export const generateNamedExports = (cssModuleKeys) => {
38+
const namedExports = cssModuleToNamedExports(cssModuleKeys);
39+
return (`${namedExports}
40+
`);
41+
};
42+
2143
export const generateGenericExportInterface = (cssModuleKeys, filename, indent) => {
2244
const interfaceName = filenameToInterfaceName(filename);
2345
const interfaceProperties = cssModuleToTypescriptInterfaceProperties(cssModuleKeys, indent);

src/index.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import cssLoader from 'css-loader';
22
import cssLocalsLoader from 'css-loader/locals';
33
import loaderUtils from 'loader-utils';
44
import {
5+
filterNonWordClasses,
6+
generateNamedExports,
57
generateGenericExportInterface,
68
filenameToTypingsFilename,
79
} from './cssModuleToInterface';
@@ -27,13 +29,25 @@ module.exports = function(input) {
2729

2830
// mock async step 2 - offer css loader a "fake" callback
2931
this.async = () => (err, content) => {
30-
const requestedResource = this.resourcePath;
31-
const cssModuleInterfaceFilename = filenameToTypingsFilename(requestedResource);
32+
const filename = this.resourcePath;
33+
const cssModuleInterfaceFilename = filenameToTypingsFilename(filename);
3234

3335
let cssModuleKeys = Object.keys(this.exec(content, this.resource));
3436

35-
const cssModuleInterface = generateGenericExportInterface(cssModuleKeys, requestedResource);
36-
persist.writeToFileIfChanged(cssModuleInterfaceFilename, cssModuleInterface);
37+
let cssModuleDefinition;
38+
if (!query.namedExport) {
39+
cssModuleDefinition = generateGenericExportInterface(cssModuleKeys, filename);
40+
} else {
41+
const [cleanedDefinitions, skippedDefinitions] = filterNonWordClasses(cssModuleKeys);
42+
if (skippedDefinitions.length > 0 && !query.camelCase) {
43+
console.warn(`Typings for CSS-Modules: option 'namedExport' was set but 'camelCase' for the css-loader not.
44+
The following classes will not be available as named exports:
45+
${skippedDefinitions.map(sd => ` - "${sd}"`).join('\n')}
46+
`)
47+
}
48+
cssModuleDefinition = generateNamedExports(cleanedDefinitions);
49+
}
50+
persist.writeToFileIfChanged(cssModuleInterfaceFilename, cssModuleDefinition);
3751
// mock async step 3 - make `async` return the actual callback again before calling the 'real' css-loader
3852
delegateToCssLoader(this, input, callback);
3953
};

0 commit comments

Comments
 (0)