react-refresh 0.4.0-rc.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license React
|
|
1
|
+
/** @license React vundefined
|
|
2
2
|
* react-refresh-babel.development.js
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
@@ -16,23 +16,27 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
var ReactFreshBabelPlugin = function (babel) {
|
|
19
|
+
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
20
|
+
|
|
19
21
|
if (typeof babel.getEnv === 'function') {
|
|
20
22
|
// Only available in Babel 7.
|
|
21
23
|
var env = babel.getEnv();
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
if (env !== 'development' && !opts.skipEnvCheck) {
|
|
26
|
+
throw new Error('React Refresh Babel transform should only be enabled in development environment. ' + 'Instead, the environment is: "' + env + '". If you want to override this check, pass {skipEnvCheck: true} as plugin options.');
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
var t = babel.types;
|
|
28
|
-
|
|
29
|
-
|
|
30
31
|
var registrationsByProgramPath = new Map();
|
|
32
|
+
|
|
31
33
|
function createRegistration(programPath, persistentID) {
|
|
32
34
|
var handle = programPath.scope.generateUidIdentifier('c');
|
|
35
|
+
|
|
33
36
|
if (!registrationsByProgramPath.has(programPath)) {
|
|
34
37
|
registrationsByProgramPath.set(programPath, []);
|
|
35
38
|
}
|
|
39
|
+
|
|
36
40
|
var registrations = registrationsByProgramPath.get(programPath);
|
|
37
41
|
registrations.push({
|
|
38
42
|
handle: handle,
|
|
@@ -47,17 +51,20 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
47
51
|
|
|
48
52
|
function findInnerComponents(inferredName, path, callback) {
|
|
49
53
|
var node = path.node;
|
|
54
|
+
|
|
50
55
|
switch (node.type) {
|
|
51
56
|
case 'Identifier':
|
|
52
57
|
{
|
|
53
58
|
if (!isComponentishName(node.name)) {
|
|
54
59
|
return false;
|
|
55
|
-
}
|
|
56
|
-
// export default hoc(Foo)
|
|
60
|
+
} // export default hoc(Foo)
|
|
57
61
|
// const X = hoc(Foo)
|
|
62
|
+
|
|
63
|
+
|
|
58
64
|
callback(inferredName, node, null);
|
|
59
65
|
return true;
|
|
60
66
|
}
|
|
67
|
+
|
|
61
68
|
case 'FunctionDeclaration':
|
|
62
69
|
{
|
|
63
70
|
// function Foo() {}
|
|
@@ -66,16 +73,19 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
66
73
|
callback(inferredName, node.id, null);
|
|
67
74
|
return true;
|
|
68
75
|
}
|
|
76
|
+
|
|
69
77
|
case 'ArrowFunctionExpression':
|
|
70
78
|
{
|
|
71
79
|
if (node.body.type === 'ArrowFunctionExpression') {
|
|
72
80
|
return false;
|
|
73
|
-
}
|
|
74
|
-
// let Foo = () => {}
|
|
81
|
+
} // let Foo = () => {}
|
|
75
82
|
// export default hoc1(hoc2(() => {}))
|
|
83
|
+
|
|
84
|
+
|
|
76
85
|
callback(inferredName, node, path);
|
|
77
86
|
return true;
|
|
78
87
|
}
|
|
88
|
+
|
|
79
89
|
case 'FunctionExpression':
|
|
80
90
|
{
|
|
81
91
|
// let Foo = function() {}
|
|
@@ -84,13 +94,17 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
84
94
|
callback(inferredName, node, path);
|
|
85
95
|
return true;
|
|
86
96
|
}
|
|
97
|
+
|
|
87
98
|
case 'CallExpression':
|
|
88
99
|
{
|
|
89
100
|
var argsPath = path.get('arguments');
|
|
101
|
+
|
|
90
102
|
if (argsPath === undefined || argsPath.length === 0) {
|
|
91
103
|
return false;
|
|
92
104
|
}
|
|
105
|
+
|
|
93
106
|
var calleePath = path.get('callee');
|
|
107
|
+
|
|
94
108
|
switch (calleePath.node.type) {
|
|
95
109
|
case 'MemberExpression':
|
|
96
110
|
case 'Identifier':
|
|
@@ -99,41 +113,51 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
99
113
|
var firstArgPath = argsPath[0];
|
|
100
114
|
var innerName = inferredName + '$' + calleeSource;
|
|
101
115
|
var foundInside = findInnerComponents(innerName, firstArgPath, callback);
|
|
116
|
+
|
|
102
117
|
if (!foundInside) {
|
|
103
118
|
return false;
|
|
104
|
-
}
|
|
105
|
-
// const Foo = hoc1(hoc2(() => {}))
|
|
119
|
+
} // const Foo = hoc1(hoc2(() => {}))
|
|
106
120
|
// export default memo(React.forwardRef(function() {}))
|
|
121
|
+
|
|
122
|
+
|
|
107
123
|
callback(inferredName, node, path);
|
|
108
124
|
return true;
|
|
109
125
|
}
|
|
126
|
+
|
|
110
127
|
default:
|
|
111
128
|
{
|
|
112
129
|
return false;
|
|
113
130
|
}
|
|
114
131
|
}
|
|
115
132
|
}
|
|
133
|
+
|
|
116
134
|
case 'VariableDeclarator':
|
|
117
135
|
{
|
|
118
136
|
var init = node.init;
|
|
137
|
+
|
|
119
138
|
if (init === null) {
|
|
120
139
|
return false;
|
|
121
140
|
}
|
|
141
|
+
|
|
122
142
|
var name = node.id.name;
|
|
143
|
+
|
|
123
144
|
if (!isComponentishName(name)) {
|
|
124
145
|
return false;
|
|
125
146
|
}
|
|
147
|
+
|
|
126
148
|
switch (init.type) {
|
|
127
149
|
case 'ArrowFunctionExpression':
|
|
128
150
|
case 'FunctionExpression':
|
|
129
151
|
// Likely component definitions.
|
|
130
152
|
break;
|
|
153
|
+
|
|
131
154
|
case 'CallExpression':
|
|
132
155
|
{
|
|
133
156
|
// Maybe a HOC.
|
|
134
157
|
// Try to determine if this is some form of import.
|
|
135
158
|
var callee = init.callee;
|
|
136
159
|
var calleeType = callee.type;
|
|
160
|
+
|
|
137
161
|
if (calleeType === 'Import') {
|
|
138
162
|
return false;
|
|
139
163
|
} else if (calleeType === 'Identifier') {
|
|
@@ -141,55 +165,70 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
141
165
|
return false;
|
|
142
166
|
} else if (callee.name.indexOf('import') === 0) {
|
|
143
167
|
return false;
|
|
144
|
-
}
|
|
145
|
-
// Neither require nor import. Might be a HOC.
|
|
168
|
+
} // Neither require nor import. Might be a HOC.
|
|
146
169
|
// Pass through.
|
|
147
|
-
|
|
148
|
-
|
|
170
|
+
|
|
171
|
+
} else if (calleeType === 'MemberExpression') {// Could be something like React.forwardRef(...)
|
|
149
172
|
// Pass through.
|
|
150
173
|
} else {
|
|
151
174
|
// More complicated call.
|
|
152
175
|
return false;
|
|
153
176
|
}
|
|
177
|
+
|
|
154
178
|
break;
|
|
155
179
|
}
|
|
180
|
+
|
|
156
181
|
case 'TaggedTemplateExpression':
|
|
157
182
|
// Maybe something like styled.div`...`
|
|
158
183
|
break;
|
|
184
|
+
|
|
159
185
|
default:
|
|
160
186
|
return false;
|
|
161
187
|
}
|
|
188
|
+
|
|
162
189
|
var initPath = path.get('init');
|
|
190
|
+
|
|
163
191
|
var _foundInside = findInnerComponents(inferredName, initPath, callback);
|
|
192
|
+
|
|
164
193
|
if (_foundInside) {
|
|
165
194
|
return true;
|
|
166
|
-
}
|
|
167
|
-
|
|
195
|
+
} // See if this identifier is used in JSX. Then it's a component.
|
|
196
|
+
|
|
197
|
+
|
|
168
198
|
var binding = path.scope.getBinding(name);
|
|
199
|
+
|
|
169
200
|
if (binding === undefined) {
|
|
170
201
|
return;
|
|
171
202
|
}
|
|
203
|
+
|
|
172
204
|
var isLikelyUsedAsType = false;
|
|
173
205
|
var referencePaths = binding.referencePaths;
|
|
206
|
+
|
|
174
207
|
for (var i = 0; i < referencePaths.length; i++) {
|
|
175
208
|
var ref = referencePaths[i];
|
|
209
|
+
|
|
176
210
|
if (ref.node.type !== 'JSXIdentifier' && ref.node.type !== 'Identifier') {
|
|
177
211
|
continue;
|
|
178
212
|
}
|
|
213
|
+
|
|
179
214
|
var refParent = ref.parent;
|
|
215
|
+
|
|
180
216
|
if (refParent.type === 'JSXOpeningElement') {
|
|
181
217
|
isLikelyUsedAsType = true;
|
|
182
218
|
} else if (refParent.type === 'CallExpression') {
|
|
183
219
|
var _callee = refParent.callee;
|
|
184
220
|
var fnName = void 0;
|
|
221
|
+
|
|
185
222
|
switch (_callee.type) {
|
|
186
223
|
case 'Identifier':
|
|
187
224
|
fnName = _callee.name;
|
|
188
225
|
break;
|
|
226
|
+
|
|
189
227
|
case 'MemberExpression':
|
|
190
228
|
fnName = _callee.property.name;
|
|
191
229
|
break;
|
|
192
230
|
}
|
|
231
|
+
|
|
193
232
|
switch (fnName) {
|
|
194
233
|
case 'createElement':
|
|
195
234
|
case 'jsx':
|
|
@@ -199,6 +238,7 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
199
238
|
break;
|
|
200
239
|
}
|
|
201
240
|
}
|
|
241
|
+
|
|
202
242
|
if (isLikelyUsedAsType) {
|
|
203
243
|
// const X = ... + later <X />
|
|
204
244
|
callback(inferredName, init, initPath);
|
|
@@ -207,6 +247,7 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
207
247
|
}
|
|
208
248
|
}
|
|
209
249
|
}
|
|
250
|
+
|
|
210
251
|
return false;
|
|
211
252
|
}
|
|
212
253
|
|
|
@@ -233,6 +274,7 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
233
274
|
case 'useDebugValue':
|
|
234
275
|
case 'React.useDebugValue':
|
|
235
276
|
return true;
|
|
277
|
+
|
|
236
278
|
default:
|
|
237
279
|
return false;
|
|
238
280
|
}
|
|
@@ -240,9 +282,11 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
240
282
|
|
|
241
283
|
function getHookCallsSignature(functionNode) {
|
|
242
284
|
var fnHookCalls = hookCalls.get(functionNode);
|
|
285
|
+
|
|
243
286
|
if (fnHookCalls === undefined) {
|
|
244
287
|
return null;
|
|
245
288
|
}
|
|
289
|
+
|
|
246
290
|
return {
|
|
247
291
|
key: fnHookCalls.map(function (call) {
|
|
248
292
|
return call.name + '{' + call.key + '}';
|
|
@@ -255,20 +299,22 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
255
299
|
};
|
|
256
300
|
}
|
|
257
301
|
|
|
258
|
-
var hasForceResetCommentByFile = new WeakMap();
|
|
302
|
+
var hasForceResetCommentByFile = new WeakMap(); // We let user do /* @refresh reset */ to reset state in the whole file.
|
|
259
303
|
|
|
260
|
-
// We let user do /* @refresh reset */ to reset state in the whole file.
|
|
261
304
|
function hasForceResetComment(path) {
|
|
262
305
|
var file = path.hub.file;
|
|
263
306
|
var hasForceReset = hasForceResetCommentByFile.get(file);
|
|
307
|
+
|
|
264
308
|
if (hasForceReset !== undefined) {
|
|
265
309
|
return hasForceReset;
|
|
266
310
|
}
|
|
267
311
|
|
|
268
312
|
hasForceReset = false;
|
|
269
313
|
var comments = file.ast.comments;
|
|
314
|
+
|
|
270
315
|
for (var i = 0; i < comments.length; i++) {
|
|
271
316
|
var cmt = comments[i];
|
|
317
|
+
|
|
272
318
|
if (cmt.value.indexOf('@refresh reset') !== -1) {
|
|
273
319
|
hasForceReset = true;
|
|
274
320
|
break;
|
|
@@ -282,23 +328,25 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
282
328
|
function createArgumentsForSignature(node, signature, scope) {
|
|
283
329
|
var key = signature.key,
|
|
284
330
|
customHooks = signature.customHooks;
|
|
285
|
-
|
|
286
|
-
|
|
287
331
|
var forceReset = hasForceResetComment(scope.path);
|
|
288
332
|
var customHooksInScope = [];
|
|
289
333
|
customHooks.forEach(function (callee) {
|
|
290
334
|
// Check if a corresponding binding exists where we emit the signature.
|
|
291
|
-
var bindingName
|
|
335
|
+
var bindingName;
|
|
336
|
+
|
|
292
337
|
switch (callee.type) {
|
|
293
338
|
case 'MemberExpression':
|
|
294
339
|
if (callee.object.type === 'Identifier') {
|
|
295
340
|
bindingName = callee.object.name;
|
|
296
341
|
}
|
|
342
|
+
|
|
297
343
|
break;
|
|
344
|
+
|
|
298
345
|
case 'Identifier':
|
|
299
346
|
bindingName = callee.name;
|
|
300
347
|
break;
|
|
301
348
|
}
|
|
349
|
+
|
|
302
350
|
if (scope.hasBinding(bindingName)) {
|
|
303
351
|
customHooksInScope.push(callee);
|
|
304
352
|
} else {
|
|
@@ -307,64 +355,82 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
307
355
|
forceReset = true;
|
|
308
356
|
}
|
|
309
357
|
});
|
|
358
|
+
var finalKey = key;
|
|
359
|
+
|
|
360
|
+
if (typeof require === 'function' && !opts.emitFullSignatures) {
|
|
361
|
+
// Prefer to hash when we can (e.g. outside of ASTExplorer).
|
|
362
|
+
// This makes it deterministically compact, even if there's
|
|
363
|
+
// e.g. a useState ininitalizer with some code inside.
|
|
364
|
+
// We also need it for www that has transforms like cx()
|
|
365
|
+
// that don't understand if something is part of a string.
|
|
366
|
+
finalKey = require('crypto').createHash('sha1').update(key).digest('base64');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
var args = [node, t.stringLiteral(finalKey)];
|
|
310
370
|
|
|
311
|
-
var args = [node, t.stringLiteral(key)];
|
|
312
371
|
if (forceReset || customHooksInScope.length > 0) {
|
|
313
372
|
args.push(t.booleanLiteral(forceReset));
|
|
314
373
|
}
|
|
374
|
+
|
|
315
375
|
if (customHooksInScope.length > 0) {
|
|
316
|
-
args.push(
|
|
317
|
-
// TODO: We could use an arrow here to be more compact.
|
|
376
|
+
args.push( // TODO: We could use an arrow here to be more compact.
|
|
318
377
|
// However, don't do it until AMA can run them natively.
|
|
319
378
|
t.functionExpression(null, [], t.blockStatement([t.returnStatement(t.arrayExpression(customHooksInScope))])));
|
|
320
379
|
}
|
|
380
|
+
|
|
321
381
|
return args;
|
|
322
382
|
}
|
|
323
383
|
|
|
324
384
|
var seenForRegistration = new WeakSet();
|
|
325
385
|
var seenForSignature = new WeakSet();
|
|
326
386
|
var seenForOutro = new WeakSet();
|
|
327
|
-
|
|
328
387
|
var hookCalls = new WeakMap();
|
|
329
388
|
var HookCallsVisitor = {
|
|
330
389
|
CallExpression: function (path) {
|
|
331
390
|
var node = path.node;
|
|
332
|
-
var callee = node.callee;
|
|
333
|
-
|
|
334
|
-
// Note: this visitor MUST NOT mutate the tree in any way.
|
|
391
|
+
var callee = node.callee; // Note: this visitor MUST NOT mutate the tree in any way.
|
|
335
392
|
// It runs early in a separate traversal and should be very fast.
|
|
336
393
|
|
|
337
394
|
var name = null;
|
|
395
|
+
|
|
338
396
|
switch (callee.type) {
|
|
339
397
|
case 'Identifier':
|
|
340
398
|
name = callee.name;
|
|
341
399
|
break;
|
|
400
|
+
|
|
342
401
|
case 'MemberExpression':
|
|
343
402
|
name = callee.property.name;
|
|
344
403
|
break;
|
|
345
404
|
}
|
|
405
|
+
|
|
346
406
|
if (name === null || !/^use[A-Z]/.test(name)) {
|
|
347
407
|
return;
|
|
348
408
|
}
|
|
409
|
+
|
|
349
410
|
var fnScope = path.scope.getFunctionParent();
|
|
411
|
+
|
|
350
412
|
if (fnScope === null) {
|
|
351
413
|
return;
|
|
352
|
-
}
|
|
414
|
+
} // This is a Hook call. Record it.
|
|
415
|
+
|
|
353
416
|
|
|
354
|
-
// This is a Hook call. Record it.
|
|
355
417
|
var fnNode = fnScope.block;
|
|
418
|
+
|
|
356
419
|
if (!hookCalls.has(fnNode)) {
|
|
357
420
|
hookCalls.set(fnNode, []);
|
|
358
421
|
}
|
|
422
|
+
|
|
359
423
|
var hookCallsForFn = hookCalls.get(fnNode);
|
|
360
424
|
var key = '';
|
|
425
|
+
|
|
361
426
|
if (path.parent.type === 'VariableDeclarator') {
|
|
362
427
|
// TODO: if there is no LHS, consider some other heuristic.
|
|
363
428
|
key = path.parentPath.get('id').getSource();
|
|
364
|
-
}
|
|
429
|
+
} // Some built-in Hooks reset on edits to arguments.
|
|
430
|
+
|
|
365
431
|
|
|
366
|
-
// Some built-in Hooks reset on edits to arguments.
|
|
367
432
|
var args = path.get('arguments');
|
|
433
|
+
|
|
368
434
|
if (name === 'useState' && args.length > 0) {
|
|
369
435
|
// useState second argument is initial state.
|
|
370
436
|
key += '(' + args[0].getSource() + ')';
|
|
@@ -380,35 +446,35 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
380
446
|
});
|
|
381
447
|
}
|
|
382
448
|
};
|
|
383
|
-
|
|
384
449
|
return {
|
|
385
450
|
visitor: {
|
|
386
451
|
ExportDefaultDeclaration: function (path) {
|
|
387
452
|
var node = path.node;
|
|
388
453
|
var decl = node.declaration;
|
|
389
454
|
var declPath = path.get('declaration');
|
|
455
|
+
|
|
390
456
|
if (decl.type !== 'CallExpression') {
|
|
391
457
|
// For now, we only support possible HOC calls here.
|
|
392
458
|
// Named function declarations are handled in FunctionDeclaration.
|
|
393
459
|
// Anonymous direct exports like export default function() {}
|
|
394
460
|
// are currently ignored.
|
|
395
461
|
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Make sure we're not mutating the same tree twice.
|
|
462
|
+
} // Make sure we're not mutating the same tree twice.
|
|
399
463
|
// This can happen if another Babel plugin replaces parents.
|
|
464
|
+
|
|
465
|
+
|
|
400
466
|
if (seenForRegistration.has(node)) {
|
|
401
467
|
return;
|
|
402
468
|
}
|
|
403
|
-
seenForRegistration.add(node);
|
|
404
|
-
// Don't mutate the tree above this point.
|
|
405
469
|
|
|
470
|
+
seenForRegistration.add(node); // Don't mutate the tree above this point.
|
|
406
471
|
// This code path handles nested cases like:
|
|
407
472
|
// export default memo(() => {})
|
|
408
473
|
// In those cases it is more plausible people will omit names
|
|
409
474
|
// so they're worth handling despite possible false positives.
|
|
410
475
|
// More importantly, it handles the named case:
|
|
411
476
|
// export default memo(function Named() {})
|
|
477
|
+
|
|
412
478
|
var inferredName = '%default%';
|
|
413
479
|
var programPath = path.parentPath;
|
|
414
480
|
findInnerComponents(inferredName, declPath, function (persistentID, targetExpr, targetPath) {
|
|
@@ -419,52 +485,60 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
419
485
|
// Instead we assume it's registered at definition.
|
|
420
486
|
return;
|
|
421
487
|
}
|
|
488
|
+
|
|
422
489
|
var handle = createRegistration(programPath, persistentID);
|
|
423
490
|
targetPath.replaceWith(t.assignmentExpression('=', handle, targetExpr));
|
|
424
491
|
});
|
|
425
492
|
},
|
|
426
|
-
|
|
427
493
|
FunctionDeclaration: {
|
|
428
494
|
enter: function (path) {
|
|
429
495
|
var node = path.node;
|
|
430
|
-
var programPath
|
|
431
|
-
var insertAfterPath
|
|
496
|
+
var programPath;
|
|
497
|
+
var insertAfterPath;
|
|
498
|
+
|
|
432
499
|
switch (path.parent.type) {
|
|
433
500
|
case 'Program':
|
|
434
501
|
insertAfterPath = path;
|
|
435
502
|
programPath = path.parentPath;
|
|
436
503
|
break;
|
|
504
|
+
|
|
437
505
|
case 'ExportNamedDeclaration':
|
|
438
506
|
insertAfterPath = path.parentPath;
|
|
439
507
|
programPath = insertAfterPath.parentPath;
|
|
440
508
|
break;
|
|
509
|
+
|
|
441
510
|
case 'ExportDefaultDeclaration':
|
|
442
511
|
insertAfterPath = path.parentPath;
|
|
443
512
|
programPath = insertAfterPath.parentPath;
|
|
444
513
|
break;
|
|
514
|
+
|
|
445
515
|
default:
|
|
446
516
|
return;
|
|
447
517
|
}
|
|
518
|
+
|
|
448
519
|
var id = node.id;
|
|
520
|
+
|
|
449
521
|
if (id === null) {
|
|
450
522
|
// We don't currently handle anonymous default exports.
|
|
451
523
|
return;
|
|
452
524
|
}
|
|
525
|
+
|
|
453
526
|
var inferredName = id.name;
|
|
527
|
+
|
|
454
528
|
if (!isComponentishName(inferredName)) {
|
|
455
529
|
return;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Make sure we're not mutating the same tree twice.
|
|
530
|
+
} // Make sure we're not mutating the same tree twice.
|
|
459
531
|
// This can happen if another Babel plugin replaces parents.
|
|
532
|
+
|
|
533
|
+
|
|
460
534
|
if (seenForRegistration.has(node)) {
|
|
461
535
|
return;
|
|
462
536
|
}
|
|
463
|
-
seenForRegistration.add(node);
|
|
464
|
-
// Don't mutate the tree above this point.
|
|
465
537
|
|
|
538
|
+
seenForRegistration.add(node); // Don't mutate the tree above this point.
|
|
466
539
|
// export function Named() {}
|
|
467
540
|
// function Named() {}
|
|
541
|
+
|
|
468
542
|
findInnerComponents(inferredName, path, function (persistentID, targetExpr) {
|
|
469
543
|
var handle = createRegistration(programPath, persistentID);
|
|
470
544
|
insertAfterPath.insertAfter(t.expressionStatement(t.assignmentExpression('=', handle, targetExpr)));
|
|
@@ -473,38 +547,38 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
473
547
|
exit: function (path) {
|
|
474
548
|
var node = path.node;
|
|
475
549
|
var id = node.id;
|
|
550
|
+
|
|
476
551
|
if (id === null) {
|
|
477
552
|
return;
|
|
478
553
|
}
|
|
554
|
+
|
|
479
555
|
var signature = getHookCallsSignature(node);
|
|
556
|
+
|
|
480
557
|
if (signature === null) {
|
|
481
558
|
return;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Make sure we're not mutating the same tree twice.
|
|
559
|
+
} // Make sure we're not mutating the same tree twice.
|
|
485
560
|
// This can happen if another Babel plugin replaces parents.
|
|
561
|
+
|
|
562
|
+
|
|
486
563
|
if (seenForSignature.has(node)) {
|
|
487
564
|
return;
|
|
488
565
|
}
|
|
489
|
-
|
|
490
|
-
// Don't mutate the tree above this point.
|
|
566
|
+
|
|
567
|
+
seenForSignature.add(node); // Don't mutate the tree above this point.
|
|
491
568
|
|
|
492
569
|
var sigCallID = path.scope.generateUidIdentifier('_s');
|
|
493
570
|
path.scope.parent.push({
|
|
494
571
|
id: sigCallID,
|
|
495
572
|
init: t.callExpression(t.identifier('$RefreshSig$'), [])
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
// The signature call is split in two parts. One part is called inside the function.
|
|
573
|
+
}); // The signature call is split in two parts. One part is called inside the function.
|
|
499
574
|
// This is used to signal when first render happens.
|
|
500
|
-
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, [])));
|
|
501
575
|
|
|
502
|
-
// The second call is around the function itself.
|
|
576
|
+
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, []))); // The second call is around the function itself.
|
|
503
577
|
// This is used to associate a type with a signature.
|
|
504
|
-
|
|
505
578
|
// Unlike with $RefreshReg$, this needs to work for nested
|
|
506
579
|
// declarations too. So we need to search for a path where
|
|
507
580
|
// we can insert a statement rather than hardcoding it.
|
|
581
|
+
|
|
508
582
|
var insertAfterPath = null;
|
|
509
583
|
path.find(function (p) {
|
|
510
584
|
if (p.parentPath.isBlock()) {
|
|
@@ -512,6 +586,7 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
512
586
|
return true;
|
|
513
587
|
}
|
|
514
588
|
});
|
|
589
|
+
|
|
515
590
|
if (insertAfterPath === null) {
|
|
516
591
|
return;
|
|
517
592
|
}
|
|
@@ -523,29 +598,31 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
523
598
|
exit: function (path) {
|
|
524
599
|
var node = path.node;
|
|
525
600
|
var signature = getHookCallsSignature(node);
|
|
601
|
+
|
|
526
602
|
if (signature === null) {
|
|
527
603
|
return;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// Make sure we're not mutating the same tree twice.
|
|
604
|
+
} // Make sure we're not mutating the same tree twice.
|
|
531
605
|
// This can happen if another Babel plugin replaces parents.
|
|
606
|
+
|
|
607
|
+
|
|
532
608
|
if (seenForSignature.has(node)) {
|
|
533
609
|
return;
|
|
534
610
|
}
|
|
535
|
-
|
|
536
|
-
// Don't mutate the tree above this point.
|
|
611
|
+
|
|
612
|
+
seenForSignature.add(node); // Don't mutate the tree above this point.
|
|
537
613
|
|
|
538
614
|
var sigCallID = path.scope.generateUidIdentifier('_s');
|
|
539
615
|
path.scope.parent.push({
|
|
540
616
|
id: sigCallID,
|
|
541
617
|
init: t.callExpression(t.identifier('$RefreshSig$'), [])
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
// The signature call is split in two parts. One part is called inside the function.
|
|
618
|
+
}); // The signature call is split in two parts. One part is called inside the function.
|
|
545
619
|
// This is used to signal when first render happens.
|
|
546
|
-
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, [])));
|
|
547
620
|
|
|
548
|
-
|
|
621
|
+
if (path.node.body.type !== 'BlockStatement') {
|
|
622
|
+
path.node.body = t.blockStatement([t.returnStatement(path.node.body)]);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
path.get('body').unshiftContainer('body', t.expressionStatement(t.callExpression(sigCallID, []))); // The second call is around the function itself.
|
|
549
626
|
// This is used to associate a type with a signature.
|
|
550
627
|
|
|
551
628
|
if (path.parent.type === 'VariableDeclarator') {
|
|
@@ -556,56 +633,62 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
556
633
|
return true;
|
|
557
634
|
}
|
|
558
635
|
});
|
|
636
|
+
|
|
559
637
|
if (insertAfterPath === null) {
|
|
560
638
|
return;
|
|
561
|
-
}
|
|
562
|
-
// Special case when a function would get an inferred name:
|
|
639
|
+
} // Special case when a function would get an inferred name:
|
|
563
640
|
// let Foo = () => {}
|
|
564
641
|
// let Foo = function() {}
|
|
565
642
|
// We'll add signature it on next line so that
|
|
566
643
|
// we don't mess up the inferred 'Foo' function name.
|
|
567
|
-
|
|
568
|
-
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
insertAfterPath.insertAfter(t.expressionStatement(t.callExpression(sigCallID, createArgumentsForSignature(path.parent.id, signature, insertAfterPath.scope)))); // Result: let Foo = () => {}; __signature(Foo, ...);
|
|
569
647
|
} else {
|
|
570
648
|
// let Foo = hoc(() => {})
|
|
571
|
-
path.replaceWith(t.callExpression(sigCallID, createArgumentsForSignature(node, signature, path.scope)));
|
|
572
|
-
// Result: let Foo = hoc(__signature(() => {}, ...))
|
|
649
|
+
path.replaceWith(t.callExpression(sigCallID, createArgumentsForSignature(node, signature, path.scope))); // Result: let Foo = hoc(__signature(() => {}, ...))
|
|
573
650
|
}
|
|
574
651
|
}
|
|
575
652
|
},
|
|
576
653
|
VariableDeclaration: function (path) {
|
|
577
654
|
var node = path.node;
|
|
578
|
-
var programPath
|
|
579
|
-
var insertAfterPath
|
|
655
|
+
var programPath;
|
|
656
|
+
var insertAfterPath;
|
|
657
|
+
|
|
580
658
|
switch (path.parent.type) {
|
|
581
659
|
case 'Program':
|
|
582
660
|
insertAfterPath = path;
|
|
583
661
|
programPath = path.parentPath;
|
|
584
662
|
break;
|
|
663
|
+
|
|
585
664
|
case 'ExportNamedDeclaration':
|
|
586
665
|
insertAfterPath = path.parentPath;
|
|
587
666
|
programPath = insertAfterPath.parentPath;
|
|
588
667
|
break;
|
|
668
|
+
|
|
589
669
|
case 'ExportDefaultDeclaration':
|
|
590
670
|
insertAfterPath = path.parentPath;
|
|
591
671
|
programPath = insertAfterPath.parentPath;
|
|
592
672
|
break;
|
|
673
|
+
|
|
593
674
|
default:
|
|
594
675
|
return;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Make sure we're not mutating the same tree twice.
|
|
676
|
+
} // Make sure we're not mutating the same tree twice.
|
|
598
677
|
// This can happen if another Babel plugin replaces parents.
|
|
678
|
+
|
|
679
|
+
|
|
599
680
|
if (seenForRegistration.has(node)) {
|
|
600
681
|
return;
|
|
601
682
|
}
|
|
602
|
-
|
|
603
|
-
// Don't mutate the tree above this point.
|
|
683
|
+
|
|
684
|
+
seenForRegistration.add(node); // Don't mutate the tree above this point.
|
|
604
685
|
|
|
605
686
|
var declPaths = path.get('declarations');
|
|
687
|
+
|
|
606
688
|
if (declPaths.length !== 1) {
|
|
607
689
|
return;
|
|
608
690
|
}
|
|
691
|
+
|
|
609
692
|
var declPath = declPaths[0];
|
|
610
693
|
var inferredName = declPath.node.id.name;
|
|
611
694
|
findInnerComponents(inferredName, declPath, function (persistentID, targetExpr, targetPath) {
|
|
@@ -616,23 +699,22 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
616
699
|
// Instead we assume it's registered at definition.
|
|
617
700
|
return;
|
|
618
701
|
}
|
|
702
|
+
|
|
619
703
|
var handle = createRegistration(programPath, persistentID);
|
|
704
|
+
|
|
620
705
|
if ((targetExpr.type === 'ArrowFunctionExpression' || targetExpr.type === 'FunctionExpression') && targetPath.parent.type === 'VariableDeclarator') {
|
|
621
706
|
// Special case when a function would get an inferred name:
|
|
622
707
|
// let Foo = () => {}
|
|
623
708
|
// let Foo = function() {}
|
|
624
709
|
// We'll register it on next line so that
|
|
625
710
|
// we don't mess up the inferred 'Foo' function name.
|
|
626
|
-
insertAfterPath.insertAfter(t.expressionStatement(t.assignmentExpression('=', handle, declPath.node.id)));
|
|
627
|
-
// Result: let Foo = () => {}; _c1 = Foo;
|
|
711
|
+
insertAfterPath.insertAfter(t.expressionStatement(t.assignmentExpression('=', handle, declPath.node.id))); // Result: let Foo = () => {}; _c1 = Foo;
|
|
628
712
|
} else {
|
|
629
713
|
// let Foo = hoc(() => {})
|
|
630
|
-
targetPath.replaceWith(t.assignmentExpression('=', handle, targetExpr));
|
|
631
|
-
// Result: let Foo = _c1 = hoc(() => {})
|
|
714
|
+
targetPath.replaceWith(t.assignmentExpression('=', handle, targetExpr)); // Result: let Foo = _c1 = hoc(() => {})
|
|
632
715
|
}
|
|
633
716
|
});
|
|
634
717
|
},
|
|
635
|
-
|
|
636
718
|
Program: {
|
|
637
719
|
enter: function (path) {
|
|
638
720
|
// This is a separate early visitor because we need to collect Hook calls
|
|
@@ -643,18 +725,20 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
643
725
|
},
|
|
644
726
|
exit: function (path) {
|
|
645
727
|
var registrations = registrationsByProgramPath.get(path);
|
|
728
|
+
|
|
646
729
|
if (registrations === undefined) {
|
|
647
730
|
return;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Make sure we're not mutating the same tree twice.
|
|
731
|
+
} // Make sure we're not mutating the same tree twice.
|
|
651
732
|
// This can happen if another Babel plugin replaces parents.
|
|
733
|
+
|
|
734
|
+
|
|
652
735
|
var node = path.node;
|
|
736
|
+
|
|
653
737
|
if (seenForOutro.has(node)) {
|
|
654
738
|
return;
|
|
655
739
|
}
|
|
656
|
-
|
|
657
|
-
// Don't mutate the tree above this point.
|
|
740
|
+
|
|
741
|
+
seenForOutro.add(node); // Don't mutate the tree above this point.
|
|
658
742
|
|
|
659
743
|
registrationsByProgramPath.delete(path);
|
|
660
744
|
var declarators = [];
|
|
@@ -662,7 +746,6 @@ var ReactFreshBabelPlugin = function (babel) {
|
|
|
662
746
|
registrations.forEach(function (_ref) {
|
|
663
747
|
var handle = _ref.handle,
|
|
664
748
|
persistentID = _ref.persistentID;
|
|
665
|
-
|
|
666
749
|
path.pushContainer('body', t.expressionStatement(t.callExpression(t.identifier('$RefreshReg$'), [handle, t.stringLiteral(persistentID)])));
|
|
667
750
|
declarators.push(t.variableDeclarator(handle));
|
|
668
751
|
});
|
|
@@ -679,6 +762,8 @@ var ReactFreshBabelPlugin$1 = Object.freeze({
|
|
|
679
762
|
var ReactFreshBabelPlugin$2 = ( ReactFreshBabelPlugin$1 && ReactFreshBabelPlugin ) || ReactFreshBabelPlugin$1;
|
|
680
763
|
|
|
681
764
|
// This is hacky but makes it work with both Rollup and Jest.
|
|
765
|
+
|
|
766
|
+
|
|
682
767
|
var babel = ReactFreshBabelPlugin$2.default || ReactFreshBabelPlugin$2;
|
|
683
768
|
|
|
684
769
|
module.exports = babel;
|