(path)
| 570 | }); |
| 571 | }, |
| 572 | exit(path) { |
| 573 | const node = path.node; |
| 574 | const id = node.id; |
| 575 | if (id === null) { |
| 576 | return; |
| 577 | } |
| 578 | const signature = getHookCallsSignature(node); |
| 579 | if (signature === null) { |
| 580 | return; |
| 581 | } |
| 582 | |
| 583 | // Make sure we're not mutating the same tree twice. |
| 584 | // This can happen if another Babel plugin replaces parents. |
| 585 | if (seenForSignature.has(node)) { |
| 586 | return; |
| 587 | } |
| 588 | seenForSignature.add(node); |
| 589 | // Don't mutate the tree above this point. |
| 590 | |
| 591 | const sigCallID = path.scope.generateUidIdentifier('_s'); |
| 592 | path.scope.parent.push({ |
| 593 | id: sigCallID, |
| 594 | init: t.callExpression(refreshSig, []), |
| 595 | }); |
| 596 | |
| 597 | // The signature call is split in two parts. One part is called inside the function. |
| 598 | // This is used to signal when first render happens. |
| 599 | path |
| 600 | .get('body') |
| 601 | .unshiftContainer( |
| 602 | 'body', |
| 603 | t.expressionStatement(t.callExpression(sigCallID, [])), |
| 604 | ); |
| 605 | |
| 606 | // The second call is around the function itself. |
| 607 | // This is used to associate a type with a signature. |
| 608 | |
| 609 | // Unlike with $RefreshReg$, this needs to work for nested |
| 610 | // declarations too. So we need to search for a path where |
| 611 | // we can insert a statement rather than hard coding it. |
| 612 | let insertAfterPath = null; |
| 613 | path.find(p => { |
| 614 | if (p.parentPath.isBlock()) { |
| 615 | insertAfterPath = p; |
| 616 | return true; |
| 617 | } |
| 618 | }); |
| 619 | if (insertAfterPath === null) { |
| 620 | return; |
| 621 | } |
| 622 | |
| 623 | insertAfterPath.insertAfter( |
| 624 | t.expressionStatement( |
| 625 | t.callExpression( |
| 626 | sigCallID, |
| 627 | createArgumentsForSignature( |
| 628 | id, |
| 629 | signature, |
no test coverage detected