From 382535ea5e7c69dad5ca2e769f505767c5ca71ed Mon Sep 17 00:00:00 2001 From: Andrew Anikin Date: Sat, 6 Oct 2018 15:26:10 +0300 Subject: [PATCH 01/27] docs: actualize links, fix typo (#203) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 858f2ee..0f636bc 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ NODE_ENV=production ./test 1. Parses the `styleName` attribute value into anonymous and named CSS module references. 1. Finds the CSS class name matching the CSS module reference: * If `styleName` value is a string literal, generates a string literal value. - * If `styleName` value is a [`jSXExpressionContainer`](https://github.com/babel/babel/tree/master/packages/babel-types#jsxexpressioncontainer), uses a helper function ([`getClassName`](./src/getClassName.js)) to construct the `className` value at the runtime. + * If `styleName` value is a [`jSXExpressionContainer`](https://babeljs.io/docs/en/next/babel-types.html#jsxexpressioncontainer), uses a helper function ([`getClassName`](./src/getClassName.js)) to construct the `className` value at the runtime. 1. Removes the `styleName` attribute from the element. 1. Appends the resulting `className` to the existing `className` value (creates `className` attribute if one does not exist). @@ -190,9 +190,9 @@ Configure the options for the plugin within your `.babelrc` as follows: |Name|Type|Description|Default| |---|---|---|---| -|`context`|`string`|Must match webpack [`context`](https://webpack.github.io/docs/configuration.html#context) configuration. [`css-loader`](https://github.com/webpack/css-loader) inherits `context` values from webpack. Other CSS module implementations might use different context resolution logic.|`process.cwd()`| +|`context`|`string`|Must match webpack [`context`](https://webpack.js.org/configuration/entry-context/#context) configuration. [`css-loader`](https://github.com/webpack/css-loader) inherits `context` values from webpack. Other CSS module implementations might use different context resolution logic.|`process.cwd()`| |`exclude`|`string`|A RegExp that will exclude otherwise included files e.g., to exclude all styles from node_modules `exclude: 'node_modules'`| -|`filetypes`|`?FiletypesConfigurationType`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugerss, LESS and SCSS and extra plugins for them. || +|`filetypes`|`?FiletypesConfigurationType`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugarss, LESS and SCSS and extra plugins for them. || |`generateScopedName`|`?GenerateScopedNameConfigurationType`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names). If you use this option, make sure it matches the value of `localIdentName` in webpack config. See this [issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/108#issuecomment-334351241) |`[path]___[name]__[local]___[hash:base64:5]`| |`removeImport`|`boolean`|Remove the matching style import. This option is used to enable server-side rendering.|`false`| |`webpackHotModuleReloading`|`boolean`|Enables hot reloading of CSS in webpack|`false`| From 10621ef1710f8920be3607ff552f310bb23a2fad Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Mon, 12 Nov 2018 23:44:27 +0000 Subject: [PATCH 02/27] chore: update .editorconfig --- .editorconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index b3dfee7..0f17867 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,9 @@ root = true [*] +charset = utf-8 end_of_line = lf -insert_final_newline = true -indent_style = space indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true From 6e105bbc907c5f27db77ccf72eeea97392d7fd0f Mon Sep 17 00:00:00 2001 From: Stephan Herzog Date: Mon, 19 Nov 2018 15:19:10 +0100 Subject: [PATCH 03/27] fix: update build command and dependencies (#210) * fix: update build command and dependencies This commit updates the presets and plugins used in the build-helper run script to use equivalent v7-packages from the @babel namespace. * fix: update demo deps and config Fixes #204 --- demo/package.json | 10 +++++----- demo/webpack.config.js | 4 ++-- package.json | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/demo/package.json b/demo/package.json index ea45fbe..334ec16 100644 --- a/demo/package.json +++ b/demo/package.json @@ -7,14 +7,14 @@ "babel-plugin-react-css-modules": "^2.1.3", "react": "^15.4.1", "react-dom": "^15.4.1", - "webpack": "^2.2.0-rc.3" + "webpack": "^2.7.0" }, "devDependencies": { - "@babel/core": "^6.21.0", - "@babel/loader": "^6.2.10", - "@babel/plugin-transform-react-jsx": "^6.8.0", + "@babel/core": "^7.1.6", + "@babel/plugin-transform-react-jsx": "^7.1.6", + "babel-loader": "^8.0.4", "css-loader": "^0.26.1", "style-loader": "^0.13.1", - "webpack-dev-server": "^2.2.0-rc.0" + "webpack-dev-server": "^2.11.3" } } diff --git a/demo/webpack.config.js b/demo/webpack.config.js index 863c3d9..c4d73d2 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -18,10 +18,10 @@ module.exports = { }, { include: path.resolve(__dirname, './src'), - loader: '@babel/loader', + loader: 'babel-loader', query: { plugins: [ - 'transform-react-jsx', + '@babel/transform-react-jsx', [ 'react-css-modules', { diff --git a/package.json b/package.json index 6c96b4b..1e05fae 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,11 @@ "@babel/core": "^7.0.0", "@babel/helper-plugin-test-runner": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", "@babel/preset-env": "^7.0.0", "@babel/register": "^7.0.0", "babel-core": "^7.0.0-bridge.0", + "babel-jest": "^23.6.0", "babel-plugin-tester": "^5.5.1", "eslint": "^5.5.0", "eslint-config-canonical": "^12.0.0", @@ -66,7 +68,7 @@ }, "scripts": { "build": "rm -fr ./dist && NODE_ENV=production babel ./src --out-dir ./dist --source-maps --copy-files && npm run build-helper", - "build-helper": "mkdir -p ./dist/browser && NODE_ENV=production babel ./src/getClassName.js --out-file ./dist/browser/getClassName.js --source-maps --no-babelrc --plugins transform-es2015-modules-commonjs,transform-flow-strip-types --presets es2015", + "build-helper": "mkdir -p ./dist/browser && NODE_ENV=production babel ./src/getClassName.js --out-file ./dist/browser/getClassName.js --source-maps --no-babelrc --plugins @babel/plugin-transform-modules-commonjs,@babel/plugin-transform-flow-strip-types --presets @babel/preset-env", "lint": "eslint ./src && flow", "test": "jest" }, From ffcd14de2e01fe1193d39f01e83985775345c302 Mon Sep 17 00:00:00 2001 From: Stephan Herzog Date: Mon, 19 Nov 2018 23:51:13 +0100 Subject: [PATCH 04/27] fix: update test fixtures (#212) * fix: update test fixtures Fixes #211 * chore: assert exception on use with missing import --- .../expected.js | 7 ----- .../{actual.js => input.js} | 0 .../output.js | 9 ++++++ .../expected.js | 9 ------ .../{actual.js => input.js} | 0 .../output.js | 11 ++++++++ .../{actual.js => input.js} | 0 .../{expected.js => output.js} | 4 ++- .../custom attribute mapping/expected.js | 28 ------------------- .../{actual.js => input.js} | 0 .../custom attribute mapping/output.js | 27 ++++++++++++++++++ .../{actual.js => input.js} | 0 .../options.json | 1 + .../{expected.js => output.js} | 0 .../expected.js | 3 -- .../{actual.js => input.js} | 0 .../output.js | 5 ++++ .../{actual.js => input.js} | 0 .../options.json | 3 +- .../{expected.js => output.js} | 5 ++-- .../expected.js | 4 --- .../{actual.js => input.js} | 0 .../output.js | 7 +++++ .../expected.js | 15 ---------- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../output.js | 17 +++++++++++ test/fixtures/react-css-modules/options.js | 27 ++++++++++++++++++ .../expected.js | 13 --------- .../{actual.js => input.js} | 0 .../output.js | 17 +++++++++++ .../resolves less stylesheets/expected.js | 3 -- .../{actual.js => input.js} | 0 .../resolves less stylesheets/output.js | 5 ++++ .../resolves namespaced styleName/expected.js | 3 -- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../resolves namespaced styleName/output.js | 7 +++++ .../expected.js | 3 -- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../output.js | 5 ++++ .../expected.js | 3 -- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../output.js | 7 +++++ .../input.js | 1 + .../options.json | 3 ++ .../expected.js | 17 ----------- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../output.js | 22 +++++++++++++++ .../expected.js | 17 ----------- .../{actual.js => input.js} | 0 .../options.json | 10 ------- .../output.js | 22 +++++++++++++++ test/index.js | 5 ++-- test/package.json | 4 --- 58 files changed, 204 insertions(+), 195 deletions(-) delete mode 100644 test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/expected.js rename test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/output.js delete mode 100644 test/fixtures/react-css-modules/adds module hot accept for CSS imports/expected.js rename test/fixtures/react-css-modules/adds module hot accept for CSS imports/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/adds module hot accept for CSS imports/output.js rename test/fixtures/react-css-modules/applies extra plugins/{actual.js => input.js} (100%) rename test/fixtures/react-css-modules/applies extra plugins/{expected.js => output.js} (52%) delete mode 100644 test/fixtures/react-css-modules/custom attribute mapping/expected.js rename test/fixtures/react-css-modules/custom attribute mapping/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/custom attribute mapping/output.js rename test/fixtures/react-css-modules/disable default styleName transform/{actual.js => input.js} (100%) rename test/fixtures/react-css-modules/disable default styleName transform/{expected.js => output.js} (100%) delete mode 100644 test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/expected.js rename test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/output.js rename test/fixtures/react-css-modules/does not throw error if attribute has no name property/{actual.js => input.js} (100%) rename test/fixtures/react-css-modules/does not throw error if attribute has no name property/{expected.js => output.js} (68%) delete mode 100644 test/fixtures/react-css-modules/exclude styles from react-css-modules/expected.js rename test/fixtures/react-css-modules/exclude styles from react-css-modules/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/exclude styles from react-css-modules/output.js delete mode 100644 test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/expected.js rename test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/options.json create mode 100644 test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/output.js create mode 100644 test/fixtures/react-css-modules/options.js delete mode 100644 test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/expected.js rename test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/output.js delete mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/expected.js rename test/fixtures/react-css-modules/resolves less stylesheets/{actual.js => input.js} (100%) create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/output.js delete mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName/expected.js rename test/fixtures/react-css-modules/resolves namespaced styleName/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName/options.json create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName/output.js delete mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/expected.js rename test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/options.json create mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/output.js delete mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/expected.js rename test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/options.json create mode 100644 test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/output.js create mode 100644 test/fixtures/react-css-modules/throws if styleName is used without import/input.js create mode 100644 test/fixtures/react-css-modules/throws if styleName is used without import/options.json delete mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js rename test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/output.js delete mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js rename test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/{actual.js => input.js} (100%) delete mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/options.json create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/output.js delete mode 100644 test/package.json diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/expected.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/expected.js deleted file mode 100644 index 1f95db4..0000000 --- a/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/expected.js +++ /dev/null @@ -1,7 +0,0 @@ -import './bar.css'; - -if (module.hot) { - module.hot.accept('./bar.css', function () { - require('./bar.css'); - }); -} diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/actual.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/input.js similarity index 100% rename from test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/actual.js rename to test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/input.js diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/output.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/output.js new file mode 100644 index 0000000..4c05c72 --- /dev/null +++ b/test/fixtures/react-css-modules/adds module hot accept for CSS imports when file only contains import statements/output.js @@ -0,0 +1,9 @@ +"use strict"; + +require("./bar.css"); + +if (module.hot) { + module.hot.accept("./bar.css", function () { + require("./bar.css"); + }); +} \ No newline at end of file diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports/expected.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports/expected.js deleted file mode 100644 index d7bfc74..0000000 --- a/test/fixtures/react-css-modules/adds module hot accept for CSS imports/expected.js +++ /dev/null @@ -1,9 +0,0 @@ -import './bar.css'; - -if (module.hot) { - module.hot.accept('./bar.css', function () { - require('./bar.css'); - }); -} - -
; diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports/actual.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports/input.js similarity index 100% rename from test/fixtures/react-css-modules/adds module hot accept for CSS imports/actual.js rename to test/fixtures/react-css-modules/adds module hot accept for CSS imports/input.js diff --git a/test/fixtures/react-css-modules/adds module hot accept for CSS imports/output.js b/test/fixtures/react-css-modules/adds module hot accept for CSS imports/output.js new file mode 100644 index 0000000..999a8df --- /dev/null +++ b/test/fixtures/react-css-modules/adds module hot accept for CSS imports/output.js @@ -0,0 +1,11 @@ +"use strict"; + +require("./bar.css"); + +if (module.hot) { + module.hot.accept("./bar.css", function () { + require("./bar.css"); + }); +} + +
; diff --git a/test/fixtures/react-css-modules/applies extra plugins/actual.js b/test/fixtures/react-css-modules/applies extra plugins/input.js similarity index 100% rename from test/fixtures/react-css-modules/applies extra plugins/actual.js rename to test/fixtures/react-css-modules/applies extra plugins/input.js diff --git a/test/fixtures/react-css-modules/applies extra plugins/expected.js b/test/fixtures/react-css-modules/applies extra plugins/output.js similarity index 52% rename from test/fixtures/react-css-modules/applies extra plugins/expected.js rename to test/fixtures/react-css-modules/applies extra plugins/output.js index 417f11d..ceb57d2 100644 --- a/test/fixtures/react-css-modules/applies extra plugins/expected.js +++ b/test/fixtures/react-css-modules/applies extra plugins/output.js @@ -1,3 +1,5 @@ -import './bar.scss'; +"use strict"; + +require("./bar.scss");
; diff --git a/test/fixtures/react-css-modules/custom attribute mapping/expected.js b/test/fixtures/react-css-modules/custom attribute mapping/expected.js deleted file mode 100644 index f770ee6..0000000 --- a/test/fixtures/react-css-modules/custom attribute mapping/expected.js +++ /dev/null @@ -1,28 +0,0 @@ -import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import './foo.css'; - -// Literal, no merging -const _styleModuleImportMap = { - './foo.css': { - 'a': 'foo__a' - } -}; -
; - -// Literal, merging with literal -
; - -// Literal, merging with expression -
; - -// Literal, merging with complex expression -
0.5 ? 'apple' : 'banana') ? (Math.random() > 0.5 ? 'apple' : 'banana') + ' ' : '') + 'foo__a'}>
; - -// Expression, no merging -
; - -// Expression, merging with expression -
; - -// Multiple attributes -
; diff --git a/test/fixtures/react-css-modules/custom attribute mapping/actual.js b/test/fixtures/react-css-modules/custom attribute mapping/input.js similarity index 100% rename from test/fixtures/react-css-modules/custom attribute mapping/actual.js rename to test/fixtures/react-css-modules/custom attribute mapping/input.js diff --git a/test/fixtures/react-css-modules/custom attribute mapping/output.js b/test/fixtures/react-css-modules/custom attribute mapping/output.js new file mode 100644 index 0000000..7c65ae6 --- /dev/null +++ b/test/fixtures/react-css-modules/custom attribute mapping/output.js @@ -0,0 +1,27 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +require("./foo.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "./foo.css": { + "a": "foo__a" + } +}; +// Literal, no merging +
; // Literal, merging with literal + +
; // Literal, merging with expression + +
; // Literal, merging with complex expression + +
0.5 ? 'apple' : 'banana') ? (Math.random() > 0.5 ? 'apple' : 'banana') + " " : "") + "foo__a"}>
; // Expression, no merging + +
; // Expression, merging with expression + +
; // Multiple attributes + +
; diff --git a/test/fixtures/react-css-modules/disable default styleName transform/actual.js b/test/fixtures/react-css-modules/disable default styleName transform/input.js similarity index 100% rename from test/fixtures/react-css-modules/disable default styleName transform/actual.js rename to test/fixtures/react-css-modules/disable default styleName transform/input.js diff --git a/test/fixtures/react-css-modules/disable default styleName transform/options.json b/test/fixtures/react-css-modules/disable default styleName transform/options.json index b3251ec..b9f4934 100644 --- a/test/fixtures/react-css-modules/disable default styleName transform/options.json +++ b/test/fixtures/react-css-modules/disable default styleName transform/options.json @@ -1,4 +1,5 @@ { + "sourceType": "script", "plugins": [ [ "../../../../src", diff --git a/test/fixtures/react-css-modules/disable default styleName transform/expected.js b/test/fixtures/react-css-modules/disable default styleName transform/output.js similarity index 100% rename from test/fixtures/react-css-modules/disable default styleName transform/expected.js rename to test/fixtures/react-css-modules/disable default styleName transform/output.js diff --git a/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/expected.js b/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/expected.js deleted file mode 100644 index a25d27a..0000000 --- a/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/expected.js +++ /dev/null @@ -1,3 +0,0 @@ -import "./foo.css"; - -
; diff --git a/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/actual.js b/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/input.js similarity index 100% rename from test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/actual.js rename to test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/input.js diff --git a/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/output.js b/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/output.js new file mode 100644 index 0000000..c1b31b0 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error for stylename not found when handleMissingStyleName is warn/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("./foo.css"); + +
; diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/input.js similarity index 100% rename from test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js rename to test/fixtures/react-css-modules/does not throw error if attribute has no name property/input.js diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json index 6f54db7..4ab2a61 100644 --- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json @@ -3,7 +3,8 @@ [ "../../../../src", { - "generateScopedName": "[name]__[local]" + "generateScopedName": "[name]__[local]", + "handleMissingStyleName": "ignore" } ] ] diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js similarity index 68% rename from test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js rename to test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js index 5d797f4..7613724 100644 --- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js @@ -1,7 +1,8 @@ -import './bar.css'; +"use strict"; + +require("./bar.css"); const props = { foo: 'bar' }; -
; diff --git a/test/fixtures/react-css-modules/exclude styles from react-css-modules/expected.js b/test/fixtures/react-css-modules/exclude styles from react-css-modules/expected.js deleted file mode 100644 index 74c2862..0000000 --- a/test/fixtures/react-css-modules/exclude styles from react-css-modules/expected.js +++ /dev/null @@ -1,4 +0,0 @@ -import './bar.css'; -import './not_me.css'; - -
; diff --git a/test/fixtures/react-css-modules/exclude styles from react-css-modules/actual.js b/test/fixtures/react-css-modules/exclude styles from react-css-modules/input.js similarity index 100% rename from test/fixtures/react-css-modules/exclude styles from react-css-modules/actual.js rename to test/fixtures/react-css-modules/exclude styles from react-css-modules/input.js diff --git a/test/fixtures/react-css-modules/exclude styles from react-css-modules/output.js b/test/fixtures/react-css-modules/exclude styles from react-css-modules/output.js new file mode 100644 index 0000000..5c2763e --- /dev/null +++ b/test/fixtures/react-css-modules/exclude styles from react-css-modules/output.js @@ -0,0 +1,7 @@ +"use strict"; + +require("./bar.css"); + +require("./not_me.css"); + +
; diff --git a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/expected.js b/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/expected.js deleted file mode 100644 index 36fbc35..0000000 --- a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/expected.js +++ /dev/null @@ -1,15 +0,0 @@ -import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import './bar.css'; - -const _styleModuleImportMap = { - './bar.css': { - 'a': 'bar__a' - } -}; -
; - -
; - -
0.5 ? 'apple' : 'banana') ? (Math.random() > 0.5 ? 'apple' : 'banana') + ' ' : '') + 'bar__a'}>
; - -
; diff --git a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/actual.js b/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/input.js similarity index 100% rename from test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/actual.js rename to test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/input.js diff --git a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/options.json b/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/output.js b/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/output.js new file mode 100644 index 0000000..10e72e0 --- /dev/null +++ b/test/fixtures/react-css-modules/merges the resolved styleName with the existing className values/output.js @@ -0,0 +1,17 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +require("./bar.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "./bar.css": { + "a": "bar__a" + } +}; +
; +
; +
0.5 ? 'apple' : 'banana') ? (Math.random() > 0.5 ? 'apple' : 'banana') + " " : "") + "bar__a"}>
; +
; diff --git a/test/fixtures/react-css-modules/options.js b/test/fixtures/react-css-modules/options.js new file mode 100644 index 0000000..11e6b5b --- /dev/null +++ b/test/fixtures/react-css-modules/options.js @@ -0,0 +1,27 @@ +/** + * @file Provides the base options object that applies to all tests. + * https://github.com/babel/babel/blob/master/CONTRIBUTING.md#writing-tests + */ +const { resolve } = require('path'); + +module.exports = { + sourceType: 'module', + presets: [ + [ + '@babel/env', + { + targets: { + node: '8.0', + }, + }, + ], + ], + "plugins": [ + [ + resolve(__dirname, '../../../src'), + { + "generateScopedName": "[name]__[local]" + } + ] + ] +}; diff --git a/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/expected.js b/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/expected.js deleted file mode 100644 index a3e55b9..0000000 --- a/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/expected.js +++ /dev/null @@ -1,13 +0,0 @@ -import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import './foo.css'; - -const _styleModuleImportMap = { - './foo.css': { - 'a-b': 'foo__a-b' - } -}; -const styleNameFoo = 'a-c'; - -
; diff --git a/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/actual.js b/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/input.js similarity index 100% rename from test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/actual.js rename to test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/input.js diff --git a/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/output.js b/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/output.js new file mode 100644 index 0000000..984ad03 --- /dev/null +++ b/test/fixtures/react-css-modules/provides handleMissingStyleName to getClassName at runtime/output.js @@ -0,0 +1,17 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +require("./foo.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "./foo.css": { + "a-b": "foo__a-b" + } +}; +const styleNameFoo = 'a-c'; +
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js deleted file mode 100644 index f87c7c1..0000000 --- a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js +++ /dev/null @@ -1,3 +0,0 @@ -import './bar.less'; - -
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js b/test/fixtures/react-css-modules/resolves less stylesheets/input.js similarity index 100% rename from test/fixtures/react-css-modules/resolves less stylesheets/actual.js rename to test/fixtures/react-css-modules/resolves less stylesheets/input.js diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/output.js b/test/fixtures/react-css-modules/resolves less stylesheets/output.js new file mode 100644 index 0000000..15e44af --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("./bar.less"); + +
; diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName/expected.js b/test/fixtures/react-css-modules/resolves namespaced styleName/expected.js deleted file mode 100644 index 14667a0..0000000 --- a/test/fixtures/react-css-modules/resolves namespaced styleName/expected.js +++ /dev/null @@ -1,3 +0,0 @@ -import foo from './bar.css'; - -
; diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName/actual.js b/test/fixtures/react-css-modules/resolves namespaced styleName/input.js similarity index 100% rename from test/fixtures/react-css-modules/resolves namespaced styleName/actual.js rename to test/fixtures/react-css-modules/resolves namespaced styleName/input.js diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName/options.json b/test/fixtures/react-css-modules/resolves namespaced styleName/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/resolves namespaced styleName/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName/output.js b/test/fixtures/react-css-modules/resolves namespaced styleName/output.js new file mode 100644 index 0000000..7e9d86b --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName/output.js @@ -0,0 +1,7 @@ +"use strict"; + +var _bar = _interopRequireDefault(require("./bar.css")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +
; diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/expected.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/expected.js deleted file mode 100644 index f24ac6d..0000000 --- a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/expected.js +++ /dev/null @@ -1,3 +0,0 @@ -import './bar.css'; - -
; diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/actual.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/input.js similarity index 100% rename from test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/actual.js rename to test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/input.js diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/options.json b/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/output.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/output.js new file mode 100644 index 0000000..29a37b6 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves non-namespaced styleName (anonymous import)/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("./bar.css"); + +
; diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/expected.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/expected.js deleted file mode 100644 index 14667a0..0000000 --- a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/expected.js +++ /dev/null @@ -1,3 +0,0 @@ -import foo from './bar.css'; - -
; diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/actual.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/input.js similarity index 100% rename from test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/actual.js rename to test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/input.js diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/options.json b/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/output.js b/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/output.js new file mode 100644 index 0000000..7e9d86b --- /dev/null +++ b/test/fixtures/react-css-modules/resolves non-namespaced styleName (named import)/output.js @@ -0,0 +1,7 @@ +"use strict"; + +var _bar = _interopRequireDefault(require("./bar.css")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +
; diff --git a/test/fixtures/react-css-modules/throws if styleName is used without import/input.js b/test/fixtures/react-css-modules/throws if styleName is used without import/input.js new file mode 100644 index 0000000..f1d1339 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if styleName is used without import/input.js @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/fixtures/react-css-modules/throws if styleName is used without import/options.json b/test/fixtures/react-css-modules/throws if styleName is used without import/options.json new file mode 100644 index 0000000..45173e9 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if styleName is used without import/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Cannot use styleName attribute for style name 'missing_import' without importing at least one stylesheet." +} \ No newline at end of file diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js deleted file mode 100644 index 587fbff..0000000 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js +++ /dev/null @@ -1,17 +0,0 @@ -import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import bar from './bar.css'; -import './foo.css'; - -const _styleModuleImportMap = { - 'bar': { - 'a-b': 'bar__a-b' - }, - './foo.css': { - 'a-b': 'foo__a-b' - } -}; -const styleNameBar = 'bar.a-b'; -const styleNameFoo = 'a-b'; - -
; -
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/input.js similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/input.js diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/output.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/output.js new file mode 100644 index 0000000..d6247f7 --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/output.js @@ -0,0 +1,22 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +var _bar = _interopRequireDefault(require("./bar.css")); + +require("./foo.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "bar": { + "a-b": "bar__a-b" + }, + "./foo.css": { + "a-b": "foo__a-b" + } +}; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js deleted file mode 100644 index 891c016..0000000 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js +++ /dev/null @@ -1,17 +0,0 @@ -import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import bar from './bar.css'; -import './foo.css'; - -const _styleModuleImportMap = { - 'bar': { - 'a-b': 'bar__a-b' - }, - './foo.css': { - 'a-b': 'foo__a-b' - } -}; -const styleNameBar = 'bar.a-b'; -const styleNameFoo = 'a-b'; - -
; -
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/input.js similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/input.js diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/options.json deleted file mode 100644 index 6f54db7..0000000 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/options.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "plugins": [ - [ - "../../../../src", - { - "generateScopedName": "[name]__[local]" - } - ] - ] -} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/output.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/output.js new file mode 100644 index 0000000..01c605e --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/output.js @@ -0,0 +1,22 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +var _bar = _interopRequireDefault(require("./bar.css")); + +require("./foo.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "bar": { + "a-b": "bar__a-b" + }, + "./foo.css": { + "a-b": "foo__a-b" + } +}; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; +
; +
; diff --git a/test/index.js b/test/index.js index 3fdfae2..01d637f 100644 --- a/test/index.js +++ b/test/index.js @@ -1,2 +1,3 @@ -// eslint-disable-next-line import/no-commonjs -require('@babel/helper-plugin-test-runner').default(__dirname); +import runner from '@babel/helper-plugin-test-runner'; + +runner(__dirname); diff --git a/test/package.json b/test/package.json deleted file mode 100644 index 06a8b8d..0000000 --- a/test/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "bar", - "version": "1.0.0" -} From 4fa15f5d258ba6934412f0a44a8296229d18a187 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 21 Nov 2018 07:36:56 +0300 Subject: [PATCH 05/27] fix: force release BREAKING CHANGE: * babel 7 requirement From b3ae56b0b253f73368238c5bfc60e7659f1c995d Mon Sep 17 00:00:00 2001 From: Stephan Herzog Date: Fri, 30 Nov 2018 22:11:12 +0100 Subject: [PATCH 06/27] feat: respect exclude setting in JSXElement transform (#215) BREAKING CHANGE: * exclude logic is used to exclude JSXElement containing files --- demo/package.json | 2 +- src/index.js | 12 +++++++++++- .../input.js | 1 + .../options.json | 11 +++++++++++ .../output.js | 3 +++ 5 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/react-css-modules/does not throw error on excluded JSXElement/input.js create mode 100644 test/fixtures/react-css-modules/does not throw error on excluded JSXElement/options.json create mode 100644 test/fixtures/react-css-modules/does not throw error on excluded JSXElement/output.js diff --git a/demo/package.json b/demo/package.json index 334ec16..fed05fd 100644 --- a/demo/package.json +++ b/demo/package.json @@ -4,7 +4,7 @@ "start": "webpack-dev-server" }, "dependencies": { - "babel-plugin-react-css-modules": "^2.1.3", + "babel-plugin-react-css-modules": "^4.0.0", "react": "^15.4.1", "react-dom": "^15.4.1", "webpack": "^2.7.0" diff --git a/src/index.js b/src/index.js index b0367f4..4bd892e 100644 --- a/src/index.js +++ b/src/index.js @@ -121,6 +121,10 @@ export default ({ return require.resolve(path.node.source.value); }; + const isFilenameExcluded = (filename, exclude) => { + return filename.match(new RegExp(exclude)); + }; + const notForPlugin = (path: *, stats: *) => { stats.opts.filetypes = stats.opts.filetypes || {}; @@ -130,7 +134,9 @@ export default ({ return true; } - if (stats.opts.exclude && getTargetResourcePath(path, stats).match(new RegExp(stats.opts.exclude))) { + const filename = getTargetResourcePath(path, stats); + + if (stats.opts.exclude && isFilenameExcluded(filename, stats.opts.exclude)) { return true; } @@ -179,6 +185,10 @@ export default ({ JSXElement (path: *, stats: *): void { const filename = stats.file.opts.filename; + if (stats.opts.exclude && isFilenameExcluded(filename, stats.opts.exclude)) { + return; + } + let attributeNames = optionsDefaults.attributeNames; if (stats.opts && stats.opts.attributeNames) { diff --git a/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/input.js b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/input.js new file mode 100644 index 0000000..f1d1339 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/input.js @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/options.json b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/options.json new file mode 100644 index 0000000..d31d8d2 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "exclude": "input" + } + ] + ] +} \ No newline at end of file diff --git a/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/output.js b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/output.js new file mode 100644 index 0000000..0ba6f74 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error on excluded JSXElement/output.js @@ -0,0 +1,3 @@ +"use strict"; + +
; From fa15c8d7048bf335fe170895266a962fdc43b4c6 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Tue, 19 Feb 2019 15:57:50 +0800 Subject: [PATCH 07/27] fix: cannot read property 'split' of undefined (#225) * fix: cannot read property 'split' of undefined * fix: lint error in getClassName * fix: lint error in getClassName --- src/getClassName.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/getClassName.js b/src/getClassName.js index d99d858..87e29cd 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -72,6 +72,10 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM const handleMissingStyleName = options && options.handleMissingStyleName || DEFAULT_HANDLE_MISSING_STYLENAME_OPTION; + if (!styleNameValue) { + return ''; + } + return styleNameValue .split(' ') .filter((styleName) => { From 4e4ed24c0496a50107d87161909213e362b3826e Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Wed, 20 Feb 2019 02:28:38 +0800 Subject: [PATCH 08/27] test: add test case for absolute import (#227) * fix: cannot read property 'split' of undefined * fix: lint error in getClassName * fix: lint error in getClassName * test: add test case for absolute import --- package.json | 1 + .../resolves absolute path stylesheets/bar.css | 1 + .../resolves absolute path stylesheets/input.js | 3 +++ .../options.json | 15 +++++++++++++++ .../resolves absolute path stylesheets/output.js | 5 +++++ 5 files changed, 25 insertions(+) create mode 100644 test/fixtures/react-css-modules/resolves absolute path stylesheets/bar.css create mode 100644 test/fixtures/react-css-modules/resolves absolute path stylesheets/input.js create mode 100644 test/fixtures/react-css-modules/resolves absolute path stylesheets/options.json create mode 100644 test/fixtures/react-css-modules/resolves absolute path stylesheets/output.js diff --git a/package.json b/package.json index 1e05fae..bcc2393 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@babel/register": "^7.0.0", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^23.6.0", + "babel-plugin-module-resolver": "^3.2.0", "babel-plugin-tester": "^5.5.1", "eslint": "^5.5.0", "eslint-config-canonical": "^12.0.0", diff --git a/test/fixtures/react-css-modules/resolves absolute path stylesheets/bar.css b/test/fixtures/react-css-modules/resolves absolute path stylesheets/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/resolves absolute path stylesheets/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/resolves absolute path stylesheets/input.js b/test/fixtures/react-css-modules/resolves absolute path stylesheets/input.js new file mode 100644 index 0000000..74e3ca8 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves absolute path stylesheets/input.js @@ -0,0 +1,3 @@ +import 'abs/bar.css'; + +
; diff --git a/test/fixtures/react-css-modules/resolves absolute path stylesheets/options.json b/test/fixtures/react-css-modules/resolves absolute path stylesheets/options.json new file mode 100644 index 0000000..b3f5043 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves absolute path stylesheets/options.json @@ -0,0 +1,15 @@ +{ + "plugins": [ + ["module-resolver", { + "alias": { + "abs": "./test/fixtures/react-css-modules/resolves absolute path stylesheets" + } + }], + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/resolves absolute path stylesheets/output.js b/test/fixtures/react-css-modules/resolves absolute path stylesheets/output.js new file mode 100644 index 0000000..29a37b6 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves absolute path stylesheets/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("./bar.css"); + +
; From bc780d5257f344509fe6f4ecec34c3286ed3319c Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Wed, 20 Feb 2019 18:33:46 +0800 Subject: [PATCH 09/27] refactor: using default handleMissingStyleName from schema (#229) --- src/getClassName.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/getClassName.js b/src/getClassName.js index 87e29cd..c445438 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -5,13 +5,12 @@ import type { StyleModuleImportMapType, HandleMissingStyleNameOptionType } from './types'; +import optionsDefaults from './schemas/optionsDefaults'; type OptionsType = {| handleMissingStyleName: HandleMissingStyleNameOptionType |}; -const DEFAULT_HANDLE_MISSING_STYLENAME_OPTION = 'throw'; - const isNamespacedStyleName = (styleName: string): boolean => { return styleName.indexOf('.') !== -1; }; @@ -28,7 +27,7 @@ const getClassNameForNamespacedStyleName = ( const importName = styleNameParts[0]; const moduleName = styleNameParts[1]; const handleMissingStyleName = handleMissingStyleNameOption || - DEFAULT_HANDLE_MISSING_STYLENAME_OPTION; + optionsDefaults.handleMissingStyleName; if (!moduleName) { if (handleMissingStyleName === 'throw') { @@ -70,7 +69,7 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM const styleModuleImportMapKeys = Object.keys(styleModuleImportMap); const handleMissingStyleName = options && options.handleMissingStyleName || - DEFAULT_HANDLE_MISSING_STYLENAME_OPTION; + optionsDefaults.handleMissingStyleName; if (!styleNameValue) { return ''; From d27306c52d5e3e36cf84f4ab1bf64dbb5911ca8e Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Thu, 21 Feb 2019 16:40:08 +0800 Subject: [PATCH 10/27] refactor: move default generateScopedName to optionsDefault (#231) --- src/requireCssModule.js | 3 ++- src/schemas/optionsDefaults.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/requireCssModule.js b/src/requireCssModule.js index 2126dbf..0268a43 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -18,6 +18,7 @@ import type { GenerateScopedNameConfigurationType, StyleModuleMapType } from './types'; +import optionsDefaults from './schemas/optionsDefaults'; type FiletypeOptionsType = {| +syntax: string, @@ -102,7 +103,7 @@ export default (cssSourceFilePath: string, options: OptionsType): StyleModuleMap if (options.generateScopedName && typeof options.generateScopedName === 'function') { generateScopedName = options.generateScopedName; } else { - generateScopedName = genericNames(options.generateScopedName || '[path]___[name]__[local]___[hash:base64:5]', { + generateScopedName = genericNames(options.generateScopedName || optionsDefaults.generateScopedName, { context: options.context || process.cwd() }); } diff --git a/src/schemas/optionsDefaults.js b/src/schemas/optionsDefaults.js index 77d3e23..7daaef5 100644 --- a/src/schemas/optionsDefaults.js +++ b/src/schemas/optionsDefaults.js @@ -2,6 +2,7 @@ const optionsDefaults = { attributeNames: { styleName: 'className' }, + generateScopedName: '[path]___[name]__[local]___[hash:base64:5]', handleMissingStyleName: 'throw' }; From 9fcb91f5c3d3b181d0087ab7de999ac2c9c1dd11 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Thu, 21 Feb 2019 16:40:44 +0800 Subject: [PATCH 11/27] feat: do not apply plug-in if file does not contain styleName attribute (#230) * feat: add skipAbsentStyleName * test: add test case for skipAbsentStyleName * feat: refactor skipAbsentStyleName traversal * fix: readd require.resolve for resource path * feat: update options naming * docs: update for skip option * refactor: traverse JSXAttribute instead of element --- README.md | 1 + src/attributeNameExists.js | 31 +++++++++++++++++++ src/index.js | 13 +++++++- src/schemas/optionsSchema.json | 3 ++ .../bar.css | 1 + .../input.js | 3 ++ .../options.json | 11 +++++++ .../output.js | 5 +++ 8 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/attributeNameExists.js create mode 100644 test/fixtures/react-css-modules/does not apply plugin if no styleName/bar.css create mode 100644 test/fixtures/react-css-modules/does not apply plugin if no styleName/input.js create mode 100644 test/fixtures/react-css-modules/does not apply plugin if no styleName/options.json create mode 100644 test/fixtures/react-css-modules/does not apply plugin if no styleName/output.js diff --git a/README.md b/README.md index 0f636bc..9f9b6d6 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ Configure the options for the plugin within your `.babelrc` as follows: |`webpackHotModuleReloading`|`boolean`|Enables hot reloading of CSS in webpack|`false`| |`handleMissingStyleName`|`"throw"`, `"warn"`, `"ignore"`|Determines what should be done for undefined CSS modules (using a `styleName` for which there is no CSS module defined). Setting this option to `"ignore"` is equivalent to setting `errorWhenNotFound: false` in [react-css-modules](https://github.com/gajus/react-css-modules#errorwhennotfound). |`"throw"`| |`attributeNames`|`?AttributeNameMapType`|Refer to [Custom Attribute Mapping](#custom-attribute-mapping)|`{"styleName": "className"}`| +|`skip`|`boolean`|Whether to apply plugin if no matching `attributeNames` found in the file|`false`| Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/new?title=New%20configuration:). diff --git a/src/attributeNameExists.js b/src/attributeNameExists.js new file mode 100644 index 0000000..6314634 --- /dev/null +++ b/src/attributeNameExists.js @@ -0,0 +1,31 @@ +// @flow + +import optionsDefaults from './schemas/optionsDefaults'; + +const attributeNameExists = (programPath: *, stats: *): boolean => { + let exists = false; + + let attributeNames = optionsDefaults.attributeNames; + + if (stats.opts && stats.opts.attributeNames) { + attributeNames = Object.assign({}, attributeNames, stats.opts.attributeNames); + } + + programPath.traverse({ + JSXAttribute (attrPath: *) { + if (exists) { + return; + } + + const attribute = attrPath.node; + + if (typeof attribute.name !== 'undefined' && typeof attributeNames[attribute.name.name] === 'string') { + exists = true; + } + } + }); + + return exists; +}; + +export default attributeNameExists; diff --git a/src/index.js b/src/index.js index 4bd892e..a584fe0 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,7 @@ import createObjectExpression from './createObjectExpression'; import requireCssModule from './requireCssModule'; import resolveStringLiteral from './resolveStringLiteral'; import replaceJsxExpressionContainer from './replaceJsxExpressionContainer'; +import attributeNameExists from './attributeNameExists'; const ajv = new Ajv({ // eslint-disable-next-line id-match @@ -31,6 +32,8 @@ export default ({ }) => { const filenameMap = {}; + let skip = false; + const setupFileForRuntimeResolution = (path, filename) => { const programPath = path.findParent((parentPath) => { return parentPath.isProgram(); @@ -147,7 +150,7 @@ export default ({ inherits: babelPluginJsxSyntax, visitor: { ImportDeclaration (path: *, stats: *): void { - if (notForPlugin(path, stats)) { + if (skip || notForPlugin(path, stats)) { return; } @@ -183,6 +186,10 @@ export default ({ } }, JSXElement (path: *, stats: *): void { + if (skip) { + return; + } + const filename = stats.file.opts.filename; if (stats.opts.exclude && isFilenameExcluded(filename, stats.opts.exclude)) { @@ -250,6 +257,10 @@ export default ({ filenameMap[filename] = { styleModuleImportMap: {} }; + + if (stats.opts.skip && !attributeNameExists(path, stats)) { + skip = true; + } } } }; diff --git a/src/schemas/optionsSchema.json b/src/schemas/optionsSchema.json index e14e525..2b3041f 100644 --- a/src/schemas/optionsSchema.json +++ b/src/schemas/optionsSchema.json @@ -69,6 +69,9 @@ } }, "type": "object" + }, + "skip": { + "type": "boolean" } }, "type": "object" diff --git a/test/fixtures/react-css-modules/does not apply plugin if no styleName/bar.css b/test/fixtures/react-css-modules/does not apply plugin if no styleName/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/does not apply plugin if no styleName/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/does not apply plugin if no styleName/input.js b/test/fixtures/react-css-modules/does not apply plugin if no styleName/input.js new file mode 100644 index 0000000..9b3805b --- /dev/null +++ b/test/fixtures/react-css-modules/does not apply plugin if no styleName/input.js @@ -0,0 +1,3 @@ +import 'bar.css'; + +
; diff --git a/test/fixtures/react-css-modules/does not apply plugin if no styleName/options.json b/test/fixtures/react-css-modules/does not apply plugin if no styleName/options.json new file mode 100644 index 0000000..88e0d9d --- /dev/null +++ b/test/fixtures/react-css-modules/does not apply plugin if no styleName/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "skip": true + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/does not apply plugin if no styleName/output.js b/test/fixtures/react-css-modules/does not apply plugin if no styleName/output.js new file mode 100644 index 0000000..f8754b6 --- /dev/null +++ b/test/fixtures/react-css-modules/does not apply plugin if no styleName/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("bar.css"); + +
; From 37fe03087401871675d3be2f0ce5c965e9387650 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Thu, 21 Feb 2019 21:36:03 +0800 Subject: [PATCH 12/27] fix: unresolved optionsDefaults in babel helper (#233) --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bcc2393..2c83262 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,8 @@ }, "scripts": { "build": "rm -fr ./dist && NODE_ENV=production babel ./src --out-dir ./dist --source-maps --copy-files && npm run build-helper", - "build-helper": "mkdir -p ./dist/browser && NODE_ENV=production babel ./src/getClassName.js --out-file ./dist/browser/getClassName.js --source-maps --no-babelrc --plugins @babel/plugin-transform-modules-commonjs,@babel/plugin-transform-flow-strip-types --presets @babel/preset-env", + "build-helper": "mkdir -p ./dist/browser && NODE_ENV=production babel ./src/getClassName.js --out-file ./dist/browser/getClassName.js --source-maps --no-babelrc --plugins @babel/plugin-transform-modules-commonjs,@babel/plugin-transform-flow-strip-types --presets @babel/preset-env && npm run build-schema-helper", + "build-schema-helper": "mkdir -p ./dist/browser/schemas && NODE_ENV=production babel ./src/schemas/optionsDefaults.js --out-file ./dist/browser/schemas/optionsDefaults.js --source-maps --no-babelrc --plugins @babel/plugin-transform-modules-commonjs,@babel/plugin-transform-flow-strip-types --presets @babel/preset-env", "lint": "eslint ./src && flow", "test": "jest" }, From 23b35604ed699e9fa9ae252fe02f747b42001bf1 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Fri, 22 Feb 2019 16:50:21 +0800 Subject: [PATCH 13/27] feat: add autoResolveMultiImports option (#234) * feat: add autoResolveMultiImports option * test: add test cases for autoResolveMultiImports option * docs: add for autoResolveMultiImports option --- README.md | 1 + src/createObjectExpression.js | 3 + src/getClassName.js | 97 +++++++++++-------- src/index.js | 14 +-- src/replaceJsxExpressionContainer.js | 11 +-- src/resolveStringLiteral.js | 8 +- src/schemas/optionsSchema.json | 3 + src/types.js | 5 + .../bar.css | 3 + .../foo.css | 1 + .../input.js | 5 + .../options.json | 12 +++ .../bar.css | 3 + .../foo.css | 1 + .../input.js | 4 + .../options.json | 12 +++ .../bar.css | 3 + .../foo.css | 1 + .../input.js | 4 + .../options.json | 11 +++ .../bar.css | 1 + .../foo.css | 1 + .../input.js | 5 + .../options.json | 11 +++ .../output.js | 8 ++ .../bar.css | 1 + .../foo.css | 1 + .../input.js | 8 ++ .../options.json | 11 +++ .../output.js | 28 ++++++ 30 files changed, 219 insertions(+), 58 deletions(-) create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/bar.css create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/foo.css create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/input.js create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/options.json create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/bar.css create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/foo.css create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/input.js create mode 100644 test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/options.json create mode 100644 test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/bar.css create mode 100644 test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/foo.css create mode 100644 test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/input.js create mode 100644 test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/options.json create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/bar.css create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/foo.css create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/input.js create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/options.json create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/output.js create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/bar.css create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/foo.css create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/input.js create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/options.json create mode 100644 test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/output.js diff --git a/README.md b/README.md index 9f9b6d6..a1bca75 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ Configure the options for the plugin within your `.babelrc` as follows: |`handleMissingStyleName`|`"throw"`, `"warn"`, `"ignore"`|Determines what should be done for undefined CSS modules (using a `styleName` for which there is no CSS module defined). Setting this option to `"ignore"` is equivalent to setting `errorWhenNotFound: false` in [react-css-modules](https://github.com/gajus/react-css-modules#errorwhennotfound). |`"throw"`| |`attributeNames`|`?AttributeNameMapType`|Refer to [Custom Attribute Mapping](#custom-attribute-mapping)|`{"styleName": "className"}`| |`skip`|`boolean`|Whether to apply plugin if no matching `attributeNames` found in the file|`false`| +|`autoResolveMultipleImports`|`boolean`|Allow multiple anonymous imports if `styleName` is only in one of them.|`false`| Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/new?title=New%20configuration:). diff --git a/src/createObjectExpression.js b/src/createObjectExpression.js index 29a6865..a14a224 100644 --- a/src/createObjectExpression.js +++ b/src/createObjectExpression.js @@ -28,6 +28,9 @@ const createObjectExpression = (t: BabelTypes, object: InputObjectType): ObjectE newValue = createObjectExpression(t, value); } else if (typeof value === 'boolean') { newValue = t.booleanLiteral(value); + } else if (typeof value === 'undefined') { + // eslint-disable-next-line no-continue + continue; } else { throw new TypeError('Unexpected type: ' + typeof value); } diff --git a/src/getClassName.js b/src/getClassName.js index c445438..537a2e8 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -3,18 +3,26 @@ import type { StyleModuleMapType, StyleModuleImportMapType, - HandleMissingStyleNameOptionType + HandleMissingStyleNameOptionType, + GetClassNameOptionsType } from './types'; import optionsDefaults from './schemas/optionsDefaults'; -type OptionsType = {| - handleMissingStyleName: HandleMissingStyleNameOptionType -|}; - const isNamespacedStyleName = (styleName: string): boolean => { return styleName.indexOf('.') !== -1; }; +const handleError = (message: string, handleMissingStyleName: HandleMissingStyleNameOptionType): null => { + if (handleMissingStyleName === 'throw') { + throw new Error(message); + } else if (handleMissingStyleName === 'warn') { + // eslint-disable-next-line no-console + console.warn(message); + } + + return null; +}; + const getClassNameForNamespacedStyleName = ( styleName: string, styleModuleImportMap: StyleModuleImportMapType, @@ -30,47 +38,60 @@ const getClassNameForNamespacedStyleName = ( optionsDefaults.handleMissingStyleName; if (!moduleName) { - if (handleMissingStyleName === 'throw') { - throw new Error('Invalid style name: ' + styleName); - } else if (handleMissingStyleName === 'warn') { - // eslint-disable-next-line no-console - console.warn('Invalid style name: ' + styleName); - } else { - return null; - } + return handleError('Invalid style name: ' + styleName, handleMissingStyleName); } if (!styleModuleImportMap[importName]) { - if (handleMissingStyleName === 'throw') { - throw new Error('CSS module import does not exist: ' + importName); - } else if (handleMissingStyleName === 'warn') { - // eslint-disable-next-line no-console - console.warn('CSS module import does not exist: ' + importName); - } else { - return null; - } + return handleError('CSS module import does not exist: ' + importName, handleMissingStyleName); } if (!styleModuleImportMap[importName][moduleName]) { - if (handleMissingStyleName === 'throw') { - throw new Error('CSS module does not exist: ' + moduleName); - } else if (handleMissingStyleName === 'warn') { - // eslint-disable-next-line no-console - console.warn('CSS module does not exist: ' + moduleName); - } else { - return null; - } + return handleError('CSS module does not exist: ' + moduleName, handleMissingStyleName); } return styleModuleImportMap[importName][moduleName]; }; -export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportMapType, options?: OptionsType): string => { +const getClassNameFromMultipleImports = ( + styleName: string, + styleModuleImportMap: StyleModuleImportMapType, + handleMissingStyleNameOption?: HandleMissingStyleNameOptionType +): ?string => { + const handleMissingStyleName = handleMissingStyleNameOption || + optionsDefaults.handleMissingStyleName; + + const importKeysWithMatches = Object.keys(styleModuleImportMap) + .map((importKey) => { + return styleModuleImportMap[importKey][styleName] && importKey; + }) + .filter((importKey) => { + return importKey; + }); + + if (importKeysWithMatches.length > 1) { + throw new Error('Cannot resolve styleName "' + styleName + '" because it is present in multiple imports:' + + '\n\n\t' + importKeysWithMatches.join('\n\t') + + '\n\nYou can resolve this by using a named import, e.g:' + + '\n\n\timport foo from "' + importKeysWithMatches[0] + '";' + + '\n\t
' + + '\n\n'); + } + + if (importKeysWithMatches.length === 0) { + return handleError('Could not resolve the styleName \'' + styleName + '\'.', handleMissingStyleName); + } + + return styleModuleImportMap[importKeysWithMatches[0]][styleName]; +}; + +export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportMapType, options?: GetClassNameOptionsType): string => { const styleModuleImportMapKeys = Object.keys(styleModuleImportMap); const handleMissingStyleName = options && options.handleMissingStyleName || optionsDefaults.handleMissingStyleName; + const autoResolveMultipleImports = options && options.autoResolveMultipleImports; + if (!styleNameValue) { return ''; } @@ -91,20 +112,18 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM } if (styleModuleImportMapKeys.length > 1) { - throw new Error('Cannot use anonymous style name \'' + styleName + - '\' with more than one stylesheet import.'); + if (!autoResolveMultipleImports) { + throw new Error('Cannot use anonymous style name \'' + styleName + + '\' with more than one stylesheet import without setting \'autoResolveMultipleImports\' to true.'); + } + + return getClassNameFromMultipleImports(styleName, styleModuleImportMap, handleMissingStyleName); } const styleModuleMap: StyleModuleMapType = styleModuleImportMap[styleModuleImportMapKeys[0]]; if (!styleModuleMap[styleName]) { - if (handleMissingStyleName === 'throw') { - throw new Error('Could not resolve the styleName \'' + styleName + '\'.'); - } - if (handleMissingStyleName === 'warn') { - // eslint-disable-next-line no-console - console.warn('Could not resolve the styleName \'' + styleName + '\'.'); - } + return handleError('Could not resolve the styleName \'' + styleName + '\'.', handleMissingStyleName); } return styleModuleMap[styleName]; diff --git a/src/index.js b/src/index.js index a584fe0..a604a91 100644 --- a/src/index.js +++ b/src/index.js @@ -212,19 +212,23 @@ export default ({ } const handleMissingStyleName = stats.opts && stats.opts.handleMissingStyleName || optionsDefaults.handleMissingStyleName; + const autoResolveMultipleImports = stats.opts && stats.opts.autoResolveMultipleImports || optionsDefaults.autoResolveMultipleImports; for (const attribute of attributes) { const destinationName = attributeNames[attribute.name.name]; + const options = { + autoResolveMultipleImports, + handleMissingStyleName + }; + if (t.isStringLiteral(attribute.value)) { resolveStringLiteral( path, filenameMap[filename].styleModuleImportMap, attribute, destinationName, - { - handleMissingStyleName - } + options ); } else if (t.isJSXExpressionContainer(attribute.value)) { if (!filenameMap[filename].importedHelperIndentifier) { @@ -237,9 +241,7 @@ export default ({ destinationName, filenameMap[filename].importedHelperIndentifier, filenameMap[filename].styleModuleImportMapIdentifier, - { - handleMissingStyleName - } + options ); } } diff --git a/src/replaceJsxExpressionContainer.js b/src/replaceJsxExpressionContainer.js index 29769f1..5dd6a01 100644 --- a/src/replaceJsxExpressionContainer.js +++ b/src/replaceJsxExpressionContainer.js @@ -11,16 +11,12 @@ import BabelTypes, { jSXIdentifier } from '@babel/types'; import type { - HandleMissingStyleNameOptionType + GetClassNameOptionsType } from './types'; import conditionalClassMerge from './conditionalClassMerge'; import createObjectExpression from './createObjectExpression'; import optionsDefaults from './schemas/optionsDefaults'; -type OptionsType = {| - handleMissingStyleName: HandleMissingStyleNameOptionType -|}; - export default ( t: BabelTypes, // eslint-disable-next-line flowtype/no-weak-types @@ -29,7 +25,7 @@ export default ( destinationName: string, importedHelperIndentifier: Identifier, styleModuleImportMapIdentifier: Identifier, - options: OptionsType + options: GetClassNameOptionsType ): void => { const expressionContainerValue = sourceAttribute.value; const destinationAttribute = path.node.openingElement.attributes @@ -50,7 +46,8 @@ export default ( // Only provide options argument if the options are something other than default // This helps save a few bits in the generated user code - if (options.handleMissingStyleName !== optionsDefaults.handleMissingStyleName) { + if (options.handleMissingStyleName !== optionsDefaults.handleMissingStyleName || + options.autoResolveMultipleImports !== optionsDefaults.autoResolveMultipleImports) { args.push(createObjectExpression(t, options)); } diff --git a/src/resolveStringLiteral.js b/src/resolveStringLiteral.js index 5af63dd..b1d4f32 100644 --- a/src/resolveStringLiteral.js +++ b/src/resolveStringLiteral.js @@ -10,13 +10,9 @@ import conditionalClassMerge from './conditionalClassMerge'; import getClassName from './getClassName'; import type { StyleModuleImportMapType, - HandleMissingStyleNameOptionType + GetClassNameOptionsType } from './types'; -type OptionsType = {| - handleMissingStyleName: HandleMissingStyleNameOptionType -|}; - /** * Updates the className value of a JSX element using a provided styleName attribute. */ @@ -25,7 +21,7 @@ export default ( styleModuleImportMap: StyleModuleImportMapType, sourceAttribute: JSXAttribute, destinationName: string, - options: OptionsType + options: GetClassNameOptionsType ): void => { const resolvedStyleName = getClassName(sourceAttribute.value.value, styleModuleImportMap, options); diff --git a/src/schemas/optionsSchema.json b/src/schemas/optionsSchema.json index 2b3041f..2257f0c 100644 --- a/src/schemas/optionsSchema.json +++ b/src/schemas/optionsSchema.json @@ -72,6 +72,9 @@ }, "skip": { "type": "boolean" + }, + "autoResolveMultipleImports": { + "type": "boolean" } }, "type": "object" diff --git a/src/types.js b/src/types.js index 76cb076..9a7ae59 100644 --- a/src/types.js +++ b/src/types.js @@ -13,3 +13,8 @@ export type GenerateScopedNameType = (localName: string, resourcePath: string) = export type GenerateScopedNameConfigurationType = GenerateScopedNameType | string; export type HandleMissingStyleNameOptionType = 'throw' | 'warn' | 'ignore'; + +export type GetClassNameOptionsType = {| + handleMissingStyleName: HandleMissingStyleNameOptionType, + autoResolveMultipleImports: boolean +|}; diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/bar.css b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/bar.css new file mode 100644 index 0000000..2177a31 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/bar.css @@ -0,0 +1,3 @@ +.a {} + +.b {} diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/foo.css b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/foo.css new file mode 100644 index 0000000..5e869b7 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/foo.css @@ -0,0 +1 @@ +.b {} diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/input.js b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/input.js new file mode 100644 index 0000000..150491a --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/input.js @@ -0,0 +1,5 @@ +import './foo.css'; +import './bar.css'; + +
; +
; diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/options.json b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/options.json new file mode 100644 index 0000000..ea43fb2 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with duplicates/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "autoResolveMultipleImports": true + } + ] + ], + "throws": "Cannot resolve styleName \"b\" because it is present in multiple imports:\n\n\t./foo.css\n\t./bar.css\n\nYou can resolve this by using a named import, e.g:\n\n\timport foo from \"./foo.css\";\n\t
\n\n" +} diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/bar.css b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/bar.css new file mode 100644 index 0000000..2177a31 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/bar.css @@ -0,0 +1,3 @@ +.a {} + +.b {} diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/foo.css b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/foo.css new file mode 100644 index 0000000..5e869b7 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/foo.css @@ -0,0 +1 @@ +.b {} diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/input.js b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/input.js new file mode 100644 index 0000000..7e9fc6a --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/input.js @@ -0,0 +1,4 @@ +import './foo.css'; +import './bar.css'; + +
; diff --git a/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/options.json b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/options.json new file mode 100644 index 0000000..2b1f00b --- /dev/null +++ b/test/fixtures/react-css-modules/throws if autoResolveMultipleImport with no match/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "autoResolveMultipleImports": true + } + ] + ], + "throws": "Could not resolve the styleName 'c'." +} diff --git a/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/bar.css b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/bar.css new file mode 100644 index 0000000..2177a31 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/bar.css @@ -0,0 +1,3 @@ +.a {} + +.b {} diff --git a/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/foo.css b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/foo.css new file mode 100644 index 0000000..5e869b7 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/foo.css @@ -0,0 +1 @@ +.b {} diff --git a/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/input.js b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/input.js new file mode 100644 index 0000000..7a76f4e --- /dev/null +++ b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/input.js @@ -0,0 +1,4 @@ +import './foo.css'; +import './bar.css'; + +
; diff --git a/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/options.json b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/options.json new file mode 100644 index 0000000..e6634e5 --- /dev/null +++ b/test/fixtures/react-css-modules/throws if unset autoResolveMultipleImport with multiple anonymous imports/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ], + "throws": "Cannot use anonymous style name 'a' with more than one stylesheet import without setting 'autoResolveMultipleImports' to true." +} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/bar.css b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/foo.css b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/foo.css new file mode 100644 index 0000000..5e869b7 --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/foo.css @@ -0,0 +1 @@ +.b {} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/input.js b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/input.js new file mode 100644 index 0000000..150491a --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/input.js @@ -0,0 +1,5 @@ +import './foo.css'; +import './bar.css'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/options.json b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/options.json new file mode 100644 index 0000000..d92f25c --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "autoResolveMultipleImports": true + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/output.js b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/output.js new file mode 100644 index 0000000..0c29384 --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport no duplicates/output.js @@ -0,0 +1,8 @@ +"use strict"; + +require("./foo.css"); + +require("./bar.css"); + +
; +
; diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/bar.css b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/foo.css b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/foo.css new file mode 100644 index 0000000..5e869b7 --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/foo.css @@ -0,0 +1 @@ +.b {} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/input.js b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/input.js new file mode 100644 index 0000000..31a34a6 --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/input.js @@ -0,0 +1,8 @@ +import './foo.css'; +import './bar.css'; + +const styleNameA = 'a'; +const styleNameB = 'b'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/options.json b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/options.json new file mode 100644 index 0000000..d92f25c --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "autoResolveMultipleImports": true + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/output.js b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/output.js new file mode 100644 index 0000000..78f8fbe --- /dev/null +++ b/test/fixtures/react-css-modules/uses autoResolveMultipleImport on runtime/output.js @@ -0,0 +1,28 @@ +"use strict"; + +var _getClassName2 = _interopRequireDefault(require("babel-plugin-react-css-modules/dist/browser/getClassName")); + +require("./foo.css"); + +require("./bar.css"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const _styleModuleImportMap = { + "./foo.css": { + "b": "foo__b" + }, + "./bar.css": { + "a": "bar__a" + } +}; +const styleNameA = 'a'; +const styleNameB = 'b'; +
; +
; From 0e39c78efd052d86007055e2cd7f11979902d175 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sun, 24 Feb 2019 12:10:16 +0800 Subject: [PATCH 14/27] fix: potential problem with default options (#235) --- src/getClassName.js | 8 ++++---- src/index.js | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/getClassName.js b/src/getClassName.js index 537a2e8..1bf05fb 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -87,10 +87,10 @@ const getClassNameFromMultipleImports = ( export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportMapType, options?: GetClassNameOptionsType): string => { const styleModuleImportMapKeys = Object.keys(styleModuleImportMap); - const handleMissingStyleName = options && options.handleMissingStyleName || - optionsDefaults.handleMissingStyleName; - - const autoResolveMultipleImports = options && options.autoResolveMultipleImports; + const { + handleMissingStyleName = optionsDefaults.handleMissingStyleName, + autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports + } = options || {}; if (!styleNameValue) { return ''; diff --git a/src/index.js b/src/index.js index a604a91..5c728f7 100644 --- a/src/index.js +++ b/src/index.js @@ -211,8 +211,10 @@ export default ({ return; } - const handleMissingStyleName = stats.opts && stats.opts.handleMissingStyleName || optionsDefaults.handleMissingStyleName; - const autoResolveMultipleImports = stats.opts && stats.opts.autoResolveMultipleImports || optionsDefaults.autoResolveMultipleImports; + const { + handleMissingStyleName = optionsDefaults.handleMissingStyleName, + autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports + } = stats.opts || {}; for (const attribute of attributes) { const destinationName = attributeNames[attribute.name.name]; From 70550bcf256e09df6da8342e241ee997b056546c Mon Sep 17 00:00:00 2001 From: Rohit Rajendran Date: Fri, 15 Mar 2019 17:22:10 -0400 Subject: [PATCH 15/27] Update hotmodule reloading webpack links (#241) The links to webpack's documents on hot module reloading was out of date --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a1bca75..543bbb9 100644 --- a/README.md +++ b/README.md @@ -474,17 +474,17 @@ This behaviour is enabled by default in `babel-plugin-react-css-modules`. ### How to live reload the CSS? -`babel-plugin-react-css-modules` utilises webpack [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement.html) (HMR) to live reload the CSS. +`babel-plugin-react-css-modules` utilises webpack [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/#root) (HMR) to live reload the CSS. To enable live reloading of the CSS: * Enable [`webpackHotModuleReloading`](#configuration) `babel-plugin-react-css-modules` configuration. -* Configure `webpack` to use HMR. Use [`--hot`](https://webpack.github.io/docs/webpack-dev-server.html) option if you are using `webpack-dev-server`. +* Configure `webpack` to use HMR. Use [`--hot`](https://webpack.js.org/configuration/dev-server/#root) option if you are using `webpack-dev-server`. * Use [`style-loader`](https://github.com/webpack/style-loader) to load the style sheets. > Note: > -> This enables live reloading of the CSS. To enable HMR of the React components, refer to the [Hot Module Replacement - React](https://webpack.js.org/guides/hmr-react/) guide. +> This enables live reloading of the CSS. To enable HMR of the React components, refer to the [Hot Module Replacement - React](https://webpack.js.org/guides/hot-module-replacement/#other-code-and-frameworks) guide. > Note: > From 05c268317e97046a915c94ff28d8ab1a63ff77cb Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Thu, 21 Mar 2019 19:27:00 +0800 Subject: [PATCH 16/27] fix: handle spread (#243) * fix: handle spread * test: handle spread * test: add test case for spread * spread: remove keys exclusion, avoid falsy values * refactor: handle spread separated in another file --- src/createSpreadMapper.js | 73 +++++++++++++++++++ src/handleSpreadClassName.js | 53 ++++++++++++++ src/index.js | 12 +++ .../output.js | 2 +- .../handle spread attributes/foo.css | 1 + .../handle spread attributes/input.js | 22 ++++++ .../handle spread attributes/options.json | 13 ++++ .../handle spread attributes/output.js | 16 ++++ 8 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/createSpreadMapper.js create mode 100644 src/handleSpreadClassName.js create mode 100644 test/fixtures/react-css-modules/handle spread attributes/foo.css create mode 100644 test/fixtures/react-css-modules/handle spread attributes/input.js create mode 100644 test/fixtures/react-css-modules/handle spread attributes/options.json create mode 100644 test/fixtures/react-css-modules/handle spread attributes/output.js diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js new file mode 100644 index 0000000..7b99cf5 --- /dev/null +++ b/src/createSpreadMapper.js @@ -0,0 +1,73 @@ +// @flow + +import { + Expression, + memberExpression, + binaryExpression, + stringLiteral, + logicalExpression, + identifier +} from '@babel/types'; +import optionsDefaults from './schemas/optionsDefaults'; + +const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Expression } => { + const result = {}; + + let {attributeNames} = optionsDefaults; + + if (stats.opts && stats.opts.attributeNames) { + attributeNames = Object.assign({}, attributeNames, stats.opts.attributeNames); + } + + const attributes = Object + .entries(attributeNames) + .filter((pair) => { + return pair[1]; + }); + + const attributeKeys = attributes.map((pair) => { + return pair[0]; + }); + + path.traverse({ + JSXSpreadAttribute (spreadPath: *) { + const spread = spreadPath.node; + + for (const attributeKey of attributeKeys) { + const destinationName = attributeNames[attributeKey]; + + if (result[destinationName]) { + result[destinationName] = binaryExpression( + '+', + result[destinationName], + binaryExpression( + '+', + stringLiteral(' '), + logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') + ) + ), + ); + } else { + result[destinationName] = logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') + ); + } + } + } + }); + + return result; +}; + +export default createSpreadMapper; diff --git a/src/handleSpreadClassName.js b/src/handleSpreadClassName.js new file mode 100644 index 0000000..62ea482 --- /dev/null +++ b/src/handleSpreadClassName.js @@ -0,0 +1,53 @@ +// @flow + +import { + Expression, + isStringLiteral, + isJSXExpressionContainer, + jsxExpressionContainer, + binaryExpression, + stringLiteral +} from '@babel/types'; + +const handleSpreadClassName = ( + path: *, + destinationName: string, + classNamesFromSpread: Expression +) => { + const destinationAttribute = path.node.openingElement.attributes + .find((attribute) => { + return typeof attribute.name !== 'undefined' && attribute.name.name === destinationName; + }); + + if (!destinationAttribute) { + return; + } + + if (isStringLiteral(destinationAttribute.value)) { + destinationAttribute.value = jsxExpressionContainer( + binaryExpression( + '+', + destinationAttribute.value, + binaryExpression( + '+', + stringLiteral(' '), + classNamesFromSpread, + ) + ) + ); + } else if (isJSXExpressionContainer(destinationAttribute.value)) { + destinationAttribute.value = jsxExpressionContainer( + binaryExpression( + '+', + destinationAttribute.value.expression, + binaryExpression( + '+', + stringLiteral(' '), + classNamesFromSpread + ) + ) + ); + } +}; + +export default handleSpreadClassName; diff --git a/src/index.js b/src/index.js index 5c728f7..305d941 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,8 @@ import requireCssModule from './requireCssModule'; import resolveStringLiteral from './resolveStringLiteral'; import replaceJsxExpressionContainer from './replaceJsxExpressionContainer'; import attributeNameExists from './attributeNameExists'; +import createSpreadMapper from './createSpreadMapper'; +import handleSpreadClassName from './handleSpreadClassName'; const ajv = new Ajv({ // eslint-disable-next-line id-match @@ -216,6 +218,8 @@ export default ({ autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports } = stats.opts || {}; + const spreadMap = createSpreadMapper(path, stats); + for (const attribute of attributes) { const destinationName = attributeNames[attribute.name.name]; @@ -246,6 +250,14 @@ export default ({ options ); } + + if (spreadMap[destinationName]) { + handleSpreadClassName( + path, + destinationName, + spreadMap[destinationName] + ); + } } }, Program (path: *, stats: *): void { diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js index 7613724..c2084e1 100644 --- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js @@ -5,4 +5,4 @@ require("./bar.css"); const props = { foo: 'bar' }; -
; +
; diff --git a/test/fixtures/react-css-modules/handle spread attributes/foo.css b/test/fixtures/react-css-modules/handle spread attributes/foo.css new file mode 100644 index 0000000..40ebb53 --- /dev/null +++ b/test/fixtures/react-css-modules/handle spread attributes/foo.css @@ -0,0 +1 @@ +.a {} \ No newline at end of file diff --git a/test/fixtures/react-css-modules/handle spread attributes/input.js b/test/fixtures/react-css-modules/handle spread attributes/input.js new file mode 100644 index 0000000..efb4b6d --- /dev/null +++ b/test/fixtures/react-css-modules/handle spread attributes/input.js @@ -0,0 +1,22 @@ +import './foo.css'; + +const rest = {}; + +
; + +
; + +
; + +
; + +// Should be okay if rest is put on last +
; + +const rest2 = {}; + +
; + +// Should not do anything +
; +
; diff --git a/test/fixtures/react-css-modules/handle spread attributes/options.json b/test/fixtures/react-css-modules/handle spread attributes/options.json new file mode 100644 index 0000000..93a418e --- /dev/null +++ b/test/fixtures/react-css-modules/handle spread attributes/options.json @@ -0,0 +1,13 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "attributeNames": { + "activeStyleName": "activeClassName" + } + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js new file mode 100644 index 0000000..49609e0 --- /dev/null +++ b/test/fixtures/react-css-modules/handle spread attributes/output.js @@ -0,0 +1,16 @@ +"use strict"; + +require("./foo.css"); + +const rest = {}; +
; +
; +
; +
; // Should be okay if rest is put on last + +
; +const rest2 = {}; +
; // Should not do anything + +
; +
; From 4a47f35e2e887bb935d0602cf1425fbc87719ae1 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Fri, 22 Mar 2019 15:38:27 +0800 Subject: [PATCH 17/27] fix: spread should not traverse children elements (#245) --- src/createSpreadMapper.js | 68 ++++++++++--------- .../handle spread attributes/input.js | 4 ++ .../handle spread attributes/output.js | 3 + 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js index 7b99cf5..81d3cb6 100644 --- a/src/createSpreadMapper.js +++ b/src/createSpreadMapper.js @@ -6,7 +6,8 @@ import { binaryExpression, stringLiteral, logicalExpression, - identifier + identifier, + isJSXSpreadAttribute } from '@babel/types'; import optionsDefaults from './schemas/optionsDefaults'; @@ -29,43 +30,44 @@ const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Exp return pair[0]; }); - path.traverse({ - JSXSpreadAttribute (spreadPath: *) { - const spread = spreadPath.node; + const spreadAttributes = path.node.openingElement.attributes + .filter((attr) => { + return isJSXSpreadAttribute(attr); + }); - for (const attributeKey of attributeKeys) { - const destinationName = attributeNames[attributeKey]; + for (const spread of spreadAttributes) { + for (const attributeKey of attributeKeys) { + const destinationName = attributeNames[attributeKey]; - if (result[destinationName]) { - result[destinationName] = binaryExpression( + if (result[destinationName]) { + result[destinationName] = binaryExpression( + '+', + result[destinationName], + binaryExpression( '+', - result[destinationName], - binaryExpression( - '+', - stringLiteral(' '), - logicalExpression( - '||', - memberExpression( - spread.argument, - identifier(destinationName), - ), - stringLiteral('') - ) - ), - ); - } else { - result[destinationName] = logicalExpression( - '||', - memberExpression( - spread.argument, - identifier(destinationName), - ), - stringLiteral('') - ); - } + stringLiteral(' '), + logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') + ) + ), + ); + } else { + result[destinationName] = logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') + ); } } - }); + } return result; }; diff --git a/test/fixtures/react-css-modules/handle spread attributes/input.js b/test/fixtures/react-css-modules/handle spread attributes/input.js index efb4b6d..8e09b6d 100644 --- a/test/fixtures/react-css-modules/handle spread attributes/input.js +++ b/test/fixtures/react-css-modules/handle spread attributes/input.js @@ -20,3 +20,7 @@ const rest2 = {}; // Should not do anything
;
; + +
+
+
diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js index 49609e0..59ec5c2 100644 --- a/test/fixtures/react-css-modules/handle spread attributes/output.js +++ b/test/fixtures/react-css-modules/handle spread attributes/output.js @@ -14,3 +14,6 @@ const rest2 = {};
;
; +
+
+
; From f11d423ae43f2eb57f603bd13cef7f58f0216a07 Mon Sep 17 00:00:00 2001 From: George Pittarelli Date: Fri, 29 Mar 2019 18:31:27 -0400 Subject: [PATCH 18/27] fix: don't break when spreading falsy value (#249) --- src/createSpreadMapper.js | 43 +++++++++++-------- .../output.js | 2 +- .../handle spread attributes/output.js | 14 +++--- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/createSpreadMapper.js b/src/createSpreadMapper.js index 81d3cb6..176fb0a 100644 --- a/src/createSpreadMapper.js +++ b/src/createSpreadMapper.js @@ -4,6 +4,7 @@ import { Expression, memberExpression, binaryExpression, + conditionalExpression, stringLiteral, logicalExpression, identifier, @@ -43,25 +44,33 @@ const createSpreadMapper = (path: *, stats: *): { [destinationName: string]: Exp result[destinationName] = binaryExpression( '+', result[destinationName], - binaryExpression( - '+', - stringLiteral(' '), - logicalExpression( - '||', - memberExpression( - spread.argument, - identifier(destinationName), - ), - stringLiteral('') - ) - ), + conditionalExpression( + spread.argument, + binaryExpression( + '+', + stringLiteral(' '), + logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') + ) + ), + stringLiteral('') + ) ); } else { - result[destinationName] = logicalExpression( - '||', - memberExpression( - spread.argument, - identifier(destinationName), + result[destinationName] = conditionalExpression( + spread.argument, + logicalExpression( + '||', + memberExpression( + spread.argument, + identifier(destinationName), + ), + stringLiteral('') ), stringLiteral('') ); diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js index c2084e1..a325415 100644 --- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js @@ -5,4 +5,4 @@ require("./bar.css"); const props = { foo: 'bar' }; -
; +
; diff --git a/test/fixtures/react-css-modules/handle spread attributes/output.js b/test/fixtures/react-css-modules/handle spread attributes/output.js index 59ec5c2..421a3f8 100644 --- a/test/fixtures/react-css-modules/handle spread attributes/output.js +++ b/test/fixtures/react-css-modules/handle spread attributes/output.js @@ -3,17 +3,17 @@ require("./foo.css"); const rest = {}; -
; -
; -
; -
; // Should be okay if rest is put on last +
; +
; +
; +
; // Should be okay if rest is put on last -
; +
; const rest2 = {}; -
; // Should not do anything +
; // Should not do anything
;
;
-
+
; From ff21df5e6cfdac94e5d3f82f4083ec257a3e9dea Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Thu, 9 May 2019 17:54:03 +0100 Subject: [PATCH 19/27] docs: add GitSpo mentions badge --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 543bbb9..df2123f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # babel-plugin-react-css-modules +![[GitSpo Mentions](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square) [![Travis build status](http://img.shields.io/travis/gajus/babel-plugin-react-css-modules/master.svg?style=flat-square)](https://travis-ci.org/gajus/babel-plugin-react-css-modules) [![NPM version](http://img.shields.io/npm/v/babel-plugin-react-css-modules.svg?style=flat-square)](https://www.npmjs.org/package/babel-plugin-react-css-modules) [![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical) @@ -260,9 +261,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two } } ``` - + Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config - + ```json "plugins": [ ["postcss-import-sync2", { @@ -270,9 +271,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two }], "postcss-nested" ] - ``` - - + ``` + + ### Custom Attribute Mapping You can set your own attribute mapping rules using the `attributeNames` option. From 31c5626c8df718c101d65b2b60630116bd13323d Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Thu, 9 May 2019 17:59:33 +0100 Subject: [PATCH 20/27] fix: correct GitSpo badge markdown --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df2123f..0fda1ce 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # babel-plugin-react-css-modules -![[GitSpo Mentions](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules)](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square) +[![GitSpo Mentions](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square)](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules) [![Travis build status](http://img.shields.io/travis/gajus/babel-plugin-react-css-modules/master.svg?style=flat-square)](https://travis-ci.org/gajus/babel-plugin-react-css-modules) [![NPM version](http://img.shields.io/npm/v/babel-plugin-react-css-modules.svg?style=flat-square)](https://www.npmjs.org/package/babel-plugin-react-css-modules) [![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical) From d6fdc38b2f6a5855407fd25232f171b5085e1236 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Sat, 11 May 2019 09:26:19 +0100 Subject: [PATCH 21/27] fix: update GitSpo badge URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fda1ce..30a303c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # babel-plugin-react-css-modules -[![GitSpo Mentions](https://gitspo.com/badges/gajus/babel-plugin-react-css-modules?style=flat-square)](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules) +[![GitSpo Mentions](https://gitspo.com/badges/mentions/gajus/babel-plugin-react-css-modules?style=flat-square)](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules) [![Travis build status](http://img.shields.io/travis/gajus/babel-plugin-react-css-modules/master.svg?style=flat-square)](https://travis-ci.org/gajus/babel-plugin-react-css-modules) [![NPM version](http://img.shields.io/npm/v/babel-plugin-react-css-modules.svg?style=flat-square)](https://www.npmjs.org/package/babel-plugin-react-css-modules) [![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical) From 59e05a2150876276f6318ce9b8f59a36d610f250 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 19 Jun 2019 10:12:38 +0200 Subject: [PATCH 22/27] Create FUNDING.yml --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2f093a7 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: gajus +patreon: gajus From e3636b39d6811aca7701d44f19cdf777a9260d71 Mon Sep 17 00:00:00 2001 From: Ben Ilegbodu Date: Fri, 10 Jan 2020 18:54:12 -0800 Subject: [PATCH 23/27] Add error FAQs (#283) --- README.md | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 30a303c..748a3fe 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ NODE_ENV=production ./test ## How does it work? 1. Builds index of all stylesheet imports per file (imports of files with `.css` or `.scss` extension). -1. Uses [postcss](https://github.com/postcss/postcss) to parse the matching CSS files. +1. Uses [postcss](https://github.com/postcss/postcss) to parse the matching CSS files into a lookup of CSS module references. 1. Iterates through all [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html) element declarations. 1. Parses the `styleName` attribute value into anonymous and named CSS module references. 1. Finds the CSS class name matching the CSS module reference: @@ -239,7 +239,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two npm install postcss-scss --save-dev ``` -2. Add a filetype syntax mapping to the Babel plugin configuration +2. Add a `filetypes` syntax mapping to the Babel plugin configuration. For example for SCSS: ```json "filetypes": { @@ -249,7 +249,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two } ``` - And optionaly specify extra plugins + And optionally specify extra plugins: ```json "filetypes": { @@ -262,7 +262,9 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two } ``` - Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config + > NOTE: [`postcss-nested`](https://github.com/postcss/postcss-nested) is added as an extra plugin for demonstration purposes only. It's not needed with [`postcss-scss`](https://github.com/postcss/postcss-scss) because SCSS already supports nesting. + + Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config: ```json "plugins": [ @@ -490,3 +492,32 @@ To enable live reloading of the CSS: > Note: > > This is a [webpack](https://webpack.github.io/) specific option. If you are using `babel-plugin-react-css-modules` in a different setup and require CSS live reloading, raise an issue describing your setup. + +### I get a "Cannot use styleName attribute for style name '`[X]`' without importing at least one stylesheet." error + +First, ensure that you are correctly importing the CSS file following the [conventions](#conventions). + +If you are correctly importing but using different CSS (such as SCSS), this is likely happening because your CSS file wasn't able to be successfully parsed. You need to [configure a syntax loader](#configurate-syntax-loaders). + +### I get a "Could not resolve the styleName '`[X]`' error but the class exists in the CSS included in the browser. + +First, verify that the CSS is being included in the browser. Remove from `styleName` the reference to the CSS class that's failing and view the page. Search through the `` tags that have been added to the `` and find the one related to your CSS module. Copy the code into your editor and search for the class name. + +Once you've verified that the class is being rendered in CSS, the likely cause is that the `babel-plugin-react-css-modules` is unable to find your CSS class in the parsed code. If you're using different CSS (such as SCSS), verify that you have [configured a syntax loader](#configurate-syntax-loaders). + +However, if you're using a syntaxes such as [`postcss-scss`](https://github.com/postcss/postcss-scss) or [`postcss-less`](https://github.com/webschik/postcss-less), they do not compile down to CSS. So if you are programmatically building a class name (see below), webpack will be able to generate the rendered CSS from SCSS/LESS, but `babel-plugin-react-css-modules` will not be able to parse the SCSS/LESS. + +A SCSS example: + +```scss +$scales: 10, 20, 30, 40, 50; + +@each $scale in $scales { + .icon-#{$scale} { + width: $scale; + height: $scale; + } + } +``` + +`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found. \ No newline at end of file From 91c8e9b9b272e1d16c756f7e865fdbf94dec2075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E7=AB=9F=E4=B8=89?= Date: Fri, 18 Sep 2020 00:11:30 +0800 Subject: [PATCH 24/27] Feat/add regexp support for filetype (#240) * feat: use RegExp as including condition in filetype config * test: add corresponding test cases. * fix: do not use extension-style filrtype as RegExp pattern * feat: modify the priority between RegExp pattern filetype and extension style filetype * style: no continue * style: for comment #2 Co-authored-by: super-cattle --- src/conditionalClassMerge.js | 1 + src/findMatchedFiletype.js | 25 +++++++++++++++++++ src/getClassName.js | 1 + src/index.js | 12 ++++++--- src/requireCssModule.js | 6 ++--- src/resolveStringLiteral.js | 1 - .../bar.less | 3 +++ .../bar.md.less | 3 +++ .../input.js | 3 +++ .../options.json | 15 +++++++++++ .../output.js | 5 ++++ .../bar.md.css | 1 + .../foo.css | 1 + .../input.js | 4 +++ .../options.json | 16 ++++++++++++ .../output.js | 9 +++++++ .../styles/base.css | 1 + 17 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 src/findMatchedFiletype.js create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js create mode 100644 test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css diff --git a/src/conditionalClassMerge.js b/src/conditionalClassMerge.js index 617599c..cb7bbf5 100644 --- a/src/conditionalClassMerge.js +++ b/src/conditionalClassMerge.js @@ -12,6 +12,7 @@ export default ( classNameExpression: any, styleNameExpression: any, ): any => { + // classNameExpression ? (classNameExpression + ' ') : '' + styleNameExpression return binaryExpression( '+', conditionalExpression( diff --git a/src/findMatchedFiletype.js b/src/findMatchedFiletype.js new file mode 100644 index 0000000..b74a0b2 --- /dev/null +++ b/src/findMatchedFiletype.js @@ -0,0 +1,25 @@ +// @flow + +export default (sourceFilePath: string, filetypes: $ReadOnlyArray): ?string => { + // Try to match as the RegExp pattern + for (const pattern of filetypes) { + if (!pattern.match(/^\.[a-z0-9A-Z]+?$/)) { + if (sourceFilePath.match(new RegExp(pattern))) { + return pattern; + } + } + } + + const extensionDotIndex = sourceFilePath.lastIndexOf('.'); + + if (extensionDotIndex > -1) { + const extension = sourceFilePath.substr(extensionDotIndex); + const index = filetypes.indexOf(extension); + + if (index > -1) { + return filetypes[index]; + } + } + + return null; +}; diff --git a/src/getClassName.js b/src/getClassName.js index 1bf05fb..823ce16 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -120,6 +120,7 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM return getClassNameFromMultipleImports(styleName, styleModuleImportMap, handleMissingStyleName); } + // There is only one imported CSS module file. const styleModuleMap: StyleModuleMapType = styleModuleImportMap[styleModuleImportMapKeys[0]]; if (!styleModuleMap[styleName]) { diff --git a/src/index.js b/src/index.js index 305d941..477026b 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,7 @@ import requireCssModule from './requireCssModule'; import resolveStringLiteral from './resolveStringLiteral'; import replaceJsxExpressionContainer from './replaceJsxExpressionContainer'; import attributeNameExists from './attributeNameExists'; +import findMatchedFiletype from './findMatchedFiletype'; import createSpreadMapper from './createSpreadMapper'; import handleSpreadClassName from './handleSpreadClassName'; @@ -130,12 +131,12 @@ export default ({ return filename.match(new RegExp(exclude)); }; + // decide whether the import statement should be processed as CSS module const notForPlugin = (path: *, stats: *) => { stats.opts.filetypes = stats.opts.filetypes || {}; - const extension = path.node.source.value.lastIndexOf('.') > -1 ? path.node.source.value.substr(path.node.source.value.lastIndexOf('.')) : null; - - if (extension !== '.css' && Object.keys(stats.opts.filetypes).indexOf(extension) < 0) { + // @HACK + if (path.node.source.value.indexOf('babel-plugin-react-css-modules') === 0) { return true; } @@ -145,7 +146,10 @@ export default ({ return true; } - return false; + const filetypeKeys = Object.keys(stats.opts.filetypes); + filetypeKeys.push('.css'); + + return !findMatchedFiletype(filename, filetypeKeys); }; return { diff --git a/src/requireCssModule.js b/src/requireCssModule.js index 0268a43..d77c25a 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -18,6 +18,7 @@ import type { GenerateScopedNameConfigurationType, StyleModuleMapType } from './types'; +import findMatchedFiletype from './findMatchedFiletype'; import optionsDefaults from './schemas/optionsDefaults'; type FiletypeOptionsType = {| @@ -36,10 +37,9 @@ type OptionsType = {| |}; const getFiletypeOptions = (cssSourceFilePath: string, filetypes: FiletypesConfigurationType): ?FiletypeOptionsType => { - const extension = cssSourceFilePath.substr(cssSourceFilePath.lastIndexOf('.')); - const filetype = filetypes ? filetypes[extension] : null; + const matchedKey = findMatchedFiletype(cssSourceFilePath, Object.keys(filetypes)); - return filetype; + return matchedKey ? filetypes && filetypes[matchedKey] : null; }; // eslint-disable-next-line flowtype/no-weak-types diff --git a/src/resolveStringLiteral.js b/src/resolveStringLiteral.js index b1d4f32..f62e42a 100644 --- a/src/resolveStringLiteral.js +++ b/src/resolveStringLiteral.js @@ -41,7 +41,6 @@ export default ( } else { throw new Error('Unexpected attribute value:' + destinationAttribute.value); } - path.node.openingElement.attributes.splice(path.node.openingElement.attributes.indexOf(sourceAttribute), 1); } else { sourceAttribute.name.name = destinationName; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less new file mode 100644 index 0000000..6586489 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.less @@ -0,0 +1,3 @@ +@color: #f00; + +.a {background-color: @color;} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less new file mode 100644 index 0000000..6586489 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/bar.md.less @@ -0,0 +1,3 @@ +@color: #f00; + +.a {background-color: @color;} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js new file mode 100644 index 0000000..25d6c7d --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/input.js @@ -0,0 +1,3 @@ +import './bar.md.less'; + +
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json new file mode 100644 index 0000000..0e3777a --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/options.json @@ -0,0 +1,15 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "filetypes": { + "\\.md\\.less$": { + "syntax": "postcss-less" + } + } + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js new file mode 100644 index 0000000..e77b991 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets matching RegExp/output.js @@ -0,0 +1,5 @@ +"use strict"; + +require("./bar.md.less"); + +
; diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css new file mode 100644 index 0000000..07a8534 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/bar.md.css @@ -0,0 +1 @@ +.a {background-color: #f00;} diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css new file mode 100644 index 0000000..07a8534 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/foo.css @@ -0,0 +1 @@ +.a {background-color: #f00;} diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js new file mode 100644 index 0000000..d00c4be --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/input.js @@ -0,0 +1,4 @@ +import barMd from './bar.md.css'; +import base from './styles/base.css'; + +
; diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json new file mode 100644 index 0000000..5adefe5 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/options.json @@ -0,0 +1,16 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "filetypes": { + "\\.md\\.less$": { + "syntax": "postcss-less" + }, + "styles/.*?\\.css$": {} + } + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js new file mode 100644 index 0000000..882cb0a --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/output.js @@ -0,0 +1,9 @@ +"use strict"; + +var _barMd = _interopRequireDefault(require("./bar.md.css")); + +var _base = _interopRequireDefault(require("./styles/base.css")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +
; diff --git a/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css new file mode 100644 index 0000000..f454509 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves namespaced styleName matching RegExp/styles/base.css @@ -0,0 +1 @@ +.b {background-color: #0f0;} \ No newline at end of file From 6a2a894df6f08fa2ba968735aeedb07a70302a01 Mon Sep 17 00:00:00 2001 From: Anton A Date: Tue, 20 Apr 2021 07:34:54 +0930 Subject: [PATCH 25/27] docs: link to webpack's localIdentName documentation in the description of generateScopedName. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 748a3fe..1af05a7 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ Configure the options for the plugin within your `.babelrc` as follows: |`context`|`string`|Must match webpack [`context`](https://webpack.js.org/configuration/entry-context/#context) configuration. [`css-loader`](https://github.com/webpack/css-loader) inherits `context` values from webpack. Other CSS module implementations might use different context resolution logic.|`process.cwd()`| |`exclude`|`string`|A RegExp that will exclude otherwise included files e.g., to exclude all styles from node_modules `exclude: 'node_modules'`| |`filetypes`|`?FiletypesConfigurationType`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugarss, LESS and SCSS and extra plugins for them. || -|`generateScopedName`|`?GenerateScopedNameConfigurationType`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names). If you use this option, make sure it matches the value of `localIdentName` in webpack config. See this [issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/108#issuecomment-334351241) |`[path]___[name]__[local]___[hash:base64:5]`| +|`generateScopedName`|`?GenerateScopedNameConfigurationType`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names). If you use this option, make sure it matches the value of `localIdentName` [in webpack config](https://webpack.js.org/loaders/css-loader/#localidentname). See this [issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/108#issuecomment-334351241) |`[path]___[name]__[local]___[hash:base64:5]`| |`removeImport`|`boolean`|Remove the matching style import. This option is used to enable server-side rendering.|`false`| |`webpackHotModuleReloading`|`boolean`|Enables hot reloading of CSS in webpack|`false`| |`handleMissingStyleName`|`"throw"`, `"warn"`, `"ignore"`|Determines what should be done for undefined CSS modules (using a `styleName` for which there is no CSS module defined). Setting this option to `"ignore"` is equivalent to setting `errorWhenNotFound: false` in [react-css-modules](https://github.com/gajus/react-css-modules#errorwhennotfound). |`"throw"`| @@ -520,4 +520,4 @@ $scales: 10, 20, 30, 40, 50; } ``` -`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found. \ No newline at end of file +`babel-plugin-react-css-modules` will not receive `icon-10` or `icon-50`, but `icon-#{$scale}`. That is why you receive the error that `styleName` `"icon-10"` cannot be found. From aef71c779bb79de4bbec9cb70e18016a65e8c865 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Fri, 23 Apr 2021 14:27:10 -0500 Subject: [PATCH 26/27] docs: add a call for maintainers --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1af05a7..d46a6d0 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ [![Gitter](https://img.shields.io/gitter/room/babel-plugin-react-css-modules/Lobby.svg?style=flat-square)](https://gitter.im/babel-plugin-react-css-modules/Lobby) [![Twitter Follow](https://img.shields.io/twitter/follow/kuizinas.svg?style=social&label=Follow)](https://twitter.com/kuizinas) +> # Looking for maintainers +> +> This project is not actively maintained by the original author. However, I am happy to nominate new maintainers. +> If you wish to contribute to `babel-plugin-react-css-modules`, please begin by raising PRs that fix existing issues. +> PRs must pass CI/CD tests, include tests (if they change behavior or fix a bug), and include documentation. + Transforms `styleName` to `className` using compile time [CSS module](#css-modules) resolution. @@ -264,7 +270,7 @@ To add support for different CSS syntaxes (e.g. SCSS), perform the following two > NOTE: [`postcss-nested`](https://github.com/postcss/postcss-nested) is added as an extra plugin for demonstration purposes only. It's not needed with [`postcss-scss`](https://github.com/postcss/postcss-scss) because SCSS already supports nesting. - Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config: + Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config: ```json "plugins": [ From eb008aaa7c8efc61c266f15b03c101cbb111a53e Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Fri, 23 Apr 2021 14:27:35 -0500 Subject: [PATCH 27/27] docs: remove gitspo link --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d46a6d0..44b349b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # babel-plugin-react-css-modules -[![GitSpo Mentions](https://gitspo.com/badges/mentions/gajus/babel-plugin-react-css-modules?style=flat-square)](https://gitspo.com/mentions/gajus/babel-plugin-react-css-modules) [![Travis build status](http://img.shields.io/travis/gajus/babel-plugin-react-css-modules/master.svg?style=flat-square)](https://travis-ci.org/gajus/babel-plugin-react-css-modules) [![NPM version](http://img.shields.io/npm/v/babel-plugin-react-css-modules.svg?style=flat-square)](https://www.npmjs.org/package/babel-plugin-react-css-modules) [![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical)