@samitouri / QOS-React-1 / commits / 34c89458f2

[entrypoint] Allow ref params to component functions

Mofei Zhang committed Jan 19, 2024 at 14:59 UTC 34c89458f2db439c24e7f5e6c762ca75066b4787
3 files changed +77 -7
compiler/packages/babel-plugin-react-forget/src/Entrypoint/Program.ts
+23 -7
@@ -481,6 +481,28 @@ function isMemoCallback(path: NodePath<t.Expression>): boolean {
481 );
482 }
483
484 +function isValidComponentParams(
485 + params: Array<NodePath<t.Identifier | t.Pattern | t.RestElement>>
486 +): boolean {
487 + if (params.length === 0) {
488 + return true;
489 + } else if (params.length === 1) {
490 + return !params[0].isRestElement();
491 + } else if (params.length === 2) {
492 + // check if second param might be a ref
493 + if (params[1].isIdentifier()) {
494 + const { name } = params[1].node;
495 + return name.includes("ref") || name.includes("Ref");
496 + }
497 + /**
498 + * Otherwise, avoid helper functions that take more than one argument.
499 + * Helpers are _usually_ named with lowercase, but some code may
500 + * violate this rule
501 + */
502 + }
503 + return false;
504 +}
505 +
506 /*
507 * Adapted from the ESLint rule at
508 * https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js#L90-L103
@@ -495,13 +517,7 @@ function isComponentOrHookLike(
517 if (functionName !== null && isComponentName(functionName)) {
518 return (
519 // As an added check we also look for hook invocations or JSX
498 - callsHooksOrCreatesJsx(node) &&
499 - /*
500 - * and avoid helper functions that take more than one argument
501 - * helpers are _usually_ named with lowercase, but some code may
502 - * violate this rule
503 - */
504 - node.get("params").length <= 1
520 + callsHooksOrCreatesJsx(node) && isValidComponentParams(node.get("params"))
521 );
522 } else if (functionName !== null && isHook(functionName)) {
523 // Hooks have hook invocations or JSX, but can take any # of arguments
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/infer-functions-component-with-ref-arg.expect.md new
+44
@@ -0,0 +1,44 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +// @compilationMode(infer)
6 +
7 +function Foo({}, ref) {
8 + return <div ref={ref} />;
9 +}
10 +
11 +export const FIXTURE_ENTRYPOINT = {
12 + fn: Foo,
13 + params: [{}],
14 +};
15 +
16 +```
17 +
18 +## Code
19 +
20 +```javascript
21 +import { unstable_useMemoCache as useMemoCache } from "react"; // @compilationMode(infer)
22 +
23 +function Foo(t6, ref) {
24 + const $ = useMemoCache(2);
25 + let t0;
26 + if ($[0] !== ref) {
27 + t0 = <div ref={ref} />;
28 + $[0] = ref;
29 + $[1] = t0;
30 + } else {
31 + t0 = $[1];
32 + }
33 + return t0;
34 +}
35 +
36 +export const FIXTURE_ENTRYPOINT = {
37 + fn: Foo,
38 + params: [{}],
39 +};
40 +
41 +```
42 +
43 +### Eval output
44 +(kind: ok) <div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/infer-functions-component-with-ref-arg.js new
+10
@@ -0,0 +1,10 @@
1 +// @compilationMode(infer)
2 +
3 +function Foo({}, ref) {
4 + return <div ref={ref} />;
5 +}
6 +
7 +export const FIXTURE_ENTRYPOINT = {
8 + fn: Foo,
9 + params: [{}],
10 +};