1
- var DEFAULT_CLASSNAMES_FUNCTION = 'babel-plugin-react-pug-classnames/classnames'
1
+ var DEFAULT_CLASSNAMES_FUNCTION = 'babel-plugin-react-pug-classnames/classcat'
2
+ var LEGACY_CLASSNAMES_FUNCTION = 'babel-plugin-react-pug-classnames/prefixedClassnames'
3
+
4
+ // DEPRECATED.
5
+ // Legacy classnames prefixing is enabled by default for now.
6
+ // In later versions it will be turned off by default and then removed completely.
7
+ // If you need to provide some kind of BEM-like prefixing or another type
8
+ // of classnames functionality -- specify the classnamesFunction in options
9
+ // which must be a module name with the following code:
10
+ // exports.c = function (name, modifiers) { ... }
11
+ var DEFAULT_SUPPORT_LEGACY = true
2
12
3
13
function isTargetAttr ( attribute , classAttribute ) {
4
14
if ( ! classAttribute ) classAttribute = 'className'
@@ -10,19 +20,42 @@ function isGoodNameForNestedComponent (name) {
10
20
}
11
21
12
22
module . exports = ( babel ) => {
23
+ var reqName
24
+ var hasTransformedClassName
13
25
var t = babel . types
14
26
15
- function generateRequireExpression ( elementName , expression , classnamesFunction ) {
16
- var require = t . callExpression ( t . identifier ( 'require' ) , [
17
- t . stringLiteral ( classnamesFunction || DEFAULT_CLASSNAMES_FUNCTION )
18
- ] )
27
+ function isRequire ( node ) {
28
+ return (
29
+ node &&
30
+ node . declarations &&
31
+ node . declarations [ 0 ] &&
32
+ node . declarations [ 0 ] . init &&
33
+ node . declarations [ 0 ] . init . callee &&
34
+ node . declarations [ 0 ] . init . callee . name === "require"
35
+ ) ;
36
+ }
37
+
38
+ function generateRequireExpression ( elementName , expression , opts ) {
19
39
var callExpression = t . callExpression (
20
- require ,
40
+ reqName ,
21
41
[ t . stringLiteral ( elementName ) , expression ]
22
42
)
23
43
return callExpression
24
44
}
25
45
46
+ function generateRequire ( name , opts ) {
47
+ var legacy = opts . legacy == null ? DEFAULT_SUPPORT_LEGACY : opts . legacy
48
+ var classnamesFn = opts . classnamesFunction || (
49
+ legacy ? LEGACY_CLASSNAMES_FUNCTION : DEFAULT_CLASSNAMES_FUNCTION
50
+ )
51
+ var require = t . callExpression ( t . identifier ( 'require' ) , [
52
+ t . stringLiteral ( classnamesFn )
53
+ ] )
54
+ var cFn = t . memberExpression ( require , t . identifier ( 'c' ) ) ;
55
+ var d = t . variableDeclarator ( name , cFn ) ;
56
+ return t . variableDeclaration ( "var" , [ d ] ) ;
57
+ }
58
+
26
59
function processClass ( JSXOpeningElement , opts ) {
27
60
var name = JSXOpeningElement . node . name . name
28
61
var property = null
@@ -69,7 +102,8 @@ module.exports = (babel) => {
69
102
elementName = classes [ 0 ]
70
103
// Process only if the styleName value is an object or array
71
104
if ( t . isObjectExpression ( expr . right ) || t . isArrayExpression ( expr . right ) ) {
72
- expr . right = generateRequireExpression ( elementName , expr . right , opts . classnamesFunction )
105
+ hasTransformedClassName = true
106
+ expr . right = generateRequireExpression ( elementName , expr . right , opts )
73
107
}
74
108
}
75
109
} else if ( t . isArrayExpression ( JSXAttribute . node . value . expression ) ) {
@@ -90,7 +124,8 @@ module.exports = (babel) => {
90
124
if ( classes [ 0 ] ) {
91
125
elementName = classes [ 0 ]
92
126
// Process only if the styleName value is an object or array
93
- expr = generateRequireExpression ( elementName , expr , opts . requireFunction )
127
+ hasTransformedClassName = true
128
+ expr = generateRequireExpression ( elementName , expr , opts )
94
129
}
95
130
96
131
var plus = t . binaryExpression ( '+' , t . stringLiteral ( classes . join ( ' ' ) + ' ' ) , expr )
@@ -112,7 +147,32 @@ module.exports = (babel) => {
112
147
}
113
148
114
149
return {
150
+ post ( ) {
151
+ reqName = null ;
152
+ hasTransformedClassName = null ;
153
+ } ,
115
154
visitor : {
155
+ Program : {
156
+ enter ( path , state ) {
157
+ reqName = path . scope . generateUidIdentifier (
158
+ "classnames"
159
+ ) ;
160
+ } ,
161
+ exit ( path , state ) {
162
+ if ( ! hasTransformedClassName ) {
163
+ return ;
164
+ }
165
+
166
+ const lastImportOrRequire = path
167
+ . get ( "body" )
168
+ . filter ( p => p . isImportDeclaration ( ) || isRequire ( p . node ) )
169
+ . pop ( ) ;
170
+
171
+ if ( lastImportOrRequire ) {
172
+ lastImportOrRequire . insertAfter ( generateRequire ( reqName , state . opts ) ) ;
173
+ }
174
+ }
175
+ } ,
116
176
JSXElement ( JSXElement , params ) {
117
177
JSXElement . traverse ( {
118
178
JSXOpeningElement ( JSXOpeningElement ) {
0 commit comments