File tree 8 files changed +191
-1
lines changed
test/fixtures/react-css-modules
does not throw error if attribute has no name property
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';
15
15
import resolveStringLiteral from './resolveStringLiteral' ;
16
16
import replaceJsxExpressionContainer from './replaceJsxExpressionContainer' ;
17
17
import attributeNameExists from './attributeNameExists' ;
18
+ import createSpreadMapper from './createSpreadMapper' ;
19
+ import handleSpreadClassName from './handleSpreadClassName' ;
18
20
19
21
const ajv = new Ajv ( {
20
22
// eslint-disable-next-line id-match
@@ -216,6 +218,8 @@ export default ({
216
218
autoResolveMultipleImports = optionsDefaults . autoResolveMultipleImports
217
219
} = stats . opts || { } ;
218
220
221
+ const spreadMap = createSpreadMapper ( path , stats ) ;
222
+
219
223
for ( const attribute of attributes ) {
220
224
const destinationName = attributeNames [ attribute . name . name ] ;
221
225
@@ -246,6 +250,14 @@ export default ({
246
250
options
247
251
) ;
248
252
}
253
+
254
+ if ( spreadMap [ destinationName ] ) {
255
+ handleSpreadClassName (
256
+ path ,
257
+ destinationName ,
258
+ spreadMap [ destinationName ]
259
+ ) ;
260
+ }
249
261
}
250
262
} ,
251
263
Program ( path : * , stats : * ) : void {
Original file line number Diff line number Diff line change @@ -5,4 +5,4 @@ require("./bar.css");
5
5
const props = {
6
6
foo : 'bar'
7
7
} ;
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