@samitouri / QOS-React-2 / commits / b1eaf88c61

[babel] Ensure only adding import specifier to non-namespace

Missed this in the previous PR Test plan: P706162189 (some babel errors) before this PR, P706255523 has no errors

Lauren Tan committed Apr 26, 2023 at 15:16 UTC b1eaf88c61dfaf3fedf4f58e45fad4cf519e8049
3 files changed +133 -9
compiler/forget/src/Babel/BabelPlugin.ts
+18 -9
@@ -233,14 +233,7 @@ export default function ReactForgetBabelPlugin(
233 }
234 },
235 ImportDeclaration(importDeclPath) {
236 - // Matches `import { /* ... */ } from 'react';`
237 - // but not `import * as React from 'react';`
238 - if (
239 - importDeclPath.get("source").node.value === "react" &&
240 - importDeclPath
241 - .get("specifiers")
242 - .every((specifier) => specifier.isImportSpecifier())
243 - ) {
236 + if (isNonNamespacedImportOfReact(importDeclPath)) {
237 hasExistingReactImport = true;
238 }
239 },
@@ -253,7 +246,7 @@ export default function ReactForgetBabelPlugin(
246 let didUpdateImport = false;
247 path.traverse({
248 ImportDeclaration(importDeclPath) {
256 - if (importDeclPath.get("source").node.value === "react") {
249 + if (isNonNamespacedImportOfReact(importDeclPath)) {
250 importDeclPath.pushContainer(
251 "specifiers",
252 t.importSpecifier(
@@ -262,6 +255,7 @@ export default function ReactForgetBabelPlugin(
255 )
256 );
257 didUpdateImport = true;
258 + path.stop();
259 }
260 },
261 });
@@ -440,3 +434,18 @@ function buildImportForGatingModule(
434 function buildSpecifierIdent(gating: GatingOptions): t.Identifier {
435 return t.identifier(gating.importSpecifierName);
436 }
437 +
438 +/**
439 + * Matches `import { ... } from 'react';`
440 + * but not `import * as React from 'react';`
441 + */
442 +function isNonNamespacedImportOfReact(
443 + importDeclPath: BabelCore.NodePath<t.ImportDeclaration>
444 +): boolean {
445 + return (
446 + importDeclPath.get("source").node.value === "react" &&
447 + importDeclPath
448 + .get("specifiers")
449 + .every((specifier) => specifier.isImportSpecifier())
450 + );
451 +}
compiler/forget/src/__tests__/fixtures/compiler/babel-existing-react-kitchensink-import.expect.md new
+99
@@ -0,0 +1,99 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +import * as React from "react";
6 +import { useState } from "react";
7 +
8 +function Component(props) {
9 + const [x] = useState(0);
10 + const expensiveNumber = React.useMemo(() => calculateExpensiveNumber(x), [x]);
11 +
12 + return <div>{expensiveNumber}</div>;
13 +}
14 +
15 +function Component2(props) {
16 + const [x] = useState(0);
17 + const expensiveNumber = React.useMemo(() => calculateExpensiveNumber(x), [x]);
18 +
19 + return <div>{expensiveNumber}</div>;
20 +}
21 +
22 +```
23 +
24 +## Code
25 +
26 +```javascript
27 +import * as React from "react";
28 +import { useState, unstable_useMemoCache as useMemoCache } from "react";
29 +
30 +function Component(props) {
31 + const $ = useMemoCache(6);
32 + const [x] = useState(0);
33 + const c_0 = $[0] !== x;
34 + let t1;
35 + if (c_0) {
36 + const c_2 = $[2] !== x;
37 + let t0;
38 + if (c_2) {
39 + t0 = () => calculateExpensiveNumber(x);
40 + $[2] = x;
41 + $[3] = t0;
42 + } else {
43 + t0 = $[3];
44 + }
45 + t1 = React.useMemo(t0, [x]);
46 + $[0] = x;
47 + $[1] = t1;
48 + } else {
49 + t1 = $[1];
50 + }
51 + const expensiveNumber = t1;
52 + const c_4 = $[4] !== expensiveNumber;
53 + let t2;
54 + if (c_4) {
55 + t2 = <div>{expensiveNumber}</div>;
56 + $[4] = expensiveNumber;
57 + $[5] = t2;
58 + } else {
59 + t2 = $[5];
60 + }
61 + return t2;
62 +}
63 +
64 +function Component2(props) {
65 + const $ = useMemoCache(6);
66 + const [x] = useState(0);
67 + const c_0 = $[0] !== x;
68 + let t1;
69 + if (c_0) {
70 + const c_2 = $[2] !== x;
71 + let t0;
72 + if (c_2) {
73 + t0 = () => calculateExpensiveNumber(x);
74 + $[2] = x;
75 + $[3] = t0;
76 + } else {
77 + t0 = $[3];
78 + }
79 + t1 = React.useMemo(t0, [x]);
80 + $[0] = x;
81 + $[1] = t1;
82 + } else {
83 + t1 = $[1];
84 + }
85 + const expensiveNumber = t1;
86 + const c_4 = $[4] !== expensiveNumber;
87 + let t2;
88 + if (c_4) {
89 + t2 = <div>{expensiveNumber}</div>;
90 + $[4] = expensiveNumber;
91 + $[5] = t2;
92 + } else {
93 + t2 = $[5];
94 + }
95 + return t2;
96 +}
97 +
98 +```
99 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/babel-existing-react-kitchensink-import.js new
+16
@@ -0,0 +1,16 @@
1 +import * as React from "react";
2 +import { useState } from "react";
3 +
4 +function Component(props) {
5 + const [x] = useState(0);
6 + const expensiveNumber = React.useMemo(() => calculateExpensiveNumber(x), [x]);
7 +
8 + return <div>{expensiveNumber}</div>;
9 +}
10 +
11 +function Component2(props) {
12 + const [x] = useState(0);
13 + const expensiveNumber = React.useMemo(() => calculateExpensiveNumber(x), [x]);
14 +
15 + return <div>{expensiveNumber}</div>;
16 +}