mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[be][tests] Run todo fixtures
--- Snap should compile all fixtures to record changes in results, even `todo` prefixed ones. Previously, they were skipped as we noted the correlation of `// @skip` pragmas and file naming. Now, no fixture should be skipped as our compiler pipeline should be able to handle every kind of error.
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid -- this is a regression test.
|
||||
jest.useFakeTimers();
|
||||
beforeEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid -- this is a regression test.
|
||||
jest.useFakeTimers();
|
||||
beforeEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can be used in anonymous function arguments to
|
||||
// React.memo.
|
||||
const MemoizedFunction = React.memo((props) => {
|
||||
useHook();
|
||||
return <button {...props} />;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can be used in anonymous function arguments to
|
||||
// React.memo.
|
||||
const MemoizedFunction = React.memo((props) => {
|
||||
const $ = useMemoCache(2);
|
||||
useHook();
|
||||
let t0;
|
||||
if ($[0] !== props) {
|
||||
t0 = <button {...props} />;
|
||||
$[0] = props;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
|
||||
useEffect(() => {
|
||||
useHookInsideCallback();
|
||||
});
|
||||
return <button {...props} ref={ref} />;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
const ComponentWithHookInsideCallback = React.forwardRef((props, ref) => {
|
||||
const $ = useMemoCache(4);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
useHookInsideCallback();
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useEffect(t0);
|
||||
let t1;
|
||||
if ($[1] !== props || $[2] !== ref) {
|
||||
t1 = <button {...props} ref={ref} />;
|
||||
$[1] = props;
|
||||
$[2] = ref;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
return t1;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because the neither the conditions before or after the hook affect the hook call
|
||||
// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
|
||||
const useSomeHook = () => {};
|
||||
|
||||
const SomeName = () => {
|
||||
const filler = FILLER ?? FILLER ?? FILLER;
|
||||
const filler2 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler3 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler4 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler5 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler6 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler7 = FILLER ?? FILLER ?? FILLER;
|
||||
const filler8 = FILLER ?? FILLER ?? FILLER;
|
||||
|
||||
useSomeHook();
|
||||
|
||||
if (anyConditionCanEvenBeFalse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because the neither the conditions before or after the hook affect the hook call
|
||||
// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
|
||||
const useSomeHook = () => {};
|
||||
|
||||
const SomeName = () => {
|
||||
const $ = useMemoCache(1);
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
(FILLER ?? FILLER, FILLER) ?? FILLER;
|
||||
|
||||
useSomeHook();
|
||||
if (anyConditionCanEvenBeFalse) {
|
||||
return null;
|
||||
}
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = (
|
||||
<React.Fragment>
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
{FILLER ? FILLER : FILLER}
|
||||
</React.Fragment>
|
||||
);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
const ComponentWithHookInsideCallback = React.memo((props) => {
|
||||
useEffect(() => {
|
||||
useHookInsideCallback();
|
||||
});
|
||||
return <button {...props} />;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
const ComponentWithHookInsideCallback = React.memo((props) => {
|
||||
const $ = useMemoCache(3);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
useHookInsideCallback();
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useEffect(t0);
|
||||
let t1;
|
||||
if ($[1] !== props) {
|
||||
t1 = <button {...props} />;
|
||||
$[1] = props;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can call hooks.
|
||||
function useHook() {
|
||||
useState();
|
||||
}
|
||||
const whatever = function useHook() {
|
||||
useState();
|
||||
};
|
||||
const useHook1 = () => {
|
||||
useState();
|
||||
};
|
||||
let useHook2 = () => useState();
|
||||
useHook2 = () => {
|
||||
useState();
|
||||
};
|
||||
({
|
||||
useHook: () => {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
({
|
||||
useHook() {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
const {
|
||||
useHook3 = () => {
|
||||
useState();
|
||||
},
|
||||
} = {};
|
||||
({
|
||||
useHook = () => {
|
||||
useState();
|
||||
},
|
||||
} = {});
|
||||
Namespace.useHook = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can call hooks.
|
||||
function useHook() {
|
||||
useState();
|
||||
}
|
||||
|
||||
const whatever = function useHook() {
|
||||
useState();
|
||||
};
|
||||
|
||||
const useHook1 = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
let useHook2 = () => {
|
||||
return useState();
|
||||
};
|
||||
useHook2 = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
({
|
||||
useHook: () => {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
({
|
||||
useHook() {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
const {
|
||||
useHook3 = () => {
|
||||
useState();
|
||||
},
|
||||
} = {};
|
||||
({
|
||||
useHook = () => {
|
||||
useState();
|
||||
},
|
||||
} = {});
|
||||
Namespace.useHook = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can be used in anonymous arrow-function arguments
|
||||
// to forwardRef.
|
||||
const FancyButton = React.forwardRef((props, ref) => {
|
||||
useHook();
|
||||
return <button {...props} ref={ref} />;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because hooks can be used in anonymous arrow-function arguments
|
||||
// to forwardRef.
|
||||
const FancyButton = React.forwardRef((props, ref) => {
|
||||
const $ = useMemoCache(3);
|
||||
useHook();
|
||||
let t0;
|
||||
if ($[0] !== props || $[1] !== ref) {
|
||||
t0 = <button {...props} ref={ref} />;
|
||||
$[0] = props;
|
||||
$[1] = ref;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
return t0;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Currently invalid.
|
||||
// These are variations capturing the current heuristic--
|
||||
// we only allow hooks in PascalCase or useFoo functions.
|
||||
// We *could* make some of these valid. But before doing it,
|
||||
// consider specific cases documented above that contain reasoning.
|
||||
function a() {
|
||||
useState();
|
||||
}
|
||||
const whatever = function b() {
|
||||
useState();
|
||||
};
|
||||
const c = () => {
|
||||
useState();
|
||||
};
|
||||
let d = () => useState();
|
||||
e = () => {
|
||||
useState();
|
||||
};
|
||||
({
|
||||
f: () => {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
({
|
||||
g() {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
const {
|
||||
j = () => {
|
||||
useState();
|
||||
},
|
||||
} = {};
|
||||
({
|
||||
k = () => {
|
||||
useState();
|
||||
},
|
||||
} = {});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Currently invalid.
|
||||
// These are variations capturing the current heuristic--
|
||||
// we only allow hooks in PascalCase or useFoo functions.
|
||||
// We *could* make some of these valid. But before doing it,
|
||||
// consider specific cases documented above that contain reasoning.
|
||||
function a() {
|
||||
useState();
|
||||
}
|
||||
|
||||
const whatever = function b() {
|
||||
useState();
|
||||
};
|
||||
|
||||
const c = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
let d = () => {
|
||||
return useState();
|
||||
};
|
||||
e = () => {
|
||||
useState();
|
||||
};
|
||||
|
||||
({
|
||||
f: () => {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
({
|
||||
g() {
|
||||
useState();
|
||||
},
|
||||
});
|
||||
const {
|
||||
j = () => {
|
||||
useState();
|
||||
},
|
||||
} = {};
|
||||
({
|
||||
k = () => {
|
||||
useState();
|
||||
},
|
||||
} = {});
|
||||
|
||||
```
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
const FancyButton = forwardRef(function (props, ref) {
|
||||
if (props.fancy) {
|
||||
useCustomHook();
|
||||
}
|
||||
return <button ref={ref}>{props.children}</button>;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
|
||||
```
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
const MemoizedButton = memo(function (props) {
|
||||
if (props.fancy) {
|
||||
useCustomHook();
|
||||
}
|
||||
return <button>{props.children}</button>;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
|
||||
```
|
||||
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function ComponentWithConditionalHook() {
|
||||
if (cond) {
|
||||
Namespace.useConditionalHook();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
|
||||
```
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
const FancyButton = React.forwardRef((props, ref) => {
|
||||
if (props.fancy) {
|
||||
useCustomHook();
|
||||
}
|
||||
return <button ref={ref}>{props.children}</button>;
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
|
||||
```
|
||||
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because the neither the condition nor the loop affect the hook call.
|
||||
function App(props) {
|
||||
const someObject = { propA: true };
|
||||
for (const propName in someObject) {
|
||||
if (propName === true) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
const [myState, setMyState] = useState(null);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (12:12)
|
||||
```
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Valid because the loop doesn't change the order of hooks calls.
|
||||
function RegressionTest() {
|
||||
const res = [];
|
||||
const additionalCond = true;
|
||||
for (let i = 0; i !== 10 && additionalCond; ++i) {
|
||||
res.push(i);
|
||||
}
|
||||
React.useLayoutEffect(() => {});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (11:11)
|
||||
```
|
||||
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// This is valid because "use"-prefixed functions called in
|
||||
// unnamed function arguments are not assumed to be hooks.
|
||||
React.unknownFunction((foo, bar) => {
|
||||
if (foo) {
|
||||
useNotAHook(bar);
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (8:8)
|
||||
```
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Unsupported input
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function useHook() {
|
||||
try {
|
||||
f();
|
||||
useState();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] InvalidReact: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning) (9:9)
|
||||
```
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function createHook() {
|
||||
return function useHookWithConditionalHook() {
|
||||
if (cond) {
|
||||
useConditionalHook();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function createHook() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = function useHookWithConditionalHook() {
|
||||
if (cond) {
|
||||
useConditionalHook();
|
||||
}
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function createComponent() {
|
||||
return function ComponentWithHookInsideCallback() {
|
||||
useEffect(() => {
|
||||
useHookInsideCallback();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function createComponent() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = function ComponentWithHookInsideCallback() {
|
||||
useEffect(() => {
|
||||
useHookInsideCallback();
|
||||
});
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous.
|
||||
// Normally, this would crash, but not if you use inline requires.
|
||||
// This *must* be invalid.
|
||||
// It's expected to have some false positives, but arguably
|
||||
// they are confusing anyway due to the use*() convention
|
||||
// already being associated with Hooks.
|
||||
useState();
|
||||
if (foo) {
|
||||
const foo = React.useCallback(() => {});
|
||||
}
|
||||
useCustomHook();
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous.
|
||||
// Normally, this would crash, but not if you use inline requires.
|
||||
// This *must* be invalid.
|
||||
// It's expected to have some false positives, but arguably
|
||||
// they are confusing anyway due to the use*() convention
|
||||
// already being associated with Hooks.
|
||||
useState();
|
||||
if (foo) {
|
||||
const foo = React.useCallback(() => {});
|
||||
}
|
||||
useCustomHook();
|
||||
|
||||
```
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// This is a false positive (it's valid) that unfortunately
|
||||
// we cannot avoid. Prefer to rename it to not start with "use"
|
||||
class Foo extends Component {
|
||||
render() {
|
||||
if (cond) {
|
||||
FooStore.useFeatureFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// This is a false positive (it's valid) that unfortunately
|
||||
// we cannot avoid. Prefer to rename it to not start with "use"
|
||||
class Foo extends Component {
|
||||
render() {
|
||||
if (cond) {
|
||||
FooStore.useFeatureFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Technically this is a false positive.
|
||||
// We *could* make it valid (and it used to be).
|
||||
//
|
||||
// However, top-level Hook-like calls can be very dangerous
|
||||
// in environments with inline requires because they can mask
|
||||
// the runtime error by accident.
|
||||
// So we prefer to disallow it despite the false positive.
|
||||
|
||||
const { createHistory, useBasename } = require("history-2.1.2");
|
||||
const browserHistory = useBasename(createHistory)({
|
||||
basename: "/",
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Technically this is a false positive.
|
||||
// We *could* make it valid (and it used to be).
|
||||
//
|
||||
// However, top-level Hook-like calls can be very dangerous
|
||||
// in environments with inline requires because they can mask
|
||||
// the runtime error by accident.
|
||||
// So we prefer to disallow it despite the false positive.
|
||||
|
||||
const { createHistory, useBasename } = require("history-2.1.2");
|
||||
const browserHistory = useBasename(createHistory)({
|
||||
basename: "/",
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
useHook() {
|
||||
useState();
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
useHook() {
|
||||
useState();
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function createComponent() {
|
||||
return function ComponentWithHookInsideCallback() {
|
||||
function handleClick() {
|
||||
useState();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function createComponent() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = function ComponentWithHookInsideCallback() {};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// These are neither functions nor hooks.
|
||||
function _normalFunctionWithHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
function _useNotAHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// These are neither functions nor hooks.
|
||||
function _normalFunctionWithHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
|
||||
function _useNotAHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function ComponentWithHookInsideCallback() {
|
||||
function handleClick() {
|
||||
useState();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function ComponentWithHookInsideCallback() {}
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class ClassComponentWithHook extends React.Component {
|
||||
render() {
|
||||
React.useState();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class ClassComponentWithHook extends React.Component {
|
||||
render() {
|
||||
React.useState();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class ClassComponentWithFeatureFlag extends React.Component {
|
||||
render() {
|
||||
if (foo) {
|
||||
useFeatureFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class ClassComponentWithFeatureFlag extends React.Component {
|
||||
render() {
|
||||
if (foo) {
|
||||
useFeatureFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
h = () => {
|
||||
useState();
|
||||
};
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
h = () => {
|
||||
useState();
|
||||
};
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// This is invalid because "use"-prefixed functions used in named
|
||||
// functions are assumed to be hooks.
|
||||
React.unknownFunction(function notAComponent(foo, bar) {
|
||||
useProbablyAHook(bar);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// This is invalid because "use"-prefixed functions used in named
|
||||
// functions are assumed to be hooks.
|
||||
React.unknownFunction(function notAComponent(foo, bar) {
|
||||
useProbablyAHook(bar);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class C {
|
||||
m() {
|
||||
This.useHook();
|
||||
Super.useHook();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
class C {
|
||||
m() {
|
||||
This.useHook();
|
||||
Super.useHook();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Currently invalid because it violates the convention and removes the "taint"
|
||||
// from a hook. We *could* make it valid to avoid some false positives but let's
|
||||
// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
|
||||
// cases which must remain invalid.
|
||||
function normalFunctionWithHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Currently invalid because it violates the convention and removes the "taint"
|
||||
// from a hook. We *could* make it valid to avoid some false positives but let's
|
||||
// ensure that we don't break the "renderItem" and "normalFunctionWithConditionalHook"
|
||||
// cases which must remain invalid.
|
||||
function normalFunctionWithHook() {
|
||||
useHookInsideNormalFunction();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function createComponent() {
|
||||
return function ComponentWithConditionalHook() {
|
||||
if (cond) {
|
||||
useConditionalHook();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function createComponent() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = function ComponentWithConditionalHook() {
|
||||
if (cond) {
|
||||
useConditionalHook();
|
||||
}
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function ComponentWithHookInsideCallback() {
|
||||
useEffect(() => {
|
||||
useHookInsideCallback();
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's a common misunderstanding.
|
||||
// We *could* make it valid but the runtime error could be confusing.
|
||||
function ComponentWithHookInsideCallback() {
|
||||
const $ = useMemoCache(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = () => {
|
||||
useHookInsideCallback();
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
useEffect(t0);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
i() {
|
||||
useState();
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
i() {
|
||||
useState();
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function renderItem() {
|
||||
useState();
|
||||
}
|
||||
|
||||
function List(props) {
|
||||
return props.items.map(renderItem);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @skip
|
||||
// Passed but should have failed
|
||||
|
||||
// Invalid because it's dangerous and might not warn otherwise.
|
||||
// This *must* be invalid.
|
||||
function renderItem() {
|
||||
useState();
|
||||
}
|
||||
|
||||
function List(props) {
|
||||
const $ = useMemoCache(2);
|
||||
let t0;
|
||||
if ($[0] !== props.items) {
|
||||
t0 = props.items.map(renderItem);
|
||||
$[0] = props.items;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
useHook = () => {
|
||||
useState();
|
||||
};
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
// @skip
|
||||
// Passed but should have failed
|
||||
|
||||
(class {
|
||||
useHook = () => {
|
||||
useState();
|
||||
};
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import { identity } from "shared-runtime";
|
||||
|
||||
const SCALE = 2;
|
||||
function Component(props) {
|
||||
const { [props.name]: value } = props;
|
||||
return value;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ name: "Sathya" }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[ReactForget] Todo: (BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern (5:5)
|
||||
```
|
||||
|
||||
|
||||
+2
-4
@@ -26,9 +26,8 @@ import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function Component(props) {
|
||||
const $ = useMemoCache(5);
|
||||
const data = useFreeze();
|
||||
const c_0 = $[0] !== data.items;
|
||||
let t1;
|
||||
if (c_0) {
|
||||
if ($[0] !== data.items) {
|
||||
let t0;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = (item) => <Item item={item} />;
|
||||
@@ -43,9 +42,8 @@ function Component(props) {
|
||||
t1 = $[1];
|
||||
}
|
||||
const items = t1;
|
||||
const c_3 = $[3] !== items;
|
||||
let t2;
|
||||
if (c_3) {
|
||||
if ($[3] !== items) {
|
||||
t2 = <div>{items}</div>;
|
||||
$[3] = items;
|
||||
$[4] = t2;
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component(props) {
|
||||
const FooContext = useContext(Foo);
|
||||
// This function should be memoized, but its mutable range is entangled
|
||||
// with the useContext call. We can't memoize hooks, therefore the
|
||||
// reactive scope around the hook + callback is pruned and we're left
|
||||
// w no memoization of the callback.
|
||||
//
|
||||
// Ideally we'd determine that this isn't called during render and can
|
||||
// therefore be considered "immutable" or otherwise safe to memoize
|
||||
// independently
|
||||
const onClick = () => {
|
||||
FooContext.current = true;
|
||||
};
|
||||
return <div onClick={onClick} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
function Component(props) {
|
||||
const $ = useMemoCache(2);
|
||||
const FooContext = useContext(Foo);
|
||||
|
||||
const onClick = () => {
|
||||
FooContext.current = true;
|
||||
};
|
||||
let t0;
|
||||
if ($[0] !== onClick) {
|
||||
t0 = <div onClick={onClick} />;
|
||||
$[0] = onClick;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -42,11 +42,7 @@ function stripExtension(filename: string, extensions: Array<string>): string {
|
||||
return filename;
|
||||
}
|
||||
|
||||
function shouldSkip(
|
||||
filter: TestFilter | null,
|
||||
filterId: string,
|
||||
filename: string
|
||||
) {
|
||||
function shouldSkip(filter: TestFilter | null, filterId: string) {
|
||||
if (filter) {
|
||||
if (filter.kind === "only" && filter.paths.indexOf(filterId) === -1) {
|
||||
return true;
|
||||
@@ -56,8 +52,6 @@ function shouldSkip(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
} else if (filename.startsWith("todo.")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -117,10 +111,9 @@ export function getFixtures(
|
||||
});
|
||||
const fixtures: Map<string, TestFixture> = new Map();
|
||||
for (const filePath of inputFiles) {
|
||||
const filename = path.basename(filePath);
|
||||
// Do not include extensions in unique identifier for fixture
|
||||
const partialPath = stripExtension(filePath, INPUT_EXTENSIONS);
|
||||
if (shouldSkip(filter, partialPath, filename)) {
|
||||
if (shouldSkip(filter, partialPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -145,10 +138,9 @@ export function getFixtures(
|
||||
cwd: FIXTURES_PATH,
|
||||
});
|
||||
for (const filePath of outputFiles) {
|
||||
const filename = path.basename(filePath);
|
||||
// Do not include extensions in unique identifier for fixture
|
||||
const partialPath = stripExtension(filePath, [OUTPUT_EXTENSION]);
|
||||
if (shouldSkip(filter, partialPath, filename)) {
|
||||
if (shouldSkip(filter, partialPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ export async function compile(
|
||||
clearRequireCache();
|
||||
}
|
||||
version = compilerVersion;
|
||||
const { inputPath, outputPath, outputExists, basename } =
|
||||
fixture;
|
||||
const { inputPath, outputPath, outputExists, basename } = fixture;
|
||||
const input = inputPath != null ? await fs.readFile(inputPath, "utf8") : null;
|
||||
const expected = outputExists ? await fs.readFile(outputPath, "utf8") : null;
|
||||
|
||||
@@ -109,7 +108,8 @@ export async function compile(
|
||||
}
|
||||
|
||||
const output = writeOutputToString(input, code, error);
|
||||
const expectError = basename.startsWith("error.");
|
||||
const expectError =
|
||||
basename.startsWith("error.") || basename.startsWith("todo.error");
|
||||
let unexpectedError: string | null = null;
|
||||
if (expectError) {
|
||||
if (error === null) {
|
||||
|
||||
@@ -477,6 +477,37 @@ const skipFilter = new Set([
|
||||
|
||||
// nothing to compile/run
|
||||
"repro-no-gating-import-without-compiled-functions",
|
||||
|
||||
// TODOs
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-279ac76f53af",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-28a78701970c",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-3d692676194b",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-6949b255e7eb",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-8503ca76d6f8",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-e0a5db3ae21e",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-e9f9bac89f8f",
|
||||
"rules-of-hooks/todo.bail.rules-of-hooks-fadd52c1e460",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0a1dbff27ba0",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-0de1224ce64b",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-191029ac48c8",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-206e2811c87c",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-28a7111f56a7",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-2c51251df67a",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-449a37146a83",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-5a7ac9a6e8fa",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-76a74b4666e9",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-8303403b8e4c",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-99b5c750d1d1",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-9c79feec4b9b",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-a63fd4f9dcc0",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-acb56658fe7e",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-c59788ef5676",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d842d36db450",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-d952b82c2597",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-ddeca9708b63",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e675f0a672d8",
|
||||
"rules-of-hooks/todo.invalid.invalid-rules-of-hooks-e69ffce323c3",
|
||||
"todo.unnecessary-lambda-memoization",
|
||||
]);
|
||||
|
||||
export default skipFilter;
|
||||
|
||||
@@ -6,16 +6,19 @@
|
||||
*/
|
||||
|
||||
import chalk from "chalk";
|
||||
import { TestFixture } from "fixture-test-utils";
|
||||
import { getFixtures, readTestFilter } from "fixture-test-utils";
|
||||
import {
|
||||
FILTER_FILENAME,
|
||||
TestFixture,
|
||||
getFixtures,
|
||||
readTestFilter,
|
||||
} from "fixture-test-utils";
|
||||
import { Worker } from "jest-worker";
|
||||
import process from "process";
|
||||
import * as readline from "readline";
|
||||
import * as RunnerWorker from "./runner-worker";
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import SproutTodoFilter from "./SproutTodoFilter";
|
||||
import { FILTER_FILENAME } from "fixture-test-utils";
|
||||
import * as RunnerWorker from "./runner-worker";
|
||||
|
||||
const WORKER_PATH = require.resolve("./runner-worker");
|
||||
readline.emitKeypressEvents(process.stdin);
|
||||
@@ -186,7 +189,10 @@ export async function main(opts: RunnerOptions): Promise<void> {
|
||||
|
||||
const validFixtures = new Map();
|
||||
for (const [name, fixture] of allFixtures) {
|
||||
if (fixture.basename.startsWith("error.")) {
|
||||
if (
|
||||
fixture.basename.startsWith("error.") ||
|
||||
fixture.basename.startsWith("todo.error.")
|
||||
) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user