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 @@ [![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. @@ -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" -}