From 9a691e9cb32e9aa2fbcf961301fe73ffc041fefb Mon Sep 17 00:00:00 2001 From: allocen Date: Mon, 13 Apr 2020 17:59:52 +0300 Subject: [PATCH 1/2] "support different exported types: camelCase, camelCaseOnly, dashes, dashesOnly (#93)" --- README.md | 27 +++++------- src/index.js | 39 ++++++++++++++--- test/fixtures/in/camelCase.css | 8 ++++ test/test.js | 80 +++++++++++++++++++++++++++++++--- 4 files changed, 126 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 8f8b869..f371023 100644 --- a/README.md +++ b/README.md @@ -181,26 +181,19 @@ postcss([ ]); ``` -### Camel cased classes +### localsConvention -If you need, you can pass the options `{ camelCase: true }` to transform classes: +Type: `String` +Default: `null` -CSS: +Style of exported classnames. -```css -.post-title { - color: red; -} -``` - -JSON: - -```json -{ - "post-title": "._post-title_116zl_1", - "postTitle": "._post-title_116zl_1" -} -``` +| Name | Type | Description | +| :-------------------: | :--------: | :----------------------------------------------------------------------------------------------- | +| **`'camelCase'`** | `{String}` | Class names will be camelized, the original class name will not to be removed from the locals | +| **`'camelCaseOnly'`** | `{String}` | Class names will be camelized, the original class name will be removed from the locals | +| **`'dashes'`** | `{String}` | Only dashes in class names will be camelized | +| **`'dashesOnly'`** | `{String}` | Dashes in class names will be camelized, the original class name will be removed from the locals | ## Integration with templates diff --git a/src/index.js b/src/index.js index 63a1058..605080d 100644 --- a/src/index.js +++ b/src/index.js @@ -54,6 +54,12 @@ function isResultPlugin(plugin) { return plugin.postcssPlugin !== PLUGIN_NAME; } +function dashesCamelCase(string) { + return string.replace(/-+(\w)/g, (_, firstLetter) => + firstLetter.toUpperCase() + ); +} + module.exports = postcss.plugin(PLUGIN_NAME, (opts = {}) => { const getJSON = opts.getJSON || saveJSON; @@ -72,11 +78,34 @@ module.exports = postcss.plugin(PLUGIN_NAME, (opts = {}) => { const out = loader.finalSource; if (out) css.prepend(out); - if (opts.camelCase) { - Object.keys(parser.exportTokens).forEach(token => { - const camelCaseToken = camelCase(token); - parser.exportTokens[camelCaseToken] = parser.exportTokens[token]; - }); + if (opts.localsConvention) { + parser.exportTokens = Object.entries(parser.exportTokens).reduce( + (tokens, [className, value]) => { + switch (opts.localsConvention) { + case "camelCase": + tokens[className] = value; + tokens[camelCase(className)] = value; + + break; + case "camelCaseOnly": + tokens[camelCase(className)] = value; + + break; + case "dashes": + tokens[className] = value; + tokens[dashesCamelCase(className)] = value; + + break; + case "dashesOnly": + tokens[dashesCamelCase(className)] = value; + + break; + } + + return tokens; + }, + {} + ); } result.messages.push({ diff --git a/test/fixtures/in/camelCase.css b/test/fixtures/in/camelCase.css index 7d53b37..784f394 100644 --- a/test/fixtures/in/camelCase.css +++ b/test/fixtures/in/camelCase.css @@ -1,3 +1,11 @@ .camel-case { background: red; } + +.camel-case-extra { + background: blue; +} + +.FooBar { + background: green; +} \ No newline at end of file diff --git a/test/test.js b/test/test.js index 1c6efcc..df84723 100644 --- a/test/test.js +++ b/test/test.js @@ -91,24 +91,92 @@ it("processes globalModulePaths option", async () => { expect(result.css).toMatchSnapshot("processes globalModulePaths option"); }); -it("processes camelCase option", async () => { +it("processes localsConvention with camelCase option", async () => { 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 } - ); + await postcss([ + plugin({ generateScopedName, localsConvention: "camelCase" }) + ]).process(source, { from: sourceFile }); + + const json = fs.readFileSync(jsonFile).toString(); + fs.unlinkSync(jsonFile); + + expect(JSON.parse(json)).toMatchObject({ + "camel-case": "_camelCase_camel-case", + camelCase: "_camelCase_camel-case", + "camel-case-extra": "_camelCase_camel-case-extra", + camelCaseExtra: "_camelCase_camel-case-extra", + FooBar: "_camelCase_FooBar", + fooBar: "_camelCase_FooBar" + }); +}); + +it("processes localsConvention with camelCaseOnly option", async () => { + 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, localsConvention: "camelCaseOnly" }) + ]).process(source, { from: sourceFile }); + + const json = fs.readFileSync(jsonFile).toString(); + fs.unlinkSync(jsonFile); + + expect(JSON.parse(json)).toMatchObject({ + camelCase: "_camelCase_camel-case", + camelCaseExtra: "_camelCase_camel-case-extra", + fooBar: "_camelCase_FooBar" + }); +}); + +it("processes localsConvention with dashes option", async () => { + 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, localsConvention: "dashes" }) + ]).process(source, { from: sourceFile }); + + const json = fs.readFileSync(jsonFile).toString(); + fs.unlinkSync(jsonFile); + + expect(JSON.parse(json)).toMatchObject({ + "camel-case": "_camelCase_camel-case", + camelCase: "_camelCase_camel-case", + "camel-case-extra": "_camelCase_camel-case-extra", + camelCaseExtra: "_camelCase_camel-case-extra", + FooBar: "_camelCase_FooBar" + }); +}); + +it("processes localsConvention with dashes option", async () => { + 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, localsConvention: "dashes" }) + ]).process(source, { from: sourceFile }); const json = fs.readFileSync(jsonFile).toString(); fs.unlinkSync(jsonFile); expect(JSON.parse(json)).toMatchObject({ camelCase: "_camelCase_camel-case", - "camel-case": "_camelCase_camel-case" + camelCaseExtra: "_camelCase_camel-case-extra", + FooBar: "_camelCase_FooBar" }); }); From bf33986fb41246ab4cec79e5909a1b474feb7ad8 Mon Sep 17 00:00:00 2001 From: allocen Date: Mon, 13 Apr 2020 18:09:16 +0300 Subject: [PATCH 2/2] updated version as well --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26060e7..d5b5e17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-modules", - "version": "1.5.0", + "version": "1.6.0", "description": "PostCSS plugin to use CSS Modules everywhere", "main": "build/index.js", "keywords": [