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
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
diff --git a/README.md b/README.md
index 858f2ee..44b349b 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,12 @@
[](https://gitter.im/babel-plugin-react-css-modules/Lobby)
[](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.
@@ -162,12 +168,12 @@ 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:
* 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,14 +196,16 @@ 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. ||
-|`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]`|
+|`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](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"`|
|`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:).
@@ -236,7 +244,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": {
@@ -246,7 +254,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": {
@@ -258,9 +266,11 @@ 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": [
["postcss-import-sync2", {
@@ -268,9 +278,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.
@@ -472,18 +482,47 @@ 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:
>
> 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.
diff --git a/demo/package.json b/demo/package.json
index ea45fbe..fed05fd 100644
--- a/demo/package.json
+++ b/demo/package.json
@@ -4,17 +4,17 @@
"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.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..2c83262 100644
--- a/package.json
+++ b/package.json
@@ -24,9 +24,12 @@
"@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-module-resolver": "^3.2.0",
"babel-plugin-tester": "^5.5.1",
"eslint": "^5.5.0",
"eslint-config-canonical": "^12.0.0",
@@ -66,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 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 && 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"
},
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/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/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/createSpreadMapper.js b/src/createSpreadMapper.js
new file mode 100644
index 0000000..176fb0a
--- /dev/null
+++ b/src/createSpreadMapper.js
@@ -0,0 +1,84 @@
+// @flow
+
+import {
+ Expression,
+ memberExpression,
+ binaryExpression,
+ conditionalExpression,
+ stringLiteral,
+ logicalExpression,
+ identifier,
+ isJSXSpreadAttribute
+} 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];
+ });
+
+ const spreadAttributes = path.node.openingElement.attributes
+ .filter((attr) => {
+ return isJSXSpreadAttribute(attr);
+ });
+
+ for (const spread of spreadAttributes) {
+ for (const attributeKey of attributeKeys) {
+ const destinationName = attributeNames[attributeKey];
+
+ if (result[destinationName]) {
+ result[destinationName] = binaryExpression(
+ '+',
+ result[destinationName],
+ conditionalExpression(
+ spread.argument,
+ binaryExpression(
+ '+',
+ stringLiteral(' '),
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ )
+ ),
+ stringLiteral('')
+ )
+ );
+ } else {
+ result[destinationName] = conditionalExpression(
+ spread.argument,
+ logicalExpression(
+ '||',
+ memberExpression(
+ spread.argument,
+ identifier(destinationName),
+ ),
+ stringLiteral('')
+ ),
+ stringLiteral('')
+ );
+ }
+ }
+ }
+
+ return result;
+};
+
+export default createSpreadMapper;
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 d99d858..823ce16 100644
--- a/src/getClassName.js
+++ b/src/getClassName.js
@@ -3,19 +3,26 @@
import type {
StyleModuleMapType,
StyleModuleImportMapType,
- HandleMissingStyleNameOptionType
+ HandleMissingStyleNameOptionType,
+ GetClassNameOptionsType
} from './types';
-
-type OptionsType = {|
- handleMissingStyleName: HandleMissingStyleNameOptionType
-|};
-
-const DEFAULT_HANDLE_MISSING_STYLENAME_OPTION = 'throw';
+import optionsDefaults from './schemas/optionsDefaults';
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,
@@ -28,49 +35,66 @@ 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') {
- 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 ||
- DEFAULT_HANDLE_MISSING_STYLENAME_OPTION;
+ const {
+ handleMissingStyleName = optionsDefaults.handleMissingStyleName,
+ autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports
+ } = options || {};
+
+ if (!styleNameValue) {
+ return '';
+ }
return styleNameValue
.split(' ')
@@ -88,20 +112,19 @@ 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);
}
+ // There is only one imported CSS module file.
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/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 b0367f4..477026b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -14,6 +14,10 @@ import createObjectExpression from './createObjectExpression';
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';
const ajv = new Ajv({
// eslint-disable-next-line id-match
@@ -31,6 +35,8 @@ export default ({
}) => {
const filenameMap = {};
+ let skip = false;
+
const setupFileForRuntimeResolution = (path, filename) => {
const programPath = path.findParent((parentPath) => {
return parentPath.isProgram();
@@ -121,27 +127,36 @@ export default ({
return require.resolve(path.node.source.value);
};
+ const isFilenameExcluded = (filename, exclude) => {
+ 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;
}
- 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;
}
- return false;
+ const filetypeKeys = Object.keys(stats.opts.filetypes);
+ filetypeKeys.push('.css');
+
+ return !findMatchedFiletype(filename, filetypeKeys);
};
return {
inherits: babelPluginJsxSyntax,
visitor: {
ImportDeclaration (path: *, stats: *): void {
- if (notForPlugin(path, stats)) {
+ if (skip || notForPlugin(path, stats)) {
return;
}
@@ -177,8 +192,16 @@ export default ({
}
},
JSXElement (path: *, stats: *): void {
+ if (skip) {
+ return;
+ }
+
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) {
@@ -194,20 +217,28 @@ export default ({
return;
}
- const handleMissingStyleName = stats.opts && stats.opts.handleMissingStyleName || optionsDefaults.handleMissingStyleName;
+ const {
+ handleMissingStyleName = optionsDefaults.handleMissingStyleName,
+ autoResolveMultipleImports = optionsDefaults.autoResolveMultipleImports
+ } = stats.opts || {};
+
+ const spreadMap = createSpreadMapper(path, stats);
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) {
@@ -220,9 +251,15 @@ export default ({
destinationName,
filenameMap[filename].importedHelperIndentifier,
filenameMap[filename].styleModuleImportMapIdentifier,
- {
- handleMissingStyleName
- }
+ options
+ );
+ }
+
+ if (spreadMap[destinationName]) {
+ handleSpreadClassName(
+ path,
+ destinationName,
+ spreadMap[destinationName]
);
}
}
@@ -240,6 +277,10 @@ export default ({
filenameMap[filename] = {
styleModuleImportMap: {}
};
+
+ if (stats.opts.skip && !attributeNameExists(path, stats)) {
+ skip = true;
+ }
}
}
};
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/requireCssModule.js b/src/requireCssModule.js
index 2126dbf..d77c25a 100644
--- a/src/requireCssModule.js
+++ b/src/requireCssModule.js
@@ -18,6 +18,8 @@ import type {
GenerateScopedNameConfigurationType,
StyleModuleMapType
} from './types';
+import findMatchedFiletype from './findMatchedFiletype';
+import optionsDefaults from './schemas/optionsDefaults';
type FiletypeOptionsType = {|
+syntax: string,
@@ -35,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
@@ -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/resolveStringLiteral.js b/src/resolveStringLiteral.js
index 5af63dd..f62e42a 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);
@@ -45,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/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'
};
diff --git a/src/schemas/optionsSchema.json b/src/schemas/optionsSchema.json
index e14e525..2257f0c 100644
--- a/src/schemas/optionsSchema.json
+++ b/src/schemas/optionsSchema.json
@@ -69,6 +69,12 @@
}
},
"type": "object"
+ },
+ "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/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 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");
+
+;
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/expected.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js
deleted file mode 100644
index 5d797f4..0000000
--- a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import './bar.css';
-
-const props = {
- foo: 'bar'
-};
-
-;
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/output.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
new file mode 100644
index 0000000..a325415
--- /dev/null
+++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/output.js
@@ -0,0 +1,8 @@
+"use strict";
+
+require("./bar.css");
+
+const props = {
+ foo: 'bar'
+};
+;
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";
+
+;
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/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..8e09b6d
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/input.js
@@ -0,0 +1,26 @@
+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..421a3f8
--- /dev/null
+++ b/test/fixtures/react-css-modules/handle spread attributes/output.js
@@ -0,0 +1,19 @@
+"use strict";
+
+require("./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/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 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");
+
+;
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 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 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
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 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 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/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';
+;
+;
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"
-}