diff --git a/README.md b/README.md index c77e09f..ac8633a 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,25 @@ postcss([ ]); ``` +### Camel cased classes + +If you need, you can pass the options `{ camelCase: true }` to transform classes: + +CSS: +```css +.post-title { + color: red; +} +``` + +JSON: +```json +{ + "post-title": "._post-title_116zl_1", + "postTitle": "._post-title_116zl_1" +} +``` + ## Integration with templates The plugin only transforms CSS classes to CSS modules. diff --git a/package-lock.json b/package-lock.json index f4dbce7..b36092b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4202,6 +4202,11 @@ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", diff --git a/package.json b/package.json index 630d166..fe54ec4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "css-modules-loader-core": "^1.1.0", "generic-names": "^1.0.2", + "lodash.camelcase": "^4.3.0", "postcss": "^6.0.1", "string-hash": "^1.1.1" }, diff --git a/src/index.js b/src/index.js index 1b65a7e..b182be0 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ import postcss from 'postcss'; +import camelCase from 'lodash.camelcase'; import Parser from 'css-modules-loader-core/lib/parser'; import FileSystemLoader from 'css-modules-loader-core/lib/file-system-loader'; import genericNames from 'generic-names'; @@ -77,6 +78,15 @@ module.exports = postcss.plugin(PLUGIN_NAME, (opts = {}) => { const out = loader.finalSource; if (out) css.prepend(out); + if (opts.camelCase === true) { + Object.keys(parser.exportTokens).forEach((token) => { + const camelCaseToken = camelCase(token); + + parser.exportTokens[camelCaseToken] = parser.exportTokens[token]; + }); + } + + // getJSON may return a promise return getJSON(css.source.input.file, parser.exportTokens, result.opts.to); }; diff --git a/test/fixtures/in/camelCase.css b/test/fixtures/in/camelCase.css new file mode 100644 index 0000000..7d53b37 --- /dev/null +++ b/test/fixtures/in/camelCase.css @@ -0,0 +1,3 @@ +.camel-case { + background: red; +} diff --git a/test/fixtures/out/camelCase.css b/test/fixtures/out/camelCase.css new file mode 100644 index 0000000..cc4fa9b --- /dev/null +++ b/test/fixtures/out/camelCase.css @@ -0,0 +1,3 @@ +._classes_camel-case { + background: red; +} diff --git a/test/test.js b/test/test.js index 5fcc01e..4caa161 100644 --- a/test/test.js +++ b/test/test.js @@ -98,6 +98,25 @@ test('processes globalModulePaths option', async (t) => { t.is(result.css, out); }); +test('processes camelCase option', async (t) => { + const sourceFile = path.join(fixturesPath, 'in', 'camelCase.css'); + const source = fs.readFileSync(sourceFile).toString(); + const jsonFile = path.join(fixturesPath, 'in', 'camelCase.css.json'); + + if (fs.existsSync(jsonFile)) fs.unlinkSync(jsonFile); + + await postcss([plugin({ generateScopedName, camelCase: true })]) + .process(source, { from: sourceFile }); + + const json = fs.readFileSync(jsonFile).toString(); + fs.unlinkSync(jsonFile); + + t.deepEqual(JSON.parse(json), { + camelCase: '_camelCase_camel-case', + 'camel-case': '_camelCase_camel-case', + }); +}); + test('different instances have different generateScopedName functions', async (t) => { const one = plugin({