File tree Expand file tree Collapse file tree 8 files changed +191
-1
lines changed
test/fixtures/react-css-modules
does not throw error if attribute has no name property Expand file tree Collapse file tree 8 files changed +191
-1
lines changed Original file line number Diff line number Diff line change 1+ // @flow
2+
3+ import {
4+ Expression ,
5+ memberExpression ,
6+ binaryExpression ,
7+ stringLiteral ,
8+ logicalExpression ,
9+ identifier
10+ } from '@babel/types' ;
11+ import optionsDefaults from './schemas/optionsDefaults' ;
12+
13+ const createSpreadMapper = ( path : * , stats : * ) : { [ destinationName : string ] : Expression } = > {
14+ const result = { } ;
15+
16+ let { attributeNames} = optionsDefaults ;
17+
18+ if ( stats . opts && stats . opts . attributeNames ) {
19+ attributeNames = Object . assign ( { } , attributeNames , stats . opts . attributeNames ) ;
20+ }
21+
22+ const attributes = Object
23+ . entries ( attributeNames )
24+ . filter ( ( pair ) => {
25+ return pair [ 1 ] ;
26+ } ) ;
27+
28+ const attributeKeys = attributes . map ( ( pair ) => {
29+ return pair [ 0 ] ;
30+ } ) ;
31+
32+ path . traverse ( {
33+ JSXSpreadAttribute ( spreadPath : * ) {
34+ const spread = spreadPath . node ;
35+
36+ for ( const attributeKey of attributeKeys ) {
37+ const destinationName = attributeNames [ attributeKey ] ;
38+
39+ if ( result [ destinationName ] ) {
40+ result [ destinationName ] = binaryExpression (
41+ '+' ,
42+ result [ destinationName ] ,
43+ binaryExpression (
44+ '+' ,
45+ stringLiteral ( ' ' ) ,
46+ logicalExpression (
47+ '||' ,
48+ memberExpression (
49+ spread . argument ,
50+ identifier ( destinationName ) ,
51+ ) ,
52+ stringLiteral ( '' )
53+ )
54+ ) ,
55+ ) ;
56+ } else {
57+ result [ destinationName ] = logicalExpression (
58+ '||' ,
59+ memberExpression (
60+ spread . argument ,
61+ identifier ( destinationName ) ,
62+ ) ,
63+ stringLiteral ( '' )
64+ ) ;
65+ }
66+ }
67+ }
68+ } ) ;
69+
70+ return result ;
71+ } ;
72+
73+ export default createSpreadMapper ;
Original file line number Diff line number Diff line change 1+ // @flow
2+
3+ import {
4+ Expression ,
5+ isStringLiteral ,
6+ isJSXExpressionContainer ,
7+ jsxExpressionContainer ,
8+ binaryExpression ,
9+ stringLiteral
10+ } from '@babel/types' ;
11+
12+ const handleSpreadClassName = (
13+ path : * ,
14+ destinationName : string ,
15+ classNamesFromSpread : Expression
16+ ) => {
17+ const destinationAttribute = path . node . openingElement . attributes
18+ . find ( ( attribute ) => {
19+ return typeof attribute . name !== 'undefined' && attribute . name . name === destinationName ;
20+ } ) ;
21+
22+ if ( ! destinationAttribute ) {
23+ return ;
24+ }
25+
26+ if ( isStringLiteral ( destinationAttribute . value ) ) {
27+ destinationAttribute . value = jsxExpressionContainer (
28+ binaryExpression (
29+ '+' ,
30+ destinationAttribute . value ,
31+ binaryExpression (
32+ '+' ,
33+ stringLiteral ( ' ' ) ,
34+ classNamesFromSpread ,
35+ )
36+ )
37+ ) ;
38+ } else if ( isJSXExpressionContainer ( destinationAttribute . value ) ) {
39+ destinationAttribute . value = jsxExpressionContainer (
40+ binaryExpression (
41+ '+' ,
42+ destinationAttribute . value . expression ,
43+ binaryExpression (
44+ '+' ,
45+ stringLiteral ( ' ' ) ,
46+ classNamesFromSpread
47+ )
48+ )
49+ ) ;
50+ }
51+ } ;
52+
53+ export default handleSpreadClassName ;
Original file line number Diff line number Diff line change @@ -15,6 +15,8 @@ import requireCssModule from './requireCssModule';
1515import resolveStringLiteral from './resolveStringLiteral' ;
1616import replaceJsxExpressionContainer from './replaceJsxExpressionContainer' ;
1717import attributeNameExists from './attributeNameExists' ;
18+ import createSpreadMapper from './createSpreadMapper' ;
19+ import handleSpreadClassName from './handleSpreadClassName' ;
1820
1921const ajv = new Ajv ( {
2022 // eslint-disable-next-line id-match
@@ -216,6 +218,8 @@ export default ({
216218 autoResolveMultipleImports = optionsDefaults . autoResolveMultipleImports
217219 } = stats . opts || { } ;
218220
221+ const spreadMap = createSpreadMapper ( path , stats ) ;
222+
219223 for ( const attribute of attributes ) {
220224 const destinationName = attributeNames [ attribute . name . name ] ;
221225
@@ -246,6 +250,14 @@ export default ({
246250 options
247251 ) ;
248252 }
253+
254+ if ( spreadMap [ destinationName ] ) {
255+ handleSpreadClassName (
256+ path ,
257+ destinationName ,
258+ spreadMap [ destinationName ]
259+ ) ;
260+ }
249261 }
250262 } ,
251263 Program ( path : * , stats : * ) : void {
Original file line number Diff line number Diff line change @@ -5,4 +5,4 @@ require("./bar.css");
55const props = {
66 foo : 'bar'
77} ;
8- < div className = "bar__a" { ...props } > </ div > ;
8+ < div className = { "bar__a" + ( " " + ( props . className || "" ) ) } { ...props } > </ div > ;
Original file line number Diff line number Diff line change 1+ .a {}
Original file line number Diff line number Diff line change 1+ import './foo.css' ;
2+
3+ const rest = { } ;
4+
5+ < div { ...rest } styleName = "a" className = "b" > </ div > ;
6+
7+ < div { ...rest } styleName = "a" > </ div > ;
8+
9+ < div { ...rest } activeClassName = { this . props . activeClassName } activeStyleName = "a" styleName = "a" > </ div > ;
10+
11+ < div { ...rest } activeStyleName = "a" activeClassName = "b" > </ div > ;
12+
13+ // Should be okay if rest is put on last
14+ < div styleName = "a" { ...rest } > </ div > ;
15+
16+ const rest2 = { } ;
17+
18+ < div { ...rest } { ...rest2 } styleName = "a" > </ div > ;
19+
20+ // Should not do anything
21+ < div { ...rest } { ...rest2 } > </ div > ;
22+ < div { ...rest } { ...rest2 } className = "b" > </ div > ;
Original file line number Diff line number Diff line change 1+ {
2+ "plugins" : [
3+ [
4+ " ../../../../src" ,
5+ {
6+ "generateScopedName" : " [name]__[local]" ,
7+ "attributeNames" : {
8+ "activeStyleName" : " activeClassName"
9+ }
10+ }
11+ ]
12+ ]
13+ }
Original file line number Diff line number Diff line change 1+ "use strict" ;
2+
3+ require ( "./foo.css" ) ;
4+
5+ const rest = { } ;
6+ < div { ...rest } className = { "b foo__a" + ( " " + ( rest . className || "" ) ) } > </ div > ;
7+ < div { ...rest } className = { "foo__a" + ( " " + ( rest . className || "" ) ) } > </ div > ;
8+ < div { ...rest } activeClassName = { ( ( void 0 ) . props . activeClassName ? ( void 0 ) . props . activeClassName + " " : "" ) + "foo__a" + ( " " + ( rest . activeClassName || "" ) ) } className = { "foo__a" + ( " " + ( rest . className || "" ) ) } > </ div > ;
9+ < div { ...rest } activeClassName = { "b foo__a" + ( " " + ( rest . activeClassName || "" ) ) } > </ div > ; // Should be okay if rest is put on last
10+
11+ < div className = { "foo__a" + ( " " + ( rest . className || "" ) ) } { ...rest } > </ div > ;
12+ const rest2 = { } ;
13+ < div { ...rest } { ...rest2 } className = { "foo__a" + ( " " + ( ( rest . className || "" ) + ( " " + ( rest2 . className || "" ) ) ) ) } > </ div > ; // Should not do anything
14+
15+ < div { ...rest } { ...rest2 } > </ div > ;
16+ < div { ...rest } { ...rest2 } className = "b" > </ div > ;
You can’t perform that action at this time.
0 commit comments