diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx
index 18f904d225..cf80b48dbf 100644
--- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx
+++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx
@@ -14,6 +14,7 @@ import React, {
unstable_ViewTransition as ViewTransition,
unstable_addTransitionType as addTransitionType,
startTransition,
+ Activity,
} from 'react';
import {Resizable} from 're-resizable';
import {useStore, useStoreDispatch} from '../StoreContext';
@@ -34,12 +35,8 @@ export default function ConfigEditor({
const [isExpanded, setIsExpanded] = useState(false);
return (
- // TODO: Use when it is compatible with Monaco: https://github.com/suren-atoyan/monaco-react/issues/753
<>
-
+
{
startTransition(() => {
@@ -49,11 +46,8 @@ export default function ConfigEditor({
}}
formattedAppliedConfig={formattedAppliedConfig}
/>
-
-
+
+
{
startTransition(() => {
@@ -62,7 +56,7 @@ export default function ConfigEditor({
});
}}
/>
-
+
>
);
}
@@ -122,7 +116,8 @@ function ExpandedEditor({
return (
+ enter={{[CONFIG_PANEL_TRANSITION]: 'slide-in', default: 'none'}}
+ exit={{[CONFIG_PANEL_TRANSITION]: 'slide-out', default: 'none'}}>
' + ' '.repeat(pipeIndex - 2) + '…',
+ ...lines.slice(
+ -(CODEFRAME_LINES_BELOW + CODEFRAME_ABBREVIATED_SOURCE_LINES),
+ ),
+ ].join('\n');
}
function printErrorSummary(category: ErrorCategory, message: string): string {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
index 0ae338f5c7..f6872da111 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
@@ -1568,20 +1568,6 @@ function lowerObjectPropertyKey(
name: key.node.value,
};
} else if (property.node.computed && key.isExpression()) {
- if (!key.isIdentifier() && !key.isMemberExpression()) {
- /*
- * NOTE: allowing complex key expressions can trigger a bug where a mutation is made conditional
- * see fixture
- * error.object-expression-computed-key-modified-during-after-construction.js
- */
- builder.errors.push({
- reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
- category: ErrorCategory.Todo,
- loc: key.node.loc ?? null,
- suggestions: null,
- });
- return null;
- }
const place = lowerExpressionToTemporary(builder, key);
return {
kind: 'computed',
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md
index 7913666aa3..bd3d513a8f 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md
@@ -35,18 +35,7 @@ error.hoist-optional-member-expression-with-conditional-optional.ts:4:23
3 | function Component(props) {
> 4 | const data = useMemo(() => {
| ^^^^^^^
-> 5 | const x = [];
- | ^^^^^^^^^^^^^^^^^
-> 6 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 7 | if (props.cond) {
- | ^^^^^^^^^^^^^^^^^
-> 8 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 9 | }
- | ^^^^^^^^^^^^^^^^^
-> 10 | return x;
- | ^^^^^^^^^^^^^^^^^
+> …
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual memoization
12 | return (
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md
index b60a911875..5a512f9c7e 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md
@@ -35,18 +35,7 @@ error.hoist-optional-member-expression-with-conditional.ts:4:23
3 | function Component(props) {
> 4 | const data = useMemo(() => {
| ^^^^^^^
-> 5 | const x = [];
- | ^^^^^^^^^^^^^^^^^
-> 6 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 7 | if (props.cond) {
- | ^^^^^^^^^^^^^^^^^
-> 8 | x.push(props.items);
- | ^^^^^^^^^^^^^^^^^
-> 9 | }
- | ^^^^^^^^^^^^^^^^^
-> 10 | return x;
- | ^^^^^^^^^^^^^^^^^
+> …
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual memoization
12 | return (
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md
index fa5cc6d53f..697a786f49 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md
@@ -29,12 +29,7 @@ error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.ts:3:2
2 | function Component(props) {
> 3 | const data = useMemo(() => {
| ^^^^^^^
-> 4 | // actual code is non-optional
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 5 | return props.items.edges.nodes ?? [];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 6 | // deps are optional
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+> …
> 7 | }, [props.items?.edges?.nodes]);
| ^^^^ Could not preserve existing manual memoization
8 | return ;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md
index 8592ae65e4..ee69f200ac 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-uncalled-function-capturing-mutable-values-memoizes-with-captures-values.expect.md
@@ -57,35 +57,7 @@ This argument is a function which may reassign or mutate `cache` after render, w
20 | ): TInput => TOutput {
> 21 | return useMemo(() => {
| ^^^^^^^^^^^^^^^
-> 22 | // The original issue is that `cache` was not memoized together with the returned
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 23 | // function. This was because neither appears to ever be mutated — the function
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 24 | // is known to mutate `cache` but the function isn't called.
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 25 | //
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 26 | // The fix is to detect cases like this — functions that are mutable but not called -
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 27 | // and ensure that their mutable captures are aliased together into the same scope.
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 28 | const cache = new WeakMap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 29 | return input => {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 30 | let output = cache.get(input);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 31 | if (output == null) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 32 | output = map(input);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 33 | cache.set(input, output);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 34 | }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 35 | return output;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 36 | };
+> …
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 37 | }, [map]);
| ^^^^^^^^^^^^ This function may (indirectly) reassign or modify `cache` after render
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-preserve-memoization-inner-destructured-value-mistaken-as-dependency-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-preserve-memoization-inner-destructured-value-mistaken-as-dependency-later-mutation.expect.md
index 8d603c629b..32b062d891 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-preserve-memoization-inner-destructured-value-mistaken-as-dependency-later-mutation.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-preserve-memoization-inner-destructured-value-mistaken-as-dependency-later-mutation.expect.md
@@ -45,10 +45,7 @@ error.repro-preserve-memoization-inner-destructured-value-mistaken-as-dependency
18 | function useInputValue(input) {
> 19 | const object = React.useMemo(() => {
| ^^^^^^^^^^^^^^^^^^^^^
-> 20 | const {value} = transform(input);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 21 | return {value};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+> …
> 22 | }, [input]);
| ^^^^^^^^^^^^^^ Could not preserve existing memoization
23 | mutate(object);
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-in-loop-with-context-variable-iterator.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-in-loop-with-context-variable-iterator.expect.md
index e5bcf704d1..775306e348 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-in-loop-with-context-variable-iterator.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-in-loop-with-context-variable-iterator.expect.md
@@ -40,18 +40,7 @@ error.todo-for-in-loop-with-context-variable-iterator.ts:8:2
7 | // within a closure, the `onClick` handler of each item
> 8 | for (let key in props.data) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 9 | key = key ?? null; // no-op reassignment to force a context variable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 10 | items.push(
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 11 | data.set(key)}>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 12 | {key}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 13 |
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 14 | );
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+> …
> 15 | }
| ^^^^ Support non-trivial for..in inits
16 | return {items}
;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-of-loop-with-context-variable-iterator.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-of-loop-with-context-variable-iterator.expect.md
index 800822b674..f487025bcb 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-of-loop-with-context-variable-iterator.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-for-of-loop-with-context-variable-iterator.expect.md
@@ -40,18 +40,7 @@ error.todo-for-of-loop-with-context-variable-iterator.ts:8:2
7 | // within a closure, the `onClick` handler of each item
> 8 | for (let item of props.data) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 9 | item = item ?? {}; // reassignment to force a context variable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 10 | items.push(
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 11 | data.set(item)}>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 12 | {item.id}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 13 |
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 14 | );
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+> …
> 15 | }
| ^^^^ Support non-trivial for..of inits
16 | return {items}
;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md
index d82575b8c3..e6bb7274e2 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md
@@ -35,22 +35,7 @@ error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.ts:6:2
5 | let el;
> 6 | try {
| ^^^^^
-> 7 | let value;
- | ^^^^^^^^^^^^^^
-> 8 | try {
- | ^^^^^^^^^^^^^^
-> 9 | value = identity(props.foo);
- | ^^^^^^^^^^^^^^
-> 10 | } catch {
- | ^^^^^^^^^^^^^^
-> 11 | el = ;
- | ^^^^^^^^^^^^^^
-> 12 | }
- | ^^^^^^^^^^^^^^
-> 13 | } finally {
- | ^^^^^^^^^^^^^^
-> 14 | console.log(el);
- | ^^^^^^^^^^^^^^
+> …
> 15 | }
| ^^^^ (BuildHIR::lowerStatement) Handle TryStatement without a catch clause
16 | return el;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md
index e8a2920564..7b4307bdf2 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md
@@ -28,12 +28,7 @@ error.todo-invalid-jsx-in-try-with-finally.ts:4:2
3 | let el;
> 4 | try {
| ^^^^^
-> 5 | el = ;
- | ^^^^^^^^^^^^^^^^^
-> 6 | } finally {
- | ^^^^^^^^^^^^^^^^^
-> 7 | console.log(el);
- | ^^^^^^^^^^^^^^^^^
+> …
> 8 | }
| ^^^^ (BuildHIR::lowerStatement) Handle TryStatement without a catch clause
9 | return el;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
index 32db5b2e7c..f11fa57689 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
@@ -101,14 +101,7 @@ error.todo-kitchensink.ts:5:2
4 |
> 5 | class Bar {
| ^^^^^^^^^^^
-> 6 | #secretSauce = 42;
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 7 | constructor() {
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 8 | console.log(this.#secretSauce);
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 9 | }
- | ^^^^^^^^^^^^^^^^^^^^^^
+> …
> 10 | }
| ^^^^ Inline `class` declarations are not supported
11 |
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md
deleted file mode 100644
index bebdd9dcc9..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md
+++ /dev/null
@@ -1,41 +0,0 @@
-
-## Input
-
-```javascript
-import {identity, mutate, mutateAndReturn} from 'shared-runtime';
-
-function Component(props) {
- const key = {};
- const context = {
- [(mutate(key), key)]: identity([props.value]),
- };
- mutate(key);
- return context;
-}
-
-export const FIXTURE_ENTRYPOINT = {
- fn: Component,
- params: [{value: 42}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: (BuildHIR::lowerExpression) Expected Identifier, got SequenceExpression key in ObjectExpression
-
-error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.ts:6:6
- 4 | const key = {};
- 5 | const context = {
-> 6 | [(mutate(key), key)]: identity([props.value]),
- | ^^^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Expected Identifier, got SequenceExpression key in ObjectExpression
- 7 | };
- 8 | mutate(key);
- 9 | return context;
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.expect.md
deleted file mode 100644
index 215e5200a9..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.expect.md
+++ /dev/null
@@ -1,41 +0,0 @@
-
-## Input
-
-```javascript
-import {identity, mutate, mutateAndReturn} from 'shared-runtime';
-
-function Component(props) {
- const key = {};
- const context = {
- [mutateAndReturn(key)]: identity([props.value]),
- };
- mutate(key);
- return context;
-}
-
-export const FIXTURE_ENTRYPOINT = {
- fn: Component,
- params: [{value: 42}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
-
-error.todo-object-expression-computed-key-modified-during-after-construction.ts:6:5
- 4 | const key = {};
- 5 | const context = {
-> 6 | [mutateAndReturn(key)]: identity([props.value]),
- | ^^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
- 7 | };
- 8 | mutate(key);
- 9 | return context;
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.expect.md
deleted file mode 100644
index abe4153e22..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.expect.md
+++ /dev/null
@@ -1,40 +0,0 @@
-
-## Input
-
-```javascript
-import {identity, mutate, mutateAndReturn} from 'shared-runtime';
-
-function Component(props) {
- const key = {};
- const context = {
- [mutateAndReturn(key)]: identity([props.value]),
- };
- return context;
-}
-
-export const FIXTURE_ENTRYPOINT = {
- fn: Component,
- params: [{value: 42}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
-
-error.todo-object-expression-computed-key-mutate-key-while-constructing-object.ts:6:5
- 4 | const key = {};
- 5 | const context = {
-> 6 | [mutateAndReturn(key)]: identity([props.value]),
- | ^^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
- 7 | };
- 8 | return context;
- 9 | }
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md
deleted file mode 100644
index 560f40b991..0000000000
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md
+++ /dev/null
@@ -1,42 +0,0 @@
-
-## Input
-
-```javascript
-import {identity, mutate, mutateAndReturn} from 'shared-runtime';
-
-function Component(props) {
- const obj = {mutateAndReturn};
- const key = {};
- const context = {
- [obj.mutateAndReturn(key)]: identity([props.value]),
- };
- mutate(key);
- return context;
-}
-
-export const FIXTURE_ENTRYPOINT = {
- fn: Component,
- params: [{value: 42}],
-};
-
-```
-
-
-## Error
-
-```
-Found 1 error:
-
-Todo: (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
-
-error.todo-object-expression-member-expr-call.ts:7:5
- 5 | const key = {};
- 6 | const context = {
-> 7 | [obj.mutateAndReturn(key)]: identity([props.value]),
- | ^^^^^^^^^^^^^^^^^^^^^^^^ (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression
- 8 | };
- 9 | mutate(key);
- 10 | return context;
-```
-
-
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.expect.md
index e9772e6799..9b61883725 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.expect.md
@@ -61,26 +61,7 @@ error.todo-preserve-memo-deps-mixed-optional-nonoptional-property-chain.ts:7:25
6 | function Component({x}) {
> 7 | const object = useMemo(() => {
| ^^^^^^^
-> 8 | return identity({
- | ^^^^^^^^^^^^^^^^^^^^^
-> 9 | callback: () => {
- | ^^^^^^^^^^^^^^^^^^^^^
-> 10 | // This is a bug in our dependency inference: we stop capturing dependencies
- | ^^^^^^^^^^^^^^^^^^^^^
-> 11 | // after x.a.b?.c. But what this dependency is telling us is that if `x.a.b`
- | ^^^^^^^^^^^^^^^^^^^^^
-> 12 | // was non-nullish, then we can access `.c.d?.e`. Thus we should take the
- | ^^^^^^^^^^^^^^^^^^^^^
-> 13 | // full property chain, exactly as-is with optionals/non-optionals, as a
- | ^^^^^^^^^^^^^^^^^^^^^
-> 14 | // dependency
- | ^^^^^^^^^^^^^^^^^^^^^
-> 15 | return identity(x.a.b?.c.d?.e);
- | ^^^^^^^^^^^^^^^^^^^^^
-> 16 | },
- | ^^^^^^^^^^^^^^^^^^^^^
-> 17 | });
- | ^^^^^^^^^^^^^^^^^^^^^
+> …
> 18 | }, [x.a.b?.c.d?.e]);
| ^^^^ Could not preserve existing manual memoization
19 | const result = useMemo(() => {
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md
index be31341d15..e356b92e08 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md
@@ -62,14 +62,7 @@ React Compiler has skipped optimizing this component because the existing manual
10 |
> 11 | const logData = useMemo(() => {
| ^^^^^^^^^^^^^^^
-> 12 | const item = items[index];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 13 | return {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 14 | key: item.key,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-> 15 | };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+> …
> 16 | }, [index, items]);
| ^^^^^^^^^^^^^^^^^^^^^ Could not preserve existing memoization
17 |
@@ -96,20 +89,7 @@ React Compiler has skipped optimizing this component because the existing manual
18 | const setCurrentIndex = useCallback(
> 19 | (index: number) => {
| ^^^^^^^^^^^^^^^^^^^^
-> 20 | const object = {
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 21 | tracking: logData.key,
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 22 | };
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 23 | // We infer that this may mutate `object`, which in turn aliases
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 24 | // data from `logData`, such that `logData` may be mutated.
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 25 | LogEvent.log(() => object);
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 26 | setIndex(index);
- | ^^^^^^^^^^^^^^^^^^^^^^
+> …
> 27 | },
| ^^^^^^ Could not preserve existing memoization
28 | [index, logData, items]
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md
index 38d10ee0d1..d080efff9b 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/error.todo-syntax.expect.md
@@ -43,24 +43,7 @@ error.todo-syntax.ts:11:2
10 | 'use memo';
> 11 | useSpecialEffect(
| ^^^^^^^^^^^^^^^^^
-> 12 | () => {
- | ^^^^^^^^^^^
-> 13 | try {
- | ^^^^^^^^^^^
-> 14 | console.log(prop1);
- | ^^^^^^^^^^^
-> 15 | } finally {
- | ^^^^^^^^^^^
-> 16 | console.log('exiting');
- | ^^^^^^^^^^^
-> 17 | }
- | ^^^^^^^^^^^
-> 18 | },
- | ^^^^^^^^^^^
-> 19 | [prop1],
- | ^^^^^^^^^^^
-> 20 | AUTODEPS
- | ^^^^^^^^^^^
+> …
> 21 | );
| ^^^^ Cannot infer dependencies
22 | return {prop1}
;
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.expect.md
index 0a5cde5cd6..f18cc75143 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/error.wrong-index.expect.md
@@ -33,15 +33,7 @@ error.wrong-index.ts:6:2
5 | function Component({foo}) {
> 6 | useEffectWrapper(
| ^^^^^^^^^^^^^^^^^
-> 7 | () => {
- | ^^^^^^^^^^^
-> 8 | console.log(foo);
- | ^^^^^^^^^^^
-> 9 | },
- | ^^^^^^^^^^^
-> 10 | [foo],
- | ^^^^^^^^^^^
-> 11 | AUTODEPS
+> …
| ^^^^^^^^^^^
> 12 | );
| ^^^^ Cannot infer dependencies
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md
new file mode 100644
index 0000000000..d46db9c8de
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.expect.md
@@ -0,0 +1,56 @@
+
+## Input
+
+```javascript
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
+
+function Component(props) {
+ const key = {};
+ const context = {
+ [(mutate(key), key)]: identity([props.value]),
+ };
+ mutate(key);
+ return [context, key];
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: 42}],
+ sequentialRenders: [{value: 42}, {value: 42}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { identity, mutate, mutateAndReturn } from "shared-runtime";
+
+function Component(props) {
+ const $ = _c(2);
+ let t0;
+ if ($[0] !== props.value) {
+ const key = {};
+ const context = { [(mutate(key), key)]: identity([props.value]) };
+ mutate(key);
+ t0 = [context, key];
+ $[0] = props.value;
+ $[1] = t0;
+ } else {
+ t0 = $[1];
+ }
+ return t0;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+ sequentialRenders: [{ value: 42 }, { value: 42 }],
+};
+
+```
+
+### Eval output
+(kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
+[{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.js
similarity index 79%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.js
index 59437a9ffd..183c03cf91 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr.js
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction-sequence-expr.js
@@ -6,10 +6,11 @@ function Component(props) {
[(mutate(key), key)]: identity([props.value]),
};
mutate(key);
- return context;
+ return [context, key];
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
+ sequentialRenders: [{value: 42}, {value: 42}],
};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.expect.md
new file mode 100644
index 0000000000..1d671aa36c
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.expect.md
@@ -0,0 +1,55 @@
+
+## Input
+
+```javascript
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
+
+function Component(props) {
+ const key = {};
+ const context = {
+ [mutateAndReturn(key)]: identity([props.value]),
+ };
+ mutate(key);
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: 42}],
+ sequentialRenders: [{value: 42}, {value: 42}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { identity, mutate, mutateAndReturn } from "shared-runtime";
+
+function Component(props) {
+ const $ = _c(2);
+ let context;
+ if ($[0] !== props.value) {
+ const key = {};
+ context = { [mutateAndReturn(key)]: identity([props.value]) };
+ mutate(key);
+ $[0] = props.value;
+ $[1] = context;
+ } else {
+ context = $[1];
+ }
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+ sequentialRenders: [{ value: 42 }, { value: 42 }],
+};
+
+```
+
+### Eval output
+(kind: ok) {"[object Object]":[42]}
+{"[object Object]":[42]}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.js
similarity index 86%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.js
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.js
index 86d9cd7fd9..0176850e98 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-modified-during-after-construction.js
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-modified-during-after-construction.js
@@ -12,4 +12,5 @@ function Component(props) {
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 42}],
+ sequentialRenders: [{value: 42}, {value: 42}],
};
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-mutate-key-while-constructing-object.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-mutate-key-while-constructing-object.expect.md
new file mode 100644
index 0000000000..4c4b45967e
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-mutate-key-while-constructing-object.expect.md
@@ -0,0 +1,67 @@
+
+## Input
+
+```javascript
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
+
+function Component(props) {
+ const key = {};
+ const context = {
+ [mutateAndReturn(key)]: identity([props.value]),
+ };
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: 42}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { identity, mutate, mutateAndReturn } from "shared-runtime";
+
+function Component(props) {
+ const $ = _c(5);
+ let t0;
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
+ const key = {};
+
+ t0 = mutateAndReturn(key);
+ $[0] = t0;
+ } else {
+ t0 = $[0];
+ }
+ let t1;
+ if ($[1] !== props.value) {
+ t1 = identity([props.value]);
+ $[1] = props.value;
+ $[2] = t1;
+ } else {
+ t1 = $[2];
+ }
+ let t2;
+ if ($[3] !== t1) {
+ t2 = { [t0]: t1 };
+ $[3] = t1;
+ $[4] = t2;
+ } else {
+ t2 = $[4];
+ }
+ const context = t2;
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+};
+
+```
+
+### Eval output
+(kind: ok) {"[object Object]":[42]}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-mutate-key-while-constructing-object.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-computed-key-mutate-key-while-constructing-object.js
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-key-mutate-key-while-constructing-object.js
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-member-expr-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-member-expr-call.expect.md
new file mode 100644
index 0000000000..ac6cb97b08
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-member-expr-call.expect.md
@@ -0,0 +1,54 @@
+
+## Input
+
+```javascript
+import {identity, mutate, mutateAndReturn} from 'shared-runtime';
+
+function Component(props) {
+ const obj = {mutateAndReturn};
+ const key = {};
+ const context = {
+ [obj.mutateAndReturn(key)]: identity([props.value]),
+ };
+ mutate(key);
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{value: 42}],
+};
+
+```
+
+## Code
+
+```javascript
+import { c as _c } from "react/compiler-runtime";
+import { identity, mutate, mutateAndReturn } from "shared-runtime";
+
+function Component(props) {
+ const $ = _c(2);
+ let context;
+ if ($[0] !== props.value) {
+ const obj = { mutateAndReturn };
+ const key = {};
+ context = { [obj.mutateAndReturn(key)]: identity([props.value]) };
+ mutate(key);
+ $[0] = props.value;
+ $[1] = context;
+ } else {
+ context = $[1];
+ }
+ return context;
+}
+
+export const FIXTURE_ENTRYPOINT = {
+ fn: Component,
+ params: [{ value: 42 }],
+};
+
+```
+
+### Eval output
+(kind: ok) {"[object Object]":[42]}
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-member-expr-call.js
similarity index 100%
rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js
rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-member-expr-call.js
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md
index ed2e61d8ee..26eff22ed7 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md
@@ -37,16 +37,7 @@ error.hoist-useCallback-conditional-access-own-scope.ts:5:21
4 | function Component({propA, propB}) {
> 5 | return useCallback(() => {
| ^^^^^^^
-> 6 | if (propA) {
- | ^^^^^^^^^^^^^^^^
-> 7 | return {
- | ^^^^^^^^^^^^^^^^
-> 8 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^
-> 9 | };
- | ^^^^^^^^^^^^^^^^
-> 10 | }
- | ^^^^^^^^^^^^^^^^
+> …
> 11 | }, [propA, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
12 | }
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md
index a16ef317b0..440478ee07 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md
@@ -40,20 +40,7 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
5 | function useHook(propA, propB) {
> 6 | return useCallback(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (identity(null) ?? propA.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
- | ^^^^^^^^^^^^^^^^^
+> …
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
15 | }
@@ -69,20 +56,7 @@ error.hoist-useCallback-infer-conditional-value-block.ts:6:21
5 | function useHook(propA, propB) {
> 6 | return useCallback(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (identity(null) ?? propA.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
- | ^^^^^^^^^^^^^^^^^
+> …
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
15 | }
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md
index 3eb8e6cb26..4f1597cdf7 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.preserve-use-memo-ref-missing-reactive.expect.md
@@ -39,12 +39,7 @@ error.preserve-use-memo-ref-missing-reactive.ts:9:21
8 |
> 9 | return useCallback(() => {
| ^^^^^^^
-> 10 | if (ref != null) {
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 11 | ref.current();
- | ^^^^^^^^^^^^^^^^^^^^^^
-> 12 | }
- | ^^^^^^^^^^^^^^^^^^^^^^
+> …
> 13 | }, []);
| ^^^^ Could not preserve existing manual memoization
14 | }
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md
index 075458831b..07d37fb156 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md
@@ -36,14 +36,7 @@ error.useCallback-conditional-access-noAlloc.ts:5:21
4 | function Component({propA, propB}) {
> 5 | return useCallback(() => {
| ^^^^^^^
-> 6 | return {
- | ^^^^^^^^^^^^
-> 7 | value: propB?.x.y,
- | ^^^^^^^^^^^^
-> 8 | other: propA,
- | ^^^^^^^^^^^^
-> 9 | };
- | ^^^^^^^^^^^^
+> …
> 10 | }, [propA, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
11 | }
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md
index 077b9aa9f6..0d81b0cf7a 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md
@@ -35,19 +35,7 @@ error.useCallback-infer-less-specific-conditional-access.ts:6:21
5 | function Component({propA, propB}) {
> 6 | return useCallback(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (propA?.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
+> …
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md
index d93c52a10c..5cb50ad525 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md
@@ -35,19 +35,7 @@ error.useMemo-infer-less-specific-conditional-access.ts:6:17
5 | function Component({propA, propB}) {
> 6 | return useMemo(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (propA?.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
+> …
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA?.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md
index 9d35f52504..943f64720a 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md
@@ -35,19 +35,7 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
5 | function Component({propA, propB}) {
> 6 | return useMemo(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (identity(null) ?? propA.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
+> …
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
@@ -63,19 +51,7 @@ error.useMemo-infer-less-specific-conditional-value-block.ts:6:17
5 | function Component({propA, propB}) {
> 6 | return useMemo(() => {
| ^^^^^^^
-> 7 | const x = {};
- | ^^^^^^^^^^^^^^^^^
-> 8 | if (identity(null) ?? propA.a) {
- | ^^^^^^^^^^^^^^^^^
-> 9 | mutate(x);
- | ^^^^^^^^^^^^^^^^^
-> 10 | return {
- | ^^^^^^^^^^^^^^^^^
-> 11 | value: propB.x.y,
- | ^^^^^^^^^^^^^^^^^
-> 12 | };
- | ^^^^^^^^^^^^^^^^^
-> 13 | }
+> …
| ^^^^^^^^^^^^^^^^^
> 14 | }, [propA.a, propB.x.y]);
| ^^^^ Could not preserve existing manual memoization
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md
index 00cc3fb839..fe8bbd64b0 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md
@@ -30,11 +30,7 @@ error.useMemo-property-call-chained-object.ts:5:17
4 | function Component({propA}) {
> 5 | return useMemo(() => {
| ^^^^^^^
-> 6 | return {
- | ^^^^^^^^^^^^
-> 7 | value: propA.x().y,
- | ^^^^^^^^^^^^
-> 8 | };
+> …
| ^^^^^^^^^^^^
> 9 | }, [propA.x]);
| ^^^^ Could not preserve existing manual memoization
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional-optional.expect.md
index 14ea4e7593..adf726b370 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional-optional.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional-optional.expect.md
@@ -35,18 +35,7 @@ error.todo-optional-member-expression-with-conditional-optional.ts:4:23
3 | function Component(props) {
> 4 | const data = useMemo(() => {
| ^^^^^^^
-> 5 | const x = [];
- | ^^^^^^^^^^^^^^^^^
-> 6 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 7 | if (props.cond) {
- | ^^^^^^^^^^^^^^^^^
-> 8 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 9 | }
- | ^^^^^^^^^^^^^^^^^
-> 10 | return x;
- | ^^^^^^^^^^^^^^^^^
+> …
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual memoization
12 | return (
diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional.expect.md
index f3fdb07697..dc2e11fd78 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional.expect.md
+++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-with-conditional.expect.md
@@ -35,18 +35,7 @@ error.todo-optional-member-expression-with-conditional.ts:4:23
3 | function Component(props) {
> 4 | const data = useMemo(() => {
| ^^^^^^^
-> 5 | const x = [];
- | ^^^^^^^^^^^^^^^^^
-> 6 | x.push(props?.items);
- | ^^^^^^^^^^^^^^^^^
-> 7 | if (props.cond) {
- | ^^^^^^^^^^^^^^^^^
-> 8 | x.push(props.items);
- | ^^^^^^^^^^^^^^^^^
-> 9 | }
- | ^^^^^^^^^^^^^^^^^
-> 10 | return x;
- | ^^^^^^^^^^^^^^^^^
+> …
> 11 | }, [props?.items, props.cond]);
| ^^^^ Could not preserve existing manual memoization
12 | return (
diff --git a/compiler/packages/babel-plugin-react-compiler/src/index.ts b/compiler/packages/babel-plugin-react-compiler/src/index.ts
index d2abd744d6..ca5b653430 100644
--- a/compiler/packages/babel-plugin-react-compiler/src/index.ts
+++ b/compiler/packages/babel-plugin-react-compiler/src/index.ts
@@ -29,10 +29,13 @@ export {
ProgramContext,
tryFindDirectiveEnablingMemoization as findDirectiveEnablingMemoization,
findDirectiveDisablingMemoization,
+ defaultOptions,
type CompilerPipelineValue,
type Logger,
type LoggerEvent,
type PluginOptions,
+ type AutoDepsDecorationsEvent,
+ type CompileSuccessEvent,
} from './Entrypoint';
export {
Effect,
diff --git a/compiler/packages/react-forgive/package.json b/compiler/packages/react-forgive/package.json
index 0bf48e232e..fc7d71095c 100644
--- a/compiler/packages/react-forgive/package.json
+++ b/compiler/packages/react-forgive/package.json
@@ -36,13 +36,14 @@
},
"scripts": {
"build": "yarn run compile",
+ "build:compiler": "yarn workspace babel-plugin-react-compiler build --dts",
"compile": "rimraf dist && concurrently -n server,client \"scripts/build.mjs -t server\" \"scripts/build.mjs -t client\"",
"dev": "yarn run package && yarn run install-ext",
"install-ext": "code --install-extension react-forgive-0.0.0.vsix",
"lint": "echo 'no tests'",
"package": "rm -f react-forgive-0.0.0.vsix && vsce package --yarn",
"postinstall": "cd client && yarn install && cd ../server && yarn install && cd ..",
- "pretest": "yarn run compile && yarn run lint",
+ "pretest": "yarn run build:compiler && yarn run compile && yarn run lint",
"test": "vscode-test",
"vscode:prepublish": "yarn run compile",
"watch": "scripts/build.mjs --watch"
diff --git a/compiler/packages/react-forgive/server/package.json b/compiler/packages/react-forgive/server/package.json
index fb6f4feebd..c912586072 100644
--- a/compiler/packages/react-forgive/server/package.json
+++ b/compiler/packages/react-forgive/server/package.json
@@ -18,7 +18,6 @@
"@babel/parser": "^7.26.0",
"@babel/plugin-syntax-typescript": "^7.25.9",
"@babel/types": "^7.26.0",
- "cosmiconfig": "^9.0.0",
"prettier": "^3.3.3",
"vscode-languageserver": "^9.0.1",
"vscode-languageserver-textdocument": "^1.0.12"
diff --git a/compiler/packages/react-forgive/server/src/compiler/compat.ts b/compiler/packages/react-forgive/server/src/compiler/compat.ts
index 10271cbdcd..f467f70ba1 100644
--- a/compiler/packages/react-forgive/server/src/compiler/compat.ts
+++ b/compiler/packages/react-forgive/server/src/compiler/compat.ts
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
-import {SourceLocation} from 'babel-plugin-react-compiler/src';
+import {type SourceLocation} from 'babel-plugin-react-compiler';
import {type Range} from 'vscode-languageserver';
export function babelLocationToRange(loc: SourceLocation): Range | null {
diff --git a/compiler/packages/react-forgive/server/src/compiler/index.ts b/compiler/packages/react-forgive/server/src/compiler/index.ts
index fe192c6213..b474253f71 100644
--- a/compiler/packages/react-forgive/server/src/compiler/index.ts
+++ b/compiler/packages/react-forgive/server/src/compiler/index.ts
@@ -9,7 +9,7 @@ import type * as BabelCore from '@babel/core';
import {parseAsync, transformFromAstAsync} from '@babel/core';
import BabelPluginReactCompiler, {
type PluginOptions,
-} from 'babel-plugin-react-compiler/src';
+} from 'babel-plugin-react-compiler';
import * as babelParser from 'prettier/plugins/babel.js';
import estreeParser from 'prettier/plugins/estree';
import * as typescriptParser from 'prettier/plugins/typescript';
diff --git a/compiler/packages/react-forgive/server/src/compiler/options.ts b/compiler/packages/react-forgive/server/src/compiler/options.ts
deleted file mode 100644
index 226be799d3..0000000000
--- a/compiler/packages/react-forgive/server/src/compiler/options.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-import {
- parsePluginOptions,
- type PluginOptions,
-} from 'babel-plugin-react-compiler/src';
-import {cosmiconfigSync} from 'cosmiconfig';
-
-export function resolveReactConfig(projectPath: string): PluginOptions | null {
- const explorerSync = cosmiconfigSync('react', {
- searchStrategy: 'project',
- cache: true,
- });
- const result = explorerSync.search(projectPath);
- if (result != null) {
- return parsePluginOptions(result.config);
- } else {
- return null;
- }
-}
diff --git a/compiler/packages/react-forgive/server/src/index.ts b/compiler/packages/react-forgive/server/src/index.ts
index fd4ffd9988..7552337cbc 100644
--- a/compiler/packages/react-forgive/server/src/index.ts
+++ b/compiler/packages/react-forgive/server/src/index.ts
@@ -20,13 +20,12 @@ import {
TextDocumentSyncKind,
} from 'vscode-languageserver/node';
import {compile, lastResult} from './compiler';
-import {type PluginOptions} from 'babel-plugin-react-compiler/src';
-import {resolveReactConfig} from './compiler/options';
import {
type CompileSuccessEvent,
type LoggerEvent,
+ type PluginOptions,
defaultOptions,
-} from 'babel-plugin-react-compiler/src/Entrypoint/Options';
+} from 'babel-plugin-react-compiler';
import {babelLocationToRange, getRangeFirstCharacter} from './compiler/compat';
import {
type AutoDepsDecorationsLSPEvent,
@@ -64,8 +63,7 @@ type CodeActionLSPEvent = {
};
connection.onInitialize((_params: InitializeParams) => {
- // TODO(@poteto) get config fr
- compilerOptions = resolveReactConfig('.') ?? defaultOptions;
+ compilerOptions = defaultOptions;
compilerOptions = {
...compilerOptions,
environment: {
@@ -76,21 +74,21 @@ connection.onInitialize((_params: InitializeParams) => {
importSpecifierName: 'useEffect',
source: 'react',
},
- numRequiredArgs: 1,
+ autodepsIndex: 1,
},
{
function: {
importSpecifierName: 'useSpecialEffect',
source: 'shared-runtime',
},
- numRequiredArgs: 2,
+ autodepsIndex: 2,
},
{
function: {
importSpecifierName: 'default',
source: 'useEffectWrapper',
},
- numRequiredArgs: 1,
+ autodepsIndex: 1,
},
],
},
diff --git a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts
index 77a568662e..c9c9e8ca01 100644
--- a/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts
+++ b/compiler/packages/react-forgive/server/src/requests/autodepsdecorations.ts
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
-import {type AutoDepsDecorationsEvent} from 'babel-plugin-react-compiler/src/Entrypoint';
+import {type AutoDepsDecorationsEvent} from 'babel-plugin-react-compiler';
import {type Position} from 'vscode-languageserver-textdocument';
import {RequestType} from 'vscode-languageserver/node';
import {type Range, sourceLocationToRange} from '../utils/range';
diff --git a/compiler/packages/react-forgive/server/yarn.lock b/compiler/packages/react-forgive/server/yarn.lock
index b72063294f..ee346ce7d3 100644
--- a/compiler/packages/react-forgive/server/yarn.lock
+++ b/compiler/packages/react-forgive/server/yarn.lock
@@ -10,7 +10,7 @@
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2":
+"@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
@@ -188,11 +188,6 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
-argparse@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
- integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-
browserslist@^4.24.0:
version "4.24.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2"
@@ -203,11 +198,6 @@ browserslist@^4.24.0:
node-releases "^2.0.19"
update-browserslist-db "^1.1.1"
-callsites@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
- integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
caniuse-lite@^1.0.30001688:
version "1.0.30001690"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8"
@@ -218,16 +208,6 @@ convert-source-map@^2.0.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
-cosmiconfig@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d"
- integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==
- dependencies:
- env-paths "^2.2.1"
- import-fresh "^3.3.0"
- js-yaml "^4.1.0"
- parse-json "^5.2.0"
-
debug@^4.1.0, debug@^4.3.1:
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
@@ -240,18 +220,6 @@ electron-to-chromium@^1.5.73:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz#cb886b504a6467e4c00bea3317edb38393c53413"
integrity sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==
-env-paths@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
- integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
-
-error-ex@^1.3.1:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
- integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
- dependencies:
- is-arrayish "^0.2.1"
-
escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
@@ -267,51 +235,21 @@ globals@^11.1.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-import-fresh@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
- integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-is-arrayish@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
- integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
-
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
- dependencies:
- argparse "^2.0.1"
-
jsesc@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
-json-parse-even-better-errors@^2.3.0:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
- integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-
json5@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
-lines-and-columns@^1.1.6:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
- integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -329,23 +267,6 @@ node-releases@^2.0.19:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
-parent-module@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
- integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
- dependencies:
- callsites "^3.0.0"
-
-parse-json@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
- integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- error-ex "^1.3.1"
- json-parse-even-better-errors "^2.3.0"
- lines-and-columns "^1.1.6"
-
picocolors@^1.0.0, picocolors@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
@@ -356,11 +277,6 @@ prettier@^3.3.3:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
diff --git a/packages/eslint-plugin-react-hooks/npm/index.d.ts b/packages/eslint-plugin-react-hooks/npm/index.d.ts
index c883d6f8ad..7516dc1e84 100644
--- a/packages/eslint-plugin-react-hooks/npm/index.d.ts
+++ b/packages/eslint-plugin-react-hooks/npm/index.d.ts
@@ -5,4 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
-export {default} from './cjs/eslint-plugin-react-hooks';
+import reactHooks from './cjs/eslint-plugin-react-hooks';
+
+export = reactHooks;
diff --git a/packages/eslint-plugin-react-hooks/npm/index.js b/packages/eslint-plugin-react-hooks/npm/index.js
index b819fc7023..3e8352af1e 100644
--- a/packages/eslint-plugin-react-hooks/npm/index.js
+++ b/packages/eslint-plugin-react-hooks/npm/index.js
@@ -14,3 +14,13 @@ if (process.env.NODE_ENV === 'production') {
} else {
module.exports = require('./cjs/eslint-plugin-react-hooks.development.js');
}
+
+// Hint to Node’s cjs-module-lexer to make named imports work
+// https://github.com/facebook/react/issues/34801#issuecomment-3433478810
+// eslint-disable-next-line ft-flow/no-unused-expressions
+0 &&
+ (module.exports = {
+ meta: true,
+ rules: true,
+ configs: true,
+ });
diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts
index 6d72c1daa5..924299d898 100644
--- a/packages/eslint-plugin-react-hooks/src/index.ts
+++ b/packages/eslint-plugin-react-hooks/src/index.ts
@@ -71,7 +71,10 @@ const configs = {
plugins,
rules: recommendedLatestRuleConfigs,
},
- flat: {} as Record,
+ flat: {} as {
+ recommended: ReactHooksFlatConfig;
+ 'recommended-latest': ReactHooksFlatConfig;
+ },
};
const plugin = {
diff --git a/packages/internal-test-utils/debugInfo.js b/packages/internal-test-utils/debugInfo.js
index 7b9c730ba6..75183ce4b6 100644
--- a/packages/internal-test-utils/debugInfo.js
+++ b/packages/internal-test-utils/debugInfo.js
@@ -64,7 +64,7 @@ function normalizeIOInfo(config: DebugInfoConfig, ioInfo) {
if (promise) {
promise.then(); // init
if (promise.status === 'fulfilled') {
- if (ioInfo.name === 'RSC stream') {
+ if (ioInfo.name === 'rsc stream') {
copy.byteSize = 0;
copy.value = {
value: 'stream',
@@ -117,7 +117,7 @@ export function getDebugInfo(config: DebugInfoConfig, obj) {
for (let i = 0; i < debugInfo.length; i++) {
if (
debugInfo[i].awaited &&
- debugInfo[i].awaited.name === 'RSC stream' &&
+ debugInfo[i].awaited.name === 'rsc stream' &&
config.ignoreRscStreamInfo
) {
// Ignore RSC stream I/O info.
diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js
index 1c2151362d..c7506a13e5 100644
--- a/packages/react-client/src/ReactFlightClient.js
+++ b/packages/react-client/src/ReactFlightClient.js
@@ -2561,6 +2561,7 @@ function ResponseInstance(
findSourceMapURL: void | FindSourceMapURLCallback, // DEV-only
replayConsole: boolean, // DEV-only
environmentName: void | string, // DEV-only
+ debugStartTime: void | number, // DEV-only
debugChannel: void | DebugChannel, // DEV-only
) {
const chunks: Map> = new Map();
@@ -2621,7 +2622,8 @@ function ResponseInstance(
// Note: createFromFetch allows this to be marked at the start of the fetch
// where as if you use createFromReadableStream from the body of the fetch
// then the start time is when the headers resolved.
- this._debugStartTime = performance.now();
+ this._debugStartTime =
+ debugStartTime == null ? performance.now() : debugStartTime;
this._debugIOStarted = false;
// We consider everything before the first setTimeout task to be cached data
// and is not considered I/O required to load the stream.
@@ -2669,6 +2671,7 @@ export function createResponse(
findSourceMapURL: void | FindSourceMapURLCallback, // DEV-only
replayConsole: boolean, // DEV-only
environmentName: void | string, // DEV-only
+ debugStartTime: void | number, // DEV-only
debugChannel: void | DebugChannel, // DEV-only
): WeakResponse {
return getWeakResponse(
@@ -2684,6 +2687,7 @@ export function createResponse(
findSourceMapURL,
replayConsole,
environmentName,
+ debugStartTime,
debugChannel,
),
);
@@ -2717,7 +2721,7 @@ export function createStreamState(
(debugValuePromise: any).status = 'fulfilled';
(debugValuePromise: any).value = streamDebugValue;
streamState._debugInfo = {
- name: 'RSC stream',
+ name: 'rsc stream',
start: response._debugStartTime,
end: response._debugStartTime, // will be updated once we finish a chunk
byteSize: 0, // will be updated as we resolve a data chunk
diff --git a/packages/react-devtools-core/package.json b/packages/react-devtools-core/package.json
index c8facd1a24..54b89e72e8 100644
--- a/packages/react-devtools-core/package.json
+++ b/packages/react-devtools-core/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools-core",
- "version": "7.0.0",
+ "version": "7.0.1",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"main": "./dist/backend.js",
diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json
index 0b5285e91a..9bb0ab1177 100644
--- a/packages/react-devtools-extensions/chrome/manifest.json
+++ b/packages/react-devtools-extensions/chrome/manifest.json
@@ -2,8 +2,8 @@
"manifest_version": 3,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Chrome Developer Tools.",
- "version": "7.0.0",
- "version_name": "7.0.0",
+ "version": "7.0.1",
+ "version_name": "7.0.1",
"minimum_chrome_version": "114",
"icons": {
"16": "icons/16-production.png",
diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json
index 342af4abb3..55b7248f25 100644
--- a/packages/react-devtools-extensions/edge/manifest.json
+++ b/packages/react-devtools-extensions/edge/manifest.json
@@ -2,8 +2,8 @@
"manifest_version": 3,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Microsoft Edge Developer Tools.",
- "version": "7.0.0",
- "version_name": "7.0.0",
+ "version": "7.0.1",
+ "version_name": "7.0.1",
"minimum_chrome_version": "114",
"icons": {
"16": "icons/16-production.png",
diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json
index bc12ac0fcd..f401708c21 100644
--- a/packages/react-devtools-extensions/firefox/manifest.json
+++ b/packages/react-devtools-extensions/firefox/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Firefox Developer Tools.",
- "version": "7.0.0",
+ "version": "7.0.1",
"browser_specific_settings": {
"gecko": {
"id": "@react-devtools",
diff --git a/packages/react-devtools-extensions/src/main/cloneStyleTags.js b/packages/react-devtools-extensions/src/main/cloneStyleTags.js
index dd84e01fc9..caad2a361c 100644
--- a/packages/react-devtools-extensions/src/main/cloneStyleTags.js
+++ b/packages/react-devtools-extensions/src/main/cloneStyleTags.js
@@ -1,5 +1,14 @@
-function cloneStyleTags() {
- const linkTags = [];
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+export function cloneStyleTags(): Array {
+ const tags: Array = [];
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
for (const linkTag of document.getElementsByTagName('link')) {
@@ -11,11 +20,23 @@ function cloneStyleTags() {
newLinkTag.setAttribute(attribute.nodeName, attribute.nodeValue);
}
- linkTags.push(newLinkTag);
+ tags.push(newLinkTag);
}
}
- return linkTags;
-}
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
+ for (const styleTag of document.getElementsByTagName('style')) {
+ const newStyleTag = document.createElement('style');
-export default cloneStyleTags;
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
+ for (const attribute of styleTag.attributes) {
+ newStyleTag.setAttribute(attribute.nodeName, attribute.nodeValue);
+ }
+
+ newStyleTag.textContent = styleTag.textContent;
+
+ tags.push(newStyleTag);
+ }
+
+ return tags;
+}
diff --git a/packages/react-devtools-extensions/src/main/index.js b/packages/react-devtools-extensions/src/main/index.js
index cec9fd6df4..bc948d1e6d 100644
--- a/packages/react-devtools-extensions/src/main/index.js
+++ b/packages/react-devtools-extensions/src/main/index.js
@@ -33,7 +33,7 @@ import {
import {viewAttributeSource} from './sourceSelection';
import {startReactPolling} from './reactPolling';
-import cloneStyleTags from './cloneStyleTags';
+import {cloneStyleTags} from './cloneStyleTags';
import fetchFileWithCaching from './fetchFileWithCaching';
import injectBackendManager from './injectBackendManager';
import registerEventsLogger from './registerEventsLogger';
diff --git a/packages/react-devtools-extensions/utils.js b/packages/react-devtools-extensions/utils.js
index 3b06bb71f7..9f02e98d19 100644
--- a/packages/react-devtools-extensions/utils.js
+++ b/packages/react-devtools-extensions/utils.js
@@ -6,7 +6,7 @@
*/
const {execSync} = require('child_process');
-const {readFileSync} = require('fs');
+const {existsSync, readFileSync} = require('fs');
const {resolve} = require('path');
const GITHUB_URL = 'https://github.com/facebook/react';
@@ -18,8 +18,26 @@ function getGitCommit() {
.trim();
} catch (error) {
// Mozilla runs this command from a git archive.
- // In that context, there is no Git revision.
- return null;
+ // In that context, there is no Git context.
+ // Using the commit hash specified to download-experimental-build.js script as a fallback.
+
+ // Try to read from build/COMMIT_SHA file
+ const commitShaPath = resolve(__dirname, '..', '..', 'build', 'COMMIT_SHA');
+ if (!existsSync(commitShaPath)) {
+ throw new Error(
+ 'Could not find build/COMMIT_SHA file. Did you run scripts/release/download-experimental-build.js script?',
+ );
+ }
+
+ try {
+ const commitHash = readFileSync(commitShaPath, 'utf8').trim();
+ // Return short hash (first 7 characters) to match abbreviated commit hash format
+ return commitHash.slice(0, 7);
+ } catch (readError) {
+ throw new Error(
+ `Failed to read build/COMMIT_SHA file: ${readError.message}`,
+ );
+ }
}
}
diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js
index 4592363c64..191eabc47c 100644
--- a/packages/react-devtools-extensions/webpack.config.js
+++ b/packages/react-devtools-extensions/webpack.config.js
@@ -285,7 +285,7 @@ module.exports = {
{
loader: 'css-loader',
options: {
- sourceMap: true,
+ sourceMap: __DEV__,
modules: true,
localIdentName: '[local]___[hash:base64:5]',
},
diff --git a/packages/react-devtools-inline/package.json b/packages/react-devtools-inline/package.json
index 0363530cd1..cc5fc51a6e 100644
--- a/packages/react-devtools-inline/package.json
+++ b/packages/react-devtools-inline/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools-inline",
- "version": "7.0.0",
+ "version": "7.0.1",
"description": "Embed react-devtools within a website",
"license": "MIT",
"main": "./dist/backend.js",
diff --git a/packages/react-devtools-shared/package.json b/packages/react-devtools-shared/package.json
index 543ac37e97..721cc9954b 100644
--- a/packages/react-devtools-shared/package.json
+++ b/packages/react-devtools-shared/package.json
@@ -23,6 +23,7 @@
"json5": "^2.2.3",
"local-storage-fallback": "^4.1.1",
"react-virtualized-auto-sizer": "^1.0.23",
- "react-window": "^1.8.10"
+ "react-window": "^1.8.10",
+ "rbush": "4.0.1"
}
}
diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js
index c02d8130c3..07e8204049 100644
--- a/packages/react-devtools-shared/src/__tests__/store-test.js
+++ b/packages/react-devtools-shared/src/__tests__/store-test.js
@@ -3243,4 +3243,61 @@ describe('Store', () => {
`);
});
+
+ // @reactVersion >= 19.0
+ it('guesses a Suspense name based on the owner', async () => {
+ let resolve;
+ const promise = new Promise(_resolve => {
+ resolve = _resolve;
+ });
+ function Inner() {
+ return (
+ Loading inner
}>
+ {promise}
+
+ );
+ }
+
+ function Outer({children}) {
+ return (
+ Loading outer}>
+ {promise}
+ {children}
+
+ );
+ }
+
+ await actAsync(() => {
+ render(
+
+
+ ,
+ );
+ });
+
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ ▾
+
+ [suspense-root] rects={[{x:1,y:2,width:13,height:1}]}
+
+ `);
+
+ console.log('...........................');
+
+ await actAsync(() => {
+ resolve('loaded');
+ });
+
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ ▾
+ ▾
+ ▾
+
+ [suspense-root] rects={[{x:1,y:2,width:6,height:1}, {x:1,y:2,width:6,height:1}]}
+
+
+ `);
+ });
});
diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js
index de178909b2..9de9037690 100644
--- a/packages/react-devtools-shared/src/backend/fiber/renderer.js
+++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js
@@ -1913,6 +1913,20 @@ export function attach(
return false;
}
+ function isUseSyncExternalStoreHook(hookObject: any): boolean {
+ const queue = hookObject.queue;
+ if (!queue) {
+ return false;
+ }
+
+ const boundHasOwnProperty = hasOwnProperty.bind(queue);
+ return (
+ boundHasOwnProperty('value') &&
+ boundHasOwnProperty('getSnapshot') &&
+ typeof queue.getSnapshot === 'function'
+ );
+ }
+
function isHookThatCanScheduleUpdate(hookObject: any) {
const queue = hookObject.queue;
if (!queue) {
@@ -1929,12 +1943,7 @@ export function attach(
return true;
}
- // Detect useSyncExternalStore()
- return (
- boundHasOwnProperty('value') &&
- boundHasOwnProperty('getSnapshot') &&
- typeof queue.getSnapshot === 'function'
- );
+ return isUseSyncExternalStoreHook(hookObject);
}
function didStatefulHookChange(prev: any, next: any): boolean {
@@ -1955,10 +1964,18 @@ export function attach(
const indices = [];
let index = 0;
+
while (next !== null) {
if (didStatefulHookChange(prev, next)) {
indices.push(index);
}
+
+ // useSyncExternalStore creates 2 internal hooks, but we only count it as 1 user-facing hook
+ if (isUseSyncExternalStoreHook(next)) {
+ next = next.next;
+ prev = prev.next;
+ }
+
next = next.next;
prev = prev.next;
index++;
@@ -2664,7 +2681,7 @@ export function attach(
const fiber = fiberInstance.data;
const props = fiber.memoizedProps;
- // TODO: Compute a fallback name based on Owner, key etc.
+ // The frontend will guess a name based on heuristics (e.g. owner) if no explicit name is given.
const name =
fiber.tag !== SuspenseComponent || props === null
? null
@@ -2862,7 +2879,10 @@ export function attach(
let parentInstance = reconcilingParent;
while (
parentInstance.kind === FILTERED_FIBER_INSTANCE &&
- parentInstance.parent !== null
+ parentInstance.parent !== null &&
+ // We can't move past the parent Suspense node.
+ // The Suspense node holding async info must be a parent of the devtools instance (or the instance itself)
+ parentInstance !== parentSuspenseNode.instance
) {
parentInstance = parentInstance.parent;
}
@@ -6168,7 +6188,10 @@ export function attach(
}
}
const newIO = asyncInfo.awaited;
- if (newIO.name === 'RSC stream' && newIO.value != null) {
+ if (
+ (newIO.name === 'RSC stream' || newIO.name === 'rsc stream') &&
+ newIO.value != null
+ ) {
const streamPromise = newIO.value;
// Special case RSC stream entries to pick the last entry keyed by the stream.
const existingEntry = streamEntries.get(streamPromise);
@@ -6227,7 +6250,10 @@ export function attach(
continue;
}
foundIOEntries.add(ioInfo);
- if (ioInfo.name === 'RSC stream' && ioInfo.value != null) {
+ if (
+ (ioInfo.name === 'RSC stream' || ioInfo.name === 'rsc stream') &&
+ ioInfo.value != null
+ ) {
const streamPromise = ioInfo.value;
// Special case RSC stream entries to pick the last entry keyed by the stream.
const existingEntry = streamEntries.get(streamPromise);
diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js
index b75e30d9c4..9377fa01df 100644
--- a/packages/react-devtools-shared/src/devtools/store.js
+++ b/packages/react-devtools-shared/src/devtools/store.js
@@ -62,6 +62,31 @@ import type {
import UnsupportedBridgeOperationError from 'react-devtools-shared/src/UnsupportedBridgeOperationError';
import type {DevToolsHookSettings} from '../backend/types';
+import RBush from 'rbush';
+
+// Custom version which works with our Rect data structure.
+class RectRBush extends RBush {
+ toBBox(rect: Rect): {
+ minX: number,
+ minY: number,
+ maxX: number,
+ maxY: number,
+ } {
+ return {
+ minX: rect.x,
+ minY: rect.y,
+ maxX: rect.x + rect.width,
+ maxY: rect.y + rect.height,
+ };
+ }
+ compareMinX(a: Rect, b: Rect): number {
+ return a.x - b.x;
+ }
+ compareMinY(a: Rect, b: Rect): number {
+ return a.y - b.y;
+ }
+}
+
const debug = (methodName: string, ...args: Array) => {
if (__DEBUG__) {
console.log(
@@ -194,6 +219,9 @@ export default class Store extends EventEmitter<{
// Renderer ID is needed to support inspection fiber props, state, and hooks.
_rootIDToRendererID: Map = new Map();
+ // Stores all the SuspenseNode rects in an R-tree to make it fast to find overlaps.
+ _rtree: RBush = new RectRBush();
+
// These options may be initially set by a configuration option when constructing the Store.
_supportsInspectMatchingDOMElement: boolean = false;
_supportsClickToInspect: boolean = false;
@@ -1622,7 +1650,12 @@ export default class Store extends EventEmitter<{
const y = operations[i + 1] / 1000;
const width = operations[i + 2] / 1000;
const height = operations[i + 3] / 1000;
- rects.push({x, y, width, height});
+ const rect = {x, y, width, height};
+ if (parentID !== 0) {
+ // Track all rects except the root.
+ this._rtree.insert(rect);
+ }
+ rects.push(rect);
i += 4;
}
}
@@ -1646,10 +1679,6 @@ export default class Store extends EventEmitter<{
parentSuspense.children.push(id);
}
- if (name === null) {
- name = 'Unknown';
- }
-
this._idToSuspense.set(id, {
id,
parentID,
@@ -1684,13 +1713,20 @@ export default class Store extends EventEmitter<{
i += 1;
- const {children, parentID} = suspense;
+ const {children, parentID, rects} = suspense;
if (children.length > 0) {
this._throwAndEmitError(
Error(`Suspense node "${id}" was removed before its children.`),
);
}
+ if (rects !== null && parentID !== 0) {
+ // Delete all the existing rects from the R-tree
+ for (let j = 0; j < rects.length; j++) {
+ this._rtree.remove(rects[j]);
+ }
+ }
+
this._idToSuspense.delete(id);
removedSuspenseIDs.set(id, parentID);
@@ -1789,6 +1825,14 @@ export default class Store extends EventEmitter<{
break;
}
+ const prevRects = suspense.rects;
+ if (prevRects !== null && suspense.parentID !== 0) {
+ // Delete all the existing rects from the R-tree
+ for (let j = 0; j < prevRects.length; j++) {
+ this._rtree.remove(prevRects[j]);
+ }
+ }
+
let nextRects: SuspenseNode['rects'];
if (numRects === -1) {
nextRects = null;
@@ -1800,7 +1844,12 @@ export default class Store extends EventEmitter<{
const width = operations[i + 2] / 1000;
const height = operations[i + 3] / 1000;
- nextRects.push({x, y, width, height});
+ const rect = {x, y, width, height};
+ if (suspense.parentID !== 0) {
+ // Track all rects except the root.
+ this._rtree.insert(rect);
+ }
+ nextRects.push(rect);
i += 4;
}
@@ -2170,13 +2219,12 @@ export default class Store extends EventEmitter<{
throw error;
}
- _guessSuspenseName(element: Element): string {
+ _guessSuspenseName(element: Element): string | null {
const owner = this._idToElement.get(element.ownerID);
- let name = 'Unknown';
if (owner !== undefined && owner.displayName !== null) {
- name = owner.displayName;
+ return owner.displayName;
}
- return name;
+ return null;
}
}
diff --git a/packages/react-devtools-shared/src/devtools/utils.js b/packages/react-devtools-shared/src/devtools/utils.js
index d5078679f4..640f0d19b5 100644
--- a/packages/react-devtools-shared/src/devtools/utils.js
+++ b/packages/react-devtools-shared/src/devtools/utils.js
@@ -63,11 +63,7 @@ function printRects(rects: SuspenseNode['rects']): string {
}
function printSuspense(suspense: SuspenseNode): string {
- let name = '';
- if (suspense.name !== null) {
- name = ` name="${suspense.name}"`;
- }
-
+ const name = ` name="${suspense.name || 'Unknown'}"`;
const printedRects = printRects(suspense.rects);
return ``;
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.css b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.css
index 574ceb0236..98200ee9df 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.css
+++ b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.css
@@ -2,9 +2,10 @@
padding: 0.25rem;
}
-.CallSite {
- display: block;
+.CallSite, .BuiltInCallSite {
+ display: flex;
padding-left: 1rem;
+ white-space-collapse: preserve;
}
.IgnoredCallSite, .BuiltInCallSite {
@@ -20,13 +21,15 @@
white-space: pre;
overflow: hidden;
text-overflow: ellipsis;
- flex: 1;
cursor: pointer;
border-radius: 0.125rem;
- padding: 0px 2px;
}
.Link:hover {
background-color: var(--color-background-hover);
}
+.ElementBadges {
+ margin-left: 0.25rem;
+}
+
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
index d3d797f781..a3cf91f14b 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
+++ b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
@@ -86,8 +86,10 @@ export function CallSiteView({
>
)}
-
-
+
);
}
diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseBreadcrumbs.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseBreadcrumbs.js
index d7112ec7d3..b27e0f5987 100644
--- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseBreadcrumbs.js
+++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseBreadcrumbs.js
@@ -72,7 +72,7 @@ export default function SuspenseBreadcrumbs(): React$Node {
className={styles.SuspenseBreadcrumbsButton}
onClick={handleClick.bind(null, id)}
type="button">
- {node === null ? 'Unknown' : node.name}
+ {node === null ? 'Unknown' : node.name || 'Unknown'}
);
diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css
index db0a84d8d8..0af7baf51a 100644
--- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css
+++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css
@@ -39,6 +39,25 @@
pointer-events: none;
}
+.SuspenseRectsTitle {
+ pointer-events: none;
+ color: color-mix(in srgb, var(--color-suspense) 50%, var(--color-text));
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: var(--font-family-sans);
+ font-size: var(--font-size-sans-small);
+ line-height: var(--line-height-data);
+ padding: 0 .25rem;
+ container-type: size;
+ container-name: title;
+}
+
+@container title (width < 30px) or (height < 18px) {
+ .SuspenseRectsTitle > span {
+ display: none;
+ }
+}
+
.SuspenseRectsScaledRect[data-visible='false'] > .SuspenseRectsBoundaryChildren {
overflow: initial;
}
@@ -75,7 +94,7 @@
transition: background-color 0.2s ease-out;
}
-.SuspenseRectsBoundary[data-selected='true'] {
+.SuspenseRectsBoundary[data-selected='true'][data-visible='true'] {
box-shadow: var(--elevation-4);
}
diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js
index e6beca7c22..d5f44eeb32 100644
--- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js
+++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js
@@ -31,6 +31,7 @@ import {
SuspenseTreeDispatcherContext,
} from './SuspenseTreeContext';
import {getClassNameForEnvironment} from './SuspenseEnvironmentColors.js';
+import type RBush from 'rbush';
function ScaledRect({
className,
@@ -78,8 +79,10 @@ function ScaledRect({
function SuspenseRects({
suspenseID,
+ parentRects,
}: {
suspenseID: SuspenseNode['id'],
+ parentRects: null | Array,
}): React$Node {
const store = useContext(StoreContext);
const treeDispatch = useContext(TreeDispatcherContext);
@@ -167,7 +170,20 @@ function SuspenseRects({
}
}
- const boundingBox = getBoundingBox(suspense.rects);
+ const rects = suspense.rects;
+ const boundingBox = getBoundingBox(rects);
+
+ // Next we'll try to find a rect within one of our rects that isn't intersecting with
+ // other rects.
+ // TODO: This should probably be memoized based on if any changes to the rtree has been made.
+ const titleBox: null | Rect =
+ rects === null ? null : findTitleBox(store._rtree, rects, parentRects);
+ const nextRects =
+ rects === null || rects.length === 0
+ ? parentRects
+ : parentRects === null || parentRects.length === 0
+ ? rects
+ : parentRects.concat(rects);
return (
);
})}
@@ -205,11 +221,22 @@ function SuspenseRects({
className={styles.SuspenseRectsBoundaryChildren}
rect={boundingBox}>
{suspense.children.map(childID => {
- return ;
+ return (
+
+ );
})}
)}
- {selected ? (
+ {titleBox && suspense.name && visible ? (
+
+ {suspense.name}
+
+ ) : null}
+ {selected && visible ? (
,
+ rects: Array,
+ parentRects: null | Array,
+): null | Rect {
+ for (let i = 0; i < rects.length; i++) {
+ const rect = rects[i];
+ if (rect.width < 20 || rect.height < 10) {
+ // Skip small rects. They're likely not able to be contain anything useful anyway.
+ continue;
+ }
+ // Find all overlapping rects elsewhere in the tree to limit our rect.
+ const overlappingRects = rtree.search({
+ minX: rect.x,
+ minY: rect.y,
+ maxX: rect.x + rect.width,
+ maxY: rect.y + rect.height,
+ });
+ if (
+ overlappingRects.length === 0 ||
+ (overlappingRects.length === 1 && overlappingRects[0] === rect)
+ ) {
+ // There are no overlapping rects that isn't our own rect, so we can just use
+ // the full space of the rect.
+ return rect;
+ }
+ // We have some overlapping rects but they might not overlap everything. Let's
+ // shrink it up toward the top left corner until it has no more overlap.
+ const minX = rect.x;
+ const minY = rect.y;
+ let maxX = rect.x + rect.width;
+ let maxY = rect.y + rect.height;
+ for (let j = 0; j < overlappingRects.length; j++) {
+ const overlappingRect = overlappingRects[j];
+ if (overlappingRect === rect) {
+ continue;
+ }
+ const x = overlappingRect.x;
+ const y = overlappingRect.y;
+ if (y < maxY && x < maxX) {
+ if (
+ parentRects !== null &&
+ parentRects.indexOf(overlappingRect) !== -1
+ ) {
+ // This rect overlaps but it's part of a parent boundary. We let
+ // title content render if it's on top and not a sibling.
+ continue;
+ }
+ // This rect cuts into the remaining space. Let's figure out if we're
+ // better off cutting on the x or y axis to maximize remaining space.
+ const remainderX = x - minX;
+ const remainderY = y - minY;
+ if (remainderX > remainderY) {
+ maxX = x;
+ } else {
+ maxY = y;
+ }
+ }
+ }
+ if (maxX > minX && maxY > minY) {
+ return {
+ x: minX,
+ y: minY,
+ width: maxX - minX,
+ height: maxY - minY,
+ };
+ }
+ }
+ return null;
+}
+
function SuspenseRectsRoot({rootID}: {rootID: SuspenseNode['id']}): React$Node {
const store = useContext(StoreContext);
const root = store.getSuspenseByID(rootID);
@@ -329,7 +427,9 @@ function SuspenseRectsRoot({rootID}: {rootID: SuspenseNode['id']}): React$Node {
}
return root.children.map(childID => {
- return ;
+ return (
+
+ );
});
}
diff --git a/packages/react-devtools-shared/src/devtools/views/useInferredName.js b/packages/react-devtools-shared/src/devtools/views/useInferredName.js
index f0822e126d..2c93ded469 100644
--- a/packages/react-devtools-shared/src/devtools/views/useInferredName.js
+++ b/packages/react-devtools-shared/src/devtools/views/useInferredName.js
@@ -16,7 +16,7 @@ export default function useInferredName(
const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
const name = asyncInfo.awaited.name;
let inferNameFromStack = null;
- if (!name || name === 'Promise') {
+ if (!name || name === 'Promise' || name === 'lazy') {
// If all we have is a generic name, we can try to infer a better name from
// the stack. We only do this if the stack has more than one frame since
// otherwise it's likely to just be the name of the component which isn't better.
diff --git a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js
index 95f104925b..34f46774b1 100644
--- a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js
+++ b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js
@@ -20,6 +20,7 @@ import SimpleValues from './SimpleValues';
import SymbolKeys from './SymbolKeys';
import UseMemoCache from './UseMemoCache';
import UseEffectEvent from './UseEffectEvent';
+import UseSyncExternalStore from './UseSyncExternalStore';
// TODO Add Immutable JS example
@@ -38,6 +39,7 @@ export default function InspectableElements(): React.Node {
+
);
}
diff --git a/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js b/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js
new file mode 100644
index 0000000000..decb10b2db
--- /dev/null
+++ b/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import * as React from 'react';
+
+const {useState, useEffect, useSyncExternalStore} = React;
+
+// Create a simple external store for demonstratio
+function createStore(initialValue: T): {
+ subscribe: (cb: () => void) => () => any,
+ getSnapshot: () => T,
+ setValue: (newValue: T) => void,
+} {
+ let value = initialValue;
+ const subscribers = new Set<() => void>();
+
+ return {
+ subscribe(callback) {
+ subscribers.add(callback);
+ return () => subscribers.delete(callback);
+ },
+ getSnapshot() {
+ return value;
+ },
+ setValue(newValue) {
+ value = newValue;
+ subscribers.forEach(callback => callback());
+ },
+ };
+}
+
+const counterStore = createStore(0);
+const themeStore = createStore('light');
+
+export default function UseSyncExternalStore(): React.Node {
+ return (
+ <>
+ useSyncExternalStore()
+
+
+
+ >
+ );
+}
+
+function SingleHookCase(): React.Node {
+ const count = useSyncExternalStore(
+ counterStore.subscribe,
+ counterStore.getSnapshot,
+ );
+
+ return (
+
+
Single hook case
+
Count: {count}
+
+
+
+ );
+}
+
+function useCounter() {
+ const count = useSyncExternalStore(
+ counterStore.subscribe,
+ counterStore.getSnapshot,
+ );
+ const [localState, setLocalState] = useState(0);
+
+ useEffect(() => {
+ // Some effect
+ }, [count]);
+
+ return {count, localState, setLocalState};
+}
+
+function HookTreeCase(): React.Node {
+ const {count, localState, setLocalState} = useCounter();
+
+ return (
+
+
Hook tree case
+
External count: {count}
+
Local state: {localState}
+
+
+
+ );
+}
+
+function useTheme() {
+ const theme = useSyncExternalStore(
+ themeStore.subscribe,
+ themeStore.getSnapshot,
+ );
+
+ return theme;
+}
+
+function MultipleStoresCase() {
+ const count = useSyncExternalStore(
+ counterStore.subscribe,
+ counterStore.getSnapshot,
+ );
+ const theme = useTheme();
+
+ return (
+
+
Multiple stores case
+
Count: {count}
+
Theme: {theme}
+
+
+ );
+}
diff --git a/packages/react-devtools-timeline/package.json b/packages/react-devtools-timeline/package.json
index 2f54399ce2..5e4df83552 100644
--- a/packages/react-devtools-timeline/package.json
+++ b/packages/react-devtools-timeline/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "react-devtools-timeline",
- "version": "7.0.0",
+ "version": "7.0.1",
"license": "MIT",
"dependencies": {
"@elg/speedscope": "1.9.0-a6f84db",
diff --git a/packages/react-devtools/CHANGELOG.md b/packages/react-devtools/CHANGELOG.md
index 0fc637b994..6c3ab1baf0 100644
--- a/packages/react-devtools/CHANGELOG.md
+++ b/packages/react-devtools/CHANGELOG.md
@@ -4,6 +4,15 @@
---
+### 7.0.1
+October 20, 2025
+
+* Various UI improvements to experimental Suspense tab ([sebmarkbage](https://github.com/sebmarkbage) & [eps1lon](https://github.com/eps1lon))
+* devtools: fix ellipsis truncation for key values ([sophiebits](https://github.com/sophiebits) in [#34796](https://github.com/facebook/react/pull/34796))
+* fix(devtools): remove duplicated "Display density" field in General settings ([Anatole-Godard](https://github.com/Anatole-Godard) in [#34792](https://github.com/facebook/react/pull/34792))
+
+---
+
### 7.0.0
Oct 2, 2025
diff --git a/packages/react-devtools/package.json b/packages/react-devtools/package.json
index ea8bab1c95..3d1a1bda2f 100644
--- a/packages/react-devtools/package.json
+++ b/packages/react-devtools/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools",
- "version": "7.0.0",
+ "version": "7.0.1",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"repository": {
@@ -26,7 +26,7 @@
"electron": "^23.1.2",
"internal-ip": "^6.2.0",
"minimist": "^1.2.3",
- "react-devtools-core": "7.0.0",
+ "react-devtools-core": "7.0.1",
"update-notifier": "^2.1.0"
}
}
diff --git a/packages/react-markup/src/ReactMarkupServer.js b/packages/react-markup/src/ReactMarkupServer.js
index 0b35404cb8..6f1e35e615 100644
--- a/packages/react-markup/src/ReactMarkupServer.js
+++ b/packages/react-markup/src/ReactMarkupServer.js
@@ -91,6 +91,9 @@ export function experimental_renderToHTML(
undefined,
undefined,
false,
+ undefined,
+ undefined,
+ undefined,
);
const streamState = createFlightStreamState(flightResponse, null);
const flightDestination = {
diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js
index cfc8dcf5f1..371f08abc9 100644
--- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js
+++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js
@@ -52,6 +52,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
};
function createDebugCallbackFromWritableStream(
@@ -103,6 +104,9 @@ function createResponseFromOptions(options: void | Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js
index 2bf3272947..78dce93615 100644
--- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js
+++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js
@@ -57,6 +57,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Node.js client we only support a single-direction debug channel.
debugChannel?: Readable,
};
@@ -112,6 +113,9 @@ function createFromNodeStream(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
diff --git a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientBrowser.js
index 2f71ce2fa9..0f0141e640 100644
--- a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientBrowser.js
+++ b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientBrowser.js
@@ -129,6 +129,9 @@ function createResponseFromOptions(options: void | Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
@@ -205,6 +208,7 @@ export type Options = {
temporaryReferences?: TemporaryReferenceSet,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
};
export function createFromReadableStream(
diff --git a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientEdge.js
index f9c63ccbc3..5c8d1023b2 100644
--- a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientEdge.js
+++ b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientEdge.js
@@ -79,6 +79,7 @@ export type Options = {
temporaryReferences?: TemporaryReferenceSet,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Edge client we only support a single-direction debug channel.
debugChannel?: {readable?: ReadableStream, ...},
};
@@ -107,6 +108,9 @@ function createResponseFromOptions(options?: Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientNode.js
index b874bcd7d4..fbc633a175 100644
--- a/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientNode.js
+++ b/packages/react-server-dom-parcel/src/client/ReactFlightDOMClientNode.js
@@ -52,6 +52,7 @@ export type Options = {
encodeFormAction?: EncodeFormActionCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Node.js client we only support a single-direction debug channel.
debugChannel?: Readable,
};
@@ -103,6 +104,9 @@ export function createFromNodeStream(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js
index b4b84f1c41..b3d31bd1bb 100644
--- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js
+++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js
@@ -51,6 +51,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
};
function createDebugCallbackFromWritableStream(
@@ -102,6 +103,9 @@ function createResponseFromOptions(options: void | Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js
index b994841be1..5517e0f73c 100644
--- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js
+++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js
@@ -79,6 +79,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Edge client we only support a single-direction debug channel.
debugChannel?: {readable?: ReadableStream, ...},
};
@@ -109,6 +110,9 @@ function createResponseFromOptions(options: Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js
index f174f10c0b..6d117929df 100644
--- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js
+++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js
@@ -60,6 +60,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Node.js client we only support a single-direction debug channel.
debugChannel?: Readable,
};
@@ -114,6 +115,9 @@ function createFromNodeStream(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js
index b4b84f1c41..b3d31bd1bb 100644
--- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js
+++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js
@@ -51,6 +51,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
};
function createDebugCallbackFromWritableStream(
@@ -102,6 +103,9 @@ function createResponseFromOptions(options: void | Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js
index 63dae49545..bc4caac767 100644
--- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js
+++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js
@@ -79,6 +79,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Edge client we only support a single-direction debug channel.
debugChannel?: {readable?: ReadableStream, ...},
};
@@ -109,6 +110,9 @@ function createResponseFromOptions(options: Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
}
diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js
index f174f10c0b..6d117929df 100644
--- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js
+++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js
@@ -60,6 +60,7 @@ export type Options = {
findSourceMapURL?: FindSourceMapURLCallback,
replayConsoleLogs?: boolean,
environmentName?: string,
+ startTime?: number,
// For the Node.js client we only support a single-direction debug channel.
debugChannel?: Readable,
};
@@ -114,6 +115,9 @@ function createFromNodeStream(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
+ __DEV__ && options && options.startTime != null
+ ? options.startTime
+ : undefined,
debugChannel,
);
diff --git a/packages/react-server/src/ReactFlightServerConfigDebugNode.js b/packages/react-server/src/ReactFlightServerConfigDebugNode.js
index a78297ad83..e79c19cc73 100644
--- a/packages/react-server/src/ReactFlightServerConfigDebugNode.js
+++ b/packages/react-server/src/ReactFlightServerConfigDebugNode.js
@@ -142,10 +142,28 @@ export function initAsyncDebugInfo(): void {
}: UnresolvedPromiseNode);
}
} else if (
- type !== 'Microtask' &&
- type !== 'TickObject' &&
- type !== 'Immediate'
+ // bound-anonymous-fn is the default name for snapshots and .bind() without a name.
+ // This isn't I/O by itself but likely just a continuation. If the bound function
+ // has a name, we might treat it as I/O but we can't tell the difference.
+ type === 'bound-anonymous-fn' ||
+ // queueMicroTask, process.nextTick and setImmediate aren't considered new I/O
+ // for our purposes but just continuation of existing I/O.
+ type === 'Microtask' ||
+ type === 'TickObject' ||
+ type === 'Immediate'
) {
+ // Treat the trigger as the node to carry along the sequence.
+ // For "bound-anonymous-fn" this will be the callsite of the .bind() which may not
+ // be the best if the callsite of the .run() call is within I/O which should be
+ // tracked. It might be better to track the execution context of "before()" as the
+ // execution context for anything spawned from within the run(). Basically as if
+ // it wasn't an AsyncResource at all.
+ if (trigger === undefined) {
+ return;
+ }
+ node = trigger;
+ } else {
+ // New I/O
if (trigger === undefined) {
// We have begun a new I/O sequence.
const owner = resolveOwner();
@@ -181,13 +199,6 @@ export function initAsyncDebugInfo(): void {
// Otherwise, this is just a continuation of the same I/O sequence.
node = trigger;
}
- } else {
- // Ignore nextTick and microtasks as they're not considered I/O operations.
- // we just treat the trigger as the node to carry along the sequence.
- if (trigger === undefined) {
- return;
- }
- node = trigger;
}
pendingOperations.set(asyncId, node);
},
diff --git a/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js b/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js
index 00c6f78503..db1d7af3a6 100644
--- a/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js
+++ b/packages/react-server/src/__tests__/ReactFlightAsyncDebugInfo-test.js
@@ -459,7 +459,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -867,7 +867,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -985,7 +985,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -1460,7 +1460,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"byteSize": 0,
"end": 0,
"env": "Server",
- "name": "RSC stream",
+ "name": "rsc stream",
"start": 0,
"value": {
"value": "stream",
@@ -1475,7 +1475,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -1789,7 +1789,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -2083,7 +2083,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -2499,7 +2499,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -2665,7 +2665,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -2845,7 +2845,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -3130,7 +3130,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
@@ -3275,7 +3275,7 @@ describe('ReactFlightAsyncDebugInfo', () => {
"awaited": {
"byteSize": 0,
"end": 0,
- "name": "RSC stream",
+ "name": "rsc stream",
"owner": null,
"start": 0,
"value": {
diff --git a/packages/react/src/ReactLazy.js b/packages/react/src/ReactLazy.js
index 55b1690b7c..47f37afbae 100644
--- a/packages/react/src/ReactLazy.js
+++ b/packages/react/src/ReactLazy.js
@@ -20,6 +20,8 @@ import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';
+import noop from 'shared/noop';
+
const Uninitialized = -1;
const Pending = 0;
const Resolved = 1;
@@ -67,12 +69,20 @@ export type LazyComponent = {
function lazyInitializer(payload: Payload): T {
if (payload._status === Uninitialized) {
+ let resolveDebugValue: (void | T) => void = (null: any);
+ let rejectDebugValue: mixed => void = (null: any);
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark when we first kicked off the lazy request.
// $FlowFixMe[cannot-write]
ioInfo.start = ioInfo.end = performance.now();
+ // Stash a Promise for introspection of the value later.
+ // $FlowFixMe[cannot-write]
+ ioInfo.value = new Promise((resolve, reject) => {
+ resolveDebugValue = resolve;
+ rejectDebugValue = reject;
+ });
}
}
const ctor = payload._result;
@@ -92,12 +102,20 @@ function lazyInitializer(payload: Payload): T {
const resolved: ResolvedPayload = (payload: any);
resolved._status = Resolved;
resolved._result = moduleObject;
- if (__DEV__) {
+ if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark the end time of when we resolved.
// $FlowFixMe[cannot-write]
ioInfo.end = performance.now();
+ // Surface the default export as the resolved "value" for debug purposes.
+ const debugValue =
+ moduleObject == null ? undefined : moduleObject.default;
+ resolveDebugValue(debugValue);
+ // $FlowFixMe
+ ioInfo.value.status = 'fulfilled';
+ // $FlowFixMe
+ ioInfo.value.value = debugValue;
}
// Make the thenable introspectable
if (thenable.status === undefined) {
@@ -124,6 +142,14 @@ function lazyInitializer(payload: Payload): T {
// Mark the end time of when we rejected.
// $FlowFixMe[cannot-write]
ioInfo.end = performance.now();
+ // Hide unhandled rejections.
+ // $FlowFixMe
+ ioInfo.value.then(noop, noop);
+ rejectDebugValue(error);
+ // $FlowFixMe
+ ioInfo.value.status = 'rejected';
+ // $FlowFixMe
+ ioInfo.value.reason = error;
}
// Make the thenable introspectable
if (thenable.status === undefined) {
@@ -139,9 +165,6 @@ function lazyInitializer(payload: Payload): T {
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
- // Stash the thenable for introspection of the value later.
- // $FlowFixMe[cannot-write]
- ioInfo.value = thenable;
const displayName = thenable.displayName;
if (typeof displayName === 'string') {
// $FlowFixMe[cannot-write]
diff --git a/packages/shared/ReactIODescription.js b/packages/shared/ReactIODescription.js
index e1a0fce2c4..6d7bf648fc 100644
--- a/packages/shared/ReactIODescription.js
+++ b/packages/shared/ReactIODescription.js
@@ -13,6 +13,8 @@ export function getIODescription(value: mixed): string {
}
try {
switch (typeof value) {
+ case 'function':
+ return value.name || '';
case 'object':
// Test the object for a bunch of common property names that are useful identifiers.
// While we only have the return value here, it should ideally be a name that
diff --git a/scripts/flow/environment.js b/scripts/flow/environment.js
index 5556fad1a0..f201c2e0e8 100644
--- a/scripts/flow/environment.js
+++ b/scripts/flow/environment.js
@@ -456,3 +456,191 @@ declare class NavigationDestination {
getState(): mixed;
}
+
+// Ported from definitely-typed
+declare module 'rbush' {
+ declare interface BBox {
+ minX: number;
+ minY: number;
+ maxX: number;
+ maxY: number;
+ }
+
+ declare export default class RBush {
+ /**
+ * Constructs an `RBush`, a high-performance 2D spatial index for points and
+ * rectangles. Based on an optimized __R-tree__ data structure with
+ * __bulk-insertion__ support.
+ *
+ * @param maxEntries An optional argument to RBush defines the maximum
+ * number of entries in a tree node. `9` (used by default)
+ * is a reasonable choice for most applications. Higher
+ * value means faster insertion and slower search, and
+ * vice versa.
+ */
+ constructor(maxEntries?: number): void;
+
+ /**
+ * Inserts an item. To insert many items at once, use `load()`.
+ *
+ * @param item The item to insert.
+ */
+ insert(item: T): RBush;
+
+ /**
+ * Bulk-inserts the given items into the tree.
+ *
+ * Bulk insertion is usually ~2-3 times faster than inserting items one by
+ * one. After bulk loading (bulk insertion into an empty tree), subsequent
+ * query performance is also ~20-30% better.
+ *
+ * Note that when you do bulk insertion into an existing tree, it bulk-loads
+ * the given data into a separate tree and inserts the smaller tree into the
+ * larger tree. This means that bulk insertion works very well for clustered
+ * data (where items in one update are close to each other), but makes query
+ * performance worse if the data is scattered.
+ *
+ * @param items The items to load.
+ */
+ load(items: $ReadOnlyArray): RBush;
+
+ /**
+ * Removes a previously inserted item, comparing by reference.
+ *
+ * To remove all items, use `clear()`.
+ *
+ * @param item The item to remove.
+ * @param equals A custom function that allows comparing by value instead.
+ * Useful when you have only a copy of the object you need
+ * removed (e.g. loaded from server).
+ */
+ remove(item: T, equals?: (a: T, b: T) => boolean): RBush;
+
+ /**
+ * Removes all items.
+ */
+ clear(): RBush;
+
+ /**
+ * Returns an array of data items (points or rectangles) that the given
+ * bounding box intersects.
+ *
+ * Note that the search method accepts a bounding box in `{minX, minY, maxX,
+ * maxY}` format regardless of the data format.
+ *
+ * @param box The bounding box in which to search.
+ */
+ search(box: BBox): T[];
+
+ /**
+ * Returns all items contained in the tree.
+ */
+ all(): T[];
+
+ /**
+ * Returns `true` if there are any items intersecting the given bounding
+ * box, otherwise `false`.
+ *
+ * @param box The bounding box in which to search.
+ */
+ collides(box: BBox): boolean;
+
+ /**
+ * Returns the bounding box for the provided item.
+ *
+ * By default, `RBush` assumes the format of data points to be an object
+ * with `minX`, `minY`, `maxX`, and `maxY`. However, you can specify a
+ * custom item format by overriding `toBBox()`, `compareMinX()`, and
+ * `compareMinY()`.
+ *
+ * @example
+ * class MyRBush extends RBush {
+ * toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
+ * compareMinX(a, b) { return a.x - b.x; }
+ * compareMinY(a, b) { return a.y - b.y; }
+ * }
+ * const tree = new MyRBush<[number, number]>();
+ * tree.insert([20, 50]); // accepts [x, y] points
+ *
+ * @param item The item whose bounding box should be returned.
+ */
+ toBBox(item: T): BBox;
+
+ /**
+ * Compares the minimum x coordinate of two items. Returns -1 if `a`'s
+ * x-coordinate is smaller, 1 if `b`'s x coordinate is smaller, or 0 if
+ * they're equal.
+ *
+ * By default, `RBush` assumes the format of data points to be an object
+ * with `minX`, `minY`, `maxX`, and `maxY`. However, you can specify a
+ * custom item format by overriding `toBBox()`, `compareMinX()`, and
+ * `compareMinY()`.
+ *
+ * @example
+ * class MyRBush extends RBush {
+ * toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
+ * compareMinX(a, b) { return a.x - b.x; }
+ * compareMinY(a, b) { return a.y - b.y; }
+ * }
+ * const tree = new MyRBush<[number, number]>();
+ * tree.insert([20, 50]); // accepts [x, y] points
+ *
+ * @param a The first item to compare.
+ * @param b The second item to compare.
+ */
+ compareMinX(a: T, b: T): number;
+
+ /**
+ * Compares the minimum y coordinate of two items. Returns -1 if `a`'s
+ * x-coordinate is smaller, 1 if `b`'s x coordinate is smaller, or 0 if
+ * they're equal.
+ *
+ * By default, `RBush` assumes the format of data points to be an object
+ * with `minX`, `minY`, `maxX`, and `maxY`. However, you can specify a
+ * custom item format by overriding `toBBox()`, `compareMinX()`, and
+ * `compareMinY()`.
+ *
+ * @example
+ * class MyRBush extends RBush {
+ * toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
+ * compareMinX(a, b) { return a.x - b.x; }
+ * compareMinY(a, b) { return a.y - b.y; }
+ * }
+ * const tree = new MyRBush<[number, number]>();
+ * tree.insert([20, 50]); // accepts [x, y] points
+ *
+ * @param a The first item to compare.
+ * @param b The second item to compare.
+ */
+ compareMinY(a: T, b: T): number;
+
+ /**
+ * Exports the tree's contents as a JSON object.
+ *
+ * Importing and exporting as JSON allows you to use RBush on both the
+ * server (using Node.js) and the browser combined, e.g. first indexing the
+ * data on the server and and then importing the resulting tree data on the
+ * client for searching.
+ *
+ * Note that the `maxEntries` option from the constructor must be the same
+ * in both trees for export/import to work properly.
+ */
+ toJSON(): any;
+
+ /**
+ * Imports previously exported data into the tree (i.e., data that was
+ * emitted by `toJSON()`).
+ *
+ * Importing and exporting as JSON allows you to use RBush on both the
+ * server (using Node.js) and the browser combined, e.g. first indexing the
+ * data on the server and and then importing the resulting tree data on the
+ * client for searching.
+ *
+ * Note that the `maxEntries` option from the constructor must be the same
+ * in both trees for export/import to work properly.
+ *
+ * @param data The previously exported JSON data.
+ */
+ fromJSON(data: any): RBush;
+ }
+}
diff --git a/scripts/jest/config.build-devtools.js b/scripts/jest/config.build-devtools.js
index 9baf33a39b..3f03b50c3a 100644
--- a/scripts/jest/config.build-devtools.js
+++ b/scripts/jest/config.build-devtools.js
@@ -63,7 +63,7 @@ module.exports = Object.assign({}, baseConfig, {
testPathIgnorePatterns: ['/node_modules/', '-test.internal.js$'],
// Exclude the build output from transforms
transformIgnorePatterns: [
- '/node_modules/',
+ '/node_modules/(?!(rbush|quickselect)/)',
'/build/',
'/__compiled__/',
'/__untransformed__/',
diff --git a/yarn.lock b/yarn.lock
index ad8a3f0085..2543e4d176 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8271,7 +8271,7 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0:
dependencies:
eslint-visitor-keys "^1.1.0"
-"eslint-v7@npm:eslint@^7.7.0":
+"eslint-v7@npm:eslint@^7.7.0", eslint@^7.7.0:
version "7.32.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
@@ -8470,52 +8470,6 @@ eslint@8.57.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"
-eslint@^7.7.0:
- version "7.32.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
- integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
- dependencies:
- "@babel/code-frame" "7.12.11"
- "@eslint/eslintrc" "^0.4.3"
- "@humanwhocodes/config-array" "^0.5.0"
- ajv "^6.10.0"
- chalk "^4.0.0"
- cross-spawn "^7.0.2"
- debug "^4.0.1"
- doctrine "^3.0.0"
- enquirer "^2.3.5"
- escape-string-regexp "^4.0.0"
- eslint-scope "^5.1.1"
- eslint-utils "^2.1.0"
- eslint-visitor-keys "^2.0.0"
- espree "^7.3.1"
- esquery "^1.4.0"
- esutils "^2.0.2"
- fast-deep-equal "^3.1.3"
- file-entry-cache "^6.0.1"
- functional-red-black-tree "^1.0.1"
- glob-parent "^5.1.2"
- globals "^13.6.0"
- ignore "^4.0.6"
- import-fresh "^3.0.0"
- imurmurhash "^0.1.4"
- is-glob "^4.0.0"
- js-yaml "^3.13.1"
- json-stable-stringify-without-jsonify "^1.0.1"
- levn "^0.4.1"
- lodash.merge "^4.6.2"
- minimatch "^3.0.4"
- natural-compare "^1.4.0"
- optionator "^0.9.1"
- progress "^2.0.0"
- regexpp "^3.1.0"
- semver "^7.2.1"
- strip-ansi "^6.0.0"
- strip-json-comments "^3.1.0"
- table "^6.0.9"
- text-table "^0.2.0"
- v8-compile-cache "^2.0.3"
-
espree@10.0.1, espree@^10.0.1:
version "10.0.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-10.0.1.tgz#600e60404157412751ba4a6f3a2ee1a42433139f"
@@ -14317,7 +14271,7 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-"prettier-2@npm:prettier@^2":
+"prettier-2@npm:prettier@^2", prettier@^2.5.1:
version "2.8.8"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
@@ -14332,11 +14286,6 @@ prettier@^1.19.1:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
-prettier@^2.5.1:
- version "2.8.8"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
- integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
-
pretty-format@^29.4.1:
version "29.4.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.1.tgz#0da99b532559097b8254298da7c75a0785b1751c"
@@ -14602,6 +14551,11 @@ quick-tmp@0.0.0:
first-match "0.0.1"
osenv "0.0.3"
+quickselect@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-3.0.0.tgz#a37fc953867d56f095a20ac71c6d27063d2de603"
+ integrity sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==
+
random-seed@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/random-seed/-/random-seed-0.3.0.tgz#d945f2e1f38f49e8d58913431b8bf6bb937556cd"
@@ -14639,6 +14593,13 @@ raw-loader@^3.1.0:
loader-utils "^1.1.0"
schema-utils "^2.0.1"
+rbush@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/rbush/-/rbush-4.0.1.tgz#1f55afa64a978f71bf9e9a99bc14ff84f3cb0d6d"
+ integrity sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==
+ dependencies:
+ quickselect "^3.0.0"
+
rc@1.2.8, rc@^1.0.1, rc@^1.1.6, rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@@ -16211,7 +16172,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
-"string-width-cjs@npm:string-width@^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -16246,15 +16207,6 @@ string-width@^4.0.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
-string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@@ -16315,7 +16267,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -16343,13 +16295,6 @@ strip-ansi@^5.1.0:
dependencies:
ansi-regex "^4.1.0"
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -17958,7 +17903,7 @@ workerize-loader@^2.0.2:
dependencies:
loader-utils "^2.0.0"
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -17976,15 +17921,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"