Merge 1e556701e0 into sapling-pr-archive-josephsavona

This commit is contained in:
Joseph Savona
2025-10-23 10:23:01 -07:00
committed by GitHub
100 changed files with 1204 additions and 843 deletions
@@ -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 <Activity> when it is compatible with Monaco: https://github.com/suren-atoyan/monaco-react/issues/753
<>
<div
style={{
display: isExpanded ? 'block' : 'none',
}}>
<Activity mode={isExpanded ? 'visible' : 'hidden'}>
<ExpandedEditor
onToggle={() => {
startTransition(() => {
@@ -49,11 +46,8 @@ export default function ConfigEditor({
}}
formattedAppliedConfig={formattedAppliedConfig}
/>
</div>
<div
style={{
display: !isExpanded ? 'block' : 'none',
}}>
</Activity>
<Activity mode={isExpanded ? 'hidden' : 'visible'}>
<CollapsedEditor
onToggle={() => {
startTransition(() => {
@@ -62,7 +56,7 @@ export default function ConfigEditor({
});
}}
/>
</div>
</Activity>
</>
);
}
@@ -122,7 +116,8 @@ function ExpandedEditor({
return (
<ViewTransition
update={{[CONFIG_PANEL_TRANSITION]: 'slide-in', default: 'none'}}>
enter={{[CONFIG_PANEL_TRANSITION]: 'slide-in', default: 'none'}}
exit={{[CONFIG_PANEL_TRANSITION]: 'slide-out', default: 'none'}}>
<Resizable
minWidth={300}
maxWidth={600}
+7 -7
View File
@@ -26,7 +26,7 @@
"@babel/traverse": "^7.18.9",
"@babel/types": "7.26.3",
"@heroicons/react": "^1.0.6",
"@monaco-editor/react": "^4.4.6",
"@monaco-editor/react": "^4.8.0-rc.2",
"@playwright/test": "^1.51.1",
"@use-gesture/react": "^10.2.22",
"hermes-eslint": "^0.25.0",
@@ -40,13 +40,13 @@
"prettier": "^3.3.3",
"pretty-format": "^29.3.1",
"re-resizable": "^6.9.16",
"react": "19.1.1",
"react-dom": "19.1.1"
"react": "19.2",
"react-dom": "19.2"
},
"devDependencies": {
"@types/node": "18.11.9",
"@types/react": "19.1.13",
"@types/react-dom": "19.1.9",
"@types/react": "19.2",
"@types/react-dom": "19.2",
"autoprefixer": "^10.4.13",
"clsx": "^1.2.1",
"concurrently": "^7.4.0",
@@ -58,7 +58,7 @@
"wait-on": "^7.2.0"
},
"resolutions": {
"@types/react": "19.1.12",
"@types/react-dom": "19.1.9"
"@types/react": "19.2",
"@types/react-dom": "19.2"
}
}
@@ -79,6 +79,15 @@
::view-transition-group(.slide-in) {
z-index: 1;
}
::view-transition-old(.slide-out) {
animation-name: slideOutLeft;
}
::view-transition-new(.slide-out) {
animation-name: slideInLeft;
}
::view-transition-group(.slide-out) {
z-index: 1;
}
@keyframes slideOutLeft {
from {
+31 -26
View File
@@ -701,19 +701,19 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@monaco-editor/loader@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.4.0.tgz#f08227057331ec890fa1e903912a5b711a2ad558"
integrity sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==
"@monaco-editor/loader@^1.6.1":
version "1.6.1"
resolved "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.6.1.tgz#c99177d87765abf10de31a0086084e714acfbc0f"
integrity sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==
dependencies:
state-local "^1.0.6"
"@monaco-editor/react@^4.4.6":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.6.0.tgz#bcc68671e358a21c3814566b865a54b191e24119"
integrity sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==
"@monaco-editor/react@^4.8.0-rc.2":
version "4.8.0-rc.2"
resolved "https://registry.npmjs.org/@monaco-editor/react/-/react-4.8.0-rc.2.tgz#e9acf652e23e9f640671a69875f496dde7f098aa"
integrity sha512-RzFHKBCnRA4RnozaG/EPhKsbkhX5wcApSa5MElR/AD2ojxhMY+QP+G8aJpxALCnIwKs6L0dec5MJ0nAjMUEqnA==
dependencies:
"@monaco-editor/loader" "^1.4.0"
"@monaco-editor/loader" "^1.6.1"
"@next/env@15.6.0-canary.7":
version "15.6.0-canary.7"
@@ -859,6 +859,11 @@
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.9.tgz#5ab695fce1e804184767932365ae6569c11b4b4b"
integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==
"@types/react-dom@19.2":
version "19.2.2"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz#a4cc874797b7ddc9cb180ef0d5dc23f596fc2332"
integrity sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==
"@types/react@19.1.12":
version "19.1.12"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.12.tgz#7bfaa76aabbb0b4fe0493c21a3a7a93d33e8937b"
@@ -866,10 +871,10 @@
dependencies:
csstype "^3.0.2"
"@types/react@19.1.13":
version "19.1.13"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.13.tgz#fc650ffa680d739a25a530f5d7ebe00cdd771883"
integrity sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==
"@types/react@19.2":
version "19.2.2"
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz#ba123a75d4c2a51158697160a4ea2ff70aa6bf36"
integrity sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==
dependencies:
csstype "^3.0.2"
@@ -3589,12 +3594,12 @@ re-resizable@^6.9.16:
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee"
integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==
react-dom@19.1.1:
version "19.1.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893"
integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==
react-dom@19.2:
version "19.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
dependencies:
scheduler "^0.26.0"
scheduler "^0.27.0"
react-is@^16.13.1:
version "16.13.1"
@@ -3606,10 +3611,10 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react@19.1.1:
version "19.1.1"
resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af"
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
react@19.2:
version "19.2.0"
resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
read-cache@^1.0.0:
version "1.0.0"
@@ -3785,10 +3790,10 @@ safe-regex-test@^1.1.0:
es-errors "^1.3.0"
is-regex "^1.2.1"
scheduler@^0.26.0:
version "0.26.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==
scheduler@^0.27.0:
version "0.27.0"
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
semver@^6.3.1:
version "6.3.1"
@@ -12,6 +12,24 @@ import {Err, Ok, Result} from './Utils/Result';
import {assertExhaustive} from './Utils/utils';
import invariant from 'invariant';
// Number of context lines to display above the source of an error
const CODEFRAME_LINES_ABOVE = 2;
// Number of context lines to display below the source of an error
const CODEFRAME_LINES_BELOW = 3;
// Max number of lines for the _source_ of an error, before we abbreviate
// the display of the source portion
const CODEFRAME_MAX_LINES = 3;
// When the error source exceeds the above threshold, how many lines of
// the source should be displayed? We show:
// - CODEFRAME_LINES_ABOVE context lines
// - CODEFRAME_ABBREVIATED_SOURCE_LINES of the error
// - '...' ellipsis
// - CODEFRAME_ABBREVIATED_SOURCE_LINES of the error
// - CODEFRAME_LINES_BELOW context lines
//
// This value must be at least 2 or else we'll cut off important parts of the error message
const CODEFRAME_ABBREVIATED_SOURCE_LINES = 2;
export enum ErrorSeverity {
/**
* An actionable error that the developer can fix. For example, product code errors should be
@@ -496,7 +514,7 @@ function printCodeFrame(
loc: t.SourceLocation,
message: string,
): string {
return codeFrameColumns(
const printed = codeFrameColumns(
source,
{
start: {
@@ -510,8 +528,25 @@ function printCodeFrame(
},
{
message,
linesAbove: CODEFRAME_LINES_ABOVE,
linesBelow: CODEFRAME_LINES_BELOW,
},
);
const lines = printed.split(/\r?\n/);
if (loc.end.line - loc.start.line < CODEFRAME_MAX_LINES) {
return printed;
}
const pipeIndex = lines[0].indexOf('|');
return [
...lines.slice(
0,
CODEFRAME_LINES_ABOVE + CODEFRAME_ABBREVIATED_SOURCE_LINES,
),
'> ' + ' '.repeat(pipeIndex - 2) + '…',
...lines.slice(
-(CODEFRAME_LINES_BELOW + CODEFRAME_ABBREVIATED_SOURCE_LINES),
),
].join('\n');
}
function printErrorSummary(category: ErrorCategory, message: string): string {
@@ -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',
@@ -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 (
@@ -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 (
@@ -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 <Foo data={data} />;
@@ -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<TInput, TOutput>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 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
@@ -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);
@@ -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 | <div key={key} onClick={() => data.set(key)}>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 12 | {key}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | </div>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 14 | );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> 15 | }
| ^^^^ Support non-trivial for..in inits
16 | return <div>{items}</div>;
@@ -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 | <div key={item.id} onClick={() => data.set(item)}>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 12 | {item.id}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 13 | </div>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 14 | );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> 15 | }
| ^^^^ Support non-trivial for..of inits
16 | return <div>{items}</div>;
@@ -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 = <div value={value} />;
| ^^^^^^^^^^^^^^
> 12 | }
| ^^^^^^^^^^^^^^
> 13 | } finally {
| ^^^^^^^^^^^^^^
> 14 | console.log(el);
| ^^^^^^^^^^^^^^
>
> 15 | }
| ^^^^ (BuildHIR::lowerStatement) Handle TryStatement without a catch clause
16 | return el;
@@ -28,12 +28,7 @@ error.todo-invalid-jsx-in-try-with-finally.ts:4:2
3 | let el;
> 4 | try {
| ^^^^^
> 5 | el = <div />;
| ^^^^^^^^^^^^^^^^^
> 6 | } finally {
| ^^^^^^^^^^^^^^^^^
> 7 | console.log(el);
| ^^^^^^^^^^^^^^^^^
>
> 8 | }
| ^^^^ (BuildHIR::lowerStatement) Handle TryStatement without a catch clause
9 | return el;
@@ -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 |
@@ -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;
```
@@ -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;
```
@@ -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 | }
```
@@ -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;
```
@@ -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(() => {
@@ -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]
@@ -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 <div>{prop1}</div>;
@@ -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
@@ -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"}]
@@ -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}],
};
@@ -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]}
@@ -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]}
@@ -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]}
@@ -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 | }
@@ -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 | }
@@ -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 | }
@@ -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 | }
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 (
@@ -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 (
@@ -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,
+2 -1
View File
@@ -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"
@@ -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"
@@ -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 {
@@ -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';
@@ -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;
}
}
@@ -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,
},
],
},
@@ -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';
@@ -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"
+3 -1
View File
@@ -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;
@@ -14,3 +14,13 @@ if (process.env.NODE_ENV === 'production') {
} else {
module.exports = require('./cjs/eslint-plugin-react-hooks.development.js');
}
// Hint to Nodes 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,
});
@@ -71,7 +71,10 @@ const configs = {
plugins,
rules: recommendedLatestRuleConfigs,
},
flat: {} as Record<string, ReactHooksFlatConfig>,
flat: {} as {
recommended: ReactHooksFlatConfig;
'recommended-latest': ReactHooksFlatConfig;
},
};
const plugin = {
+2 -2
View File
@@ -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.
+6 -2
View File
@@ -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<number, SomeChunk<any>> = 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
+1 -1
View File
@@ -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",
@@ -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",
@@ -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",
@@ -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",
@@ -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<HTMLLinkElement | HTMLStyleElement> {
const tags: Array<HTMLLinkElement | HTMLStyleElement> = [];
// 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;
}
+1 -1
View File
@@ -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';
+21 -3
View File
@@ -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}`,
);
}
}
}
@@ -285,7 +285,7 @@ module.exports = {
{
loader: 'css-loader',
options: {
sourceMap: true,
sourceMap: __DEV__,
modules: true,
localIdentName: '[local]___[hash:base64:5]',
},
+1 -1
View File
@@ -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",
+2 -1
View File
@@ -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"
}
}
@@ -3243,4 +3243,61 @@ describe('Store', () => {
<Suspense name="inner-suspense" rects={[{x:1,y:2,width:15,height:1}]}>
`);
});
// @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 (
<React.Suspense fallback={<p>Loading inner</p>}>
<p>{promise}</p>
</React.Suspense>
);
}
function Outer({children}) {
return (
<React.Suspense fallback={<p>Loading outer</p>}>
<p>{promise}</p>
{children}
</React.Suspense>
);
}
await actAsync(() => {
render(
<Outer>
<Inner />
</Outer>,
);
});
expect(store).toMatchInlineSnapshot(`
[root]
<Outer>
<Suspense>
[suspense-root] rects={[{x:1,y:2,width:13,height:1}]}
<Suspense name="Outer" rects={null}>
`);
console.log('...........................');
await actAsync(() => {
resolve('loaded');
});
expect(store).toMatchInlineSnapshot(`
[root]
<Outer>
<Suspense>
<Inner>
<Suspense>
[suspense-root] rects={[{x:1,y:2,width:6,height:1}, {x:1,y:2,width:6,height:1}]}
<Suspense name="Outer" rects={[{x:1,y:2,width:6,height:1}, {x:1,y:2,width:6,height:1}]}>
<Suspense name="Inner" rects={[{x:1,y:2,width:6,height:1}]}>
`);
});
});
+36 -10
View File
@@ -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);
+59 -11
View File
@@ -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<Rect> {
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<string>) => {
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<Element['id'], number> = new Map();
// Stores all the SuspenseNode rects in an R-tree to make it fast to find overlaps.
_rtree: RBush<Rect> = 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;
}
}
+1 -5
View File
@@ -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 `<Suspense${name}${printedRects}>`;
@@ -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;
}
@@ -86,8 +86,10 @@ export function CallSiteView({
</span>
</>
)}
<ElementBadges environmentName={environmentName} />
<ElementBadges
className={styles.ElementBadges}
environmentName={environmentName}
/>
</div>
);
}
@@ -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'}
</button>
</li>
);
@@ -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);
}
@@ -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<Rect>,
}): 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 (
<ScaledRect
@@ -196,7 +212,7 @@ function SuspenseRects({
onPointerOver={handlePointerOver}
onPointerLeave={handlePointerLeave}
// Reach-UI tooltip will go out of bounds of parent scroll container.
title={suspense.name}
title={suspense.name || 'Unknown'}
/>
);
})}
@@ -205,11 +221,22 @@ function SuspenseRects({
className={styles.SuspenseRectsBoundaryChildren}
rect={boundingBox}>
{suspense.children.map(childID => {
return <SuspenseRects key={childID} suspenseID={childID} />;
return (
<SuspenseRects
key={childID}
suspenseID={childID}
parentRects={nextRects}
/>
);
})}
</ScaledRect>
)}
{selected ? (
{titleBox && suspense.name && visible ? (
<ScaledRect className={styles.SuspenseRectsTitle} rect={titleBox}>
<span>{suspense.name}</span>
</ScaledRect>
) : null}
{selected && visible ? (
<ScaledRect
className={styles.SuspenseRectOutline}
rect={boundingBox}
@@ -320,6 +347,77 @@ function getDocumentBoundingRect(
};
}
function findTitleBox(
rtree: RBush<Rect>,
rects: Array<Rect>,
parentRects: null | Array<Rect>,
): 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 <SuspenseRects key={childID} suspenseID={childID} />;
return (
<SuspenseRects key={childID} suspenseID={childID} parentRects={null} />
);
});
}
@@ -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.
@@ -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 {
<SymbolKeys />
<UseMemoCache />
<UseEffectEvent />
<UseSyncExternalStore />
</Fragment>
);
}
@@ -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<T>(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 (
<>
<h2>useSyncExternalStore()</h2>
<SingleHookCase />
<HookTreeCase />
<MultipleStoresCase />
</>
);
}
function SingleHookCase(): React.Node {
const count = useSyncExternalStore(
counterStore.subscribe,
counterStore.getSnapshot,
);
return (
<div>
<h3>Single hook case</h3>
<p>Count: {count}</p>
<button onClick={() => counterStore.setValue(count + 1)}>
Increment
</button>
<button onClick={() => counterStore.setValue(count - 1)}>
Decrement
</button>
</div>
);
}
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 (
<div>
<h3>Hook tree case</h3>
<p>External count: {count}</p>
<p>Local state: {localState}</p>
<button onClick={() => counterStore.setValue(count + 1)}>
Increment External
</button>
<button onClick={() => setLocalState(localState + 1)}>
Increment Local
</button>
</div>
);
}
function useTheme() {
const theme = useSyncExternalStore(
themeStore.subscribe,
themeStore.getSnapshot,
);
return theme;
}
function MultipleStoresCase() {
const count = useSyncExternalStore(
counterStore.subscribe,
counterStore.getSnapshot,
);
const theme = useTheme();
return (
<div style={{background: theme === 'dark' ? '#333' : '#fff'}}>
<h3>Multiple stores case</h3>
<p>Count: {count}</p>
<p>Theme: {theme}</p>
<button
onClick={() =>
themeStore.setValue(theme === 'light' ? 'dark' : 'light')
}>
Toggle Theme
</button>
</div>
);
}
@@ -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",
+9
View File
@@ -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
+2 -2
View File
@@ -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"
}
}
+3
View File
@@ -91,6 +91,9 @@ export function experimental_renderToHTML(
undefined,
undefined,
false,
undefined,
undefined,
undefined,
);
const streamState = createFlightStreamState(flightResponse, null);
const flightDestination = {
@@ -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,
);
}
@@ -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<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ && options && options.startTime != null
? options.startTime
: undefined,
debugChannel,
);
@@ -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<T>(
@@ -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,
);
}
@@ -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<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ && options && options.startTime != null
? options.startTime
: undefined,
debugChannel,
);
@@ -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,
);
}
@@ -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,
);
}
@@ -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<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ && options && options.startTime != null
? options.startTime
: undefined,
debugChannel,
);
@@ -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,
);
}
@@ -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,
);
}
@@ -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<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ && options && options.startTime != null
? options.startTime
: undefined,
debugChannel,
);
+21 -10
View File
@@ -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);
},
@@ -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": {
+27 -4
View File
@@ -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<T, P> = {
function lazyInitializer<T>(payload: Payload<T>): 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<T>(payload: Payload<T>): T {
const resolved: ResolvedPayload<T> = (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<T>(payload: Payload<T>): 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<T>(payload: Payload<T>): 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]
+2
View File
@@ -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
+188
View File
@@ -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<T> {
/**
* 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<T>;
/**
* 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<T>): RBush<T>;
/**
* 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<T>;
/**
* Removes all items.
*/
clear(): RBush<T>;
/**
* 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<T> extends RBush<T> {
* 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<T> extends RBush<T> {
* 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<T> extends RBush<T> {
* 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<T>;
}
}
+1 -1
View File
@@ -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)/)',
'<rootDir>/build/',
'/__compiled__/',
'/__untransformed__/',
+17 -81
View File
@@ -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"