@@ -42,6 +42,96 @@ var DEV_EXPRESSION = builders.binaryExpression(
42
42
function transform ( ast , constants ) {
43
43
constants = constants || { } ;
44
44
45
+ var devProgram = copyAst ( ast . program ) ;
46
+ var prodProgram = copyAst ( ast . program ) ;
47
+
48
+ devProgram = transformDev ( hoistFunctions ( devProgram ) , constants ) ;
49
+ prodProgram = transformProd ( hoistFunctions ( prodProgram ) , constants ) ;
50
+
51
+ return builders . program ( [
52
+ builders . ifStatement (
53
+ DEV_EXPRESSION ,
54
+ builders . blockStatement ( devProgram . body ) ,
55
+ builders . blockStatement ( prodProgram . body )
56
+ )
57
+ ] ) ;
58
+ }
59
+
60
+ function copyAst ( node ) {
61
+ if ( node instanceof RegExp ) {
62
+ return node ;
63
+ } else if ( node instanceof Array ) {
64
+ return node . map ( copyAst ) ;
65
+ } else if ( typeof node === "object" && node != null ) {
66
+ var newNode = Object . create ( Object . getPrototypeOf ( node ) ) ;
67
+ for ( var key in node ) {
68
+ if ( ! Object . prototype . hasOwnProperty . call ( node , key ) ) {
69
+ continue ;
70
+ }
71
+ if ( namedTypes . Node . check ( node ) ) {
72
+ newNode [ key ] = copyAst ( node [ key ] ) ;
73
+ } else {
74
+ newNode [ key ] = node [ key ] ;
75
+ }
76
+ }
77
+
78
+ Object . defineProperty ( newNode , "original" , {
79
+ value : node . original ,
80
+ configurable : false ,
81
+ enumerable : false ,
82
+ writable : true
83
+ } ) ;
84
+
85
+ return newNode ;
86
+ } else {
87
+ return node ;
88
+ }
89
+ }
90
+
91
+ function isUseStrict ( node ) {
92
+ return node &&
93
+ namedTypes . ExpressionStatement . check ( node ) &&
94
+ namedTypes . Literal . check ( node . expression ) &&
95
+ node . expression . value === "use strict" ;
96
+ }
97
+
98
+ function hoistFunctions ( program ) {
99
+ var functionVariableDeclarations = [ ] ;
100
+
101
+ var body = program . body . slice ( ) ;
102
+ for ( var i = 0 ; i < body . length ; i ++ ) {
103
+ var node = body [ i ] ;
104
+ if ( namedTypes . FunctionDeclaration . check ( node ) ) {
105
+ functionVariableDeclarations . push (
106
+ builders . variableDeclaration ( "var" , [
107
+ builders . variableDeclarator (
108
+ node . id ,
109
+ builders . functionExpression (
110
+ null ,
111
+ node . params ,
112
+ node . body ,
113
+ node . generator ,
114
+ node . expression ,
115
+ // Switch to node.async after upgrading esprima-fb
116
+ false
117
+ )
118
+ )
119
+ ] )
120
+ ) ;
121
+ body . splice ( i , 1 ) ;
122
+ i -- ;
123
+ }
124
+ }
125
+
126
+ // Insert functions after "use strict", if present
127
+ body . splice . apply (
128
+ body ,
129
+ [ isUseStrict ( body [ 0 ] ) ? 1 : 0 , 0 ] . concat ( functionVariableDeclarations )
130
+ ) ;
131
+ return builders . program ( body ) ;
132
+ }
133
+
134
+ function transformDev ( ast , constants ) {
45
135
return types . traverse ( ast , function ( node , traverse ) {
46
136
if ( namedTypes . Identifier . check ( node ) ) {
47
137
// If the identifier is the property of a member expression
@@ -53,12 +143,40 @@ function transform(ast, constants) {
53
143
return false ;
54
144
}
55
145
146
+ if ( node . name === '__DEV__' ) {
147
+ // Replace __DEV__ with 'true'
148
+ this . replace ( builders . literal ( true ) ) ;
149
+ return false ;
150
+
56
151
// There could in principle be a constant called "hasOwnProperty",
57
152
// so be careful always to use Object.prototype.hasOwnProperty.
153
+ } else if ( hasOwn . call ( constants , node . name ) ) {
154
+ this . replace ( builders . literal ( constants [ node . name ] ) ) ;
155
+ return false ;
156
+ }
157
+ }
158
+ } ) ;
159
+ }
160
+
161
+ function transformProd ( ast , constants ) {
162
+ return types . traverse ( ast , function ( node , traverse ) {
163
+ if ( namedTypes . Identifier . check ( node ) ) {
164
+ // If the identifier is the property of a member expression
165
+ // (e.g. object.property), then it definitely is not a constant
166
+ // expression that we want to replace.
167
+ if ( namedTypes . MemberExpression . check ( this . parent . node ) &&
168
+ this . name === 'property' &&
169
+ ! this . parent . node . computed ) {
170
+ return false ;
171
+ }
172
+
58
173
if ( node . name === '__DEV__' ) {
59
- // replace __DEV__ with process.env.NODE_ENV !== 'production '
60
- this . replace ( DEV_EXPRESSION ) ;
174
+ // Replace __DEV__ with 'false '
175
+ this . replace ( builders . literal ( false ) ) ;
61
176
return false ;
177
+
178
+ // There could in principle be a constant called "hasOwnProperty",
179
+ // so be careful always to use Object.prototype.hasOwnProperty.
62
180
} else if ( hasOwn . call ( constants , node . name ) ) {
63
181
this . replace ( builders . literal ( constants [ node . name ] ) ) ;
64
182
return false ;
@@ -67,30 +185,20 @@ function transform(ast, constants) {
67
185
} else if ( namedTypes . CallExpression . check ( node ) ) {
68
186
if ( namedTypes . Identifier . check ( node . callee ) &&
69
187
node . callee . name === 'invariant' ) {
70
- // Truncate the arguments of invariant(condition, ...)
71
- // statements to just the condition based on NODE_ENV
72
- // (dead code removal will remove the extra bytes).
188
+ // Truncate the arguments of invariant(condition, ...) statements to
189
+ // just the condition
73
190
this . replace (
74
- builders . conditionalExpression (
75
- DEV_EXPRESSION ,
76
- node ,
77
- builders . callExpression (
78
- node . callee ,
79
- [ node . arguments [ 0 ] ]
80
- )
191
+ builders . callExpression (
192
+ node . callee ,
193
+ [ node . arguments [ 0 ] ]
81
194
)
82
195
) ;
83
196
return false ;
84
197
} else if ( namedTypes . Identifier . check ( node . callee ) &&
85
198
node . callee . name === 'warning' ) {
86
- // Eliminate warning(condition, ...) statements based on NODE_ENV
87
- // (dead code removal will remove the extra bytes).
199
+ // Eliminate warning(condition, ...) statements
88
200
this . replace (
89
- builders . conditionalExpression (
90
- DEV_EXPRESSION ,
91
- node ,
92
- builders . literal ( null )
93
- )
201
+ builders . literal ( null )
94
202
) ;
95
203
}
96
204
}
0 commit comments